Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js')
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js195
1 files changed, 146 insertions, 49 deletions
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
index 610aae3946f..721e2b831fc 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
@@ -1,6 +1,16 @@
import { nextTick } from 'vue';
-import { GlDrawer, GlFormCombobox, GlFormInput, GlFormSelect, GlModal } from '@gitlab/ui';
+import {
+ GlDrawer,
+ GlFormCombobox,
+ GlFormGroup,
+ GlFormInput,
+ GlFormSelect,
+ GlLink,
+ GlModal,
+ GlSprintf,
+} from '@gitlab/ui';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { helpPagePath } from '~/helpers/help_page_helper';
import CiEnvironmentsDropdown from '~/ci/ci_variable_list/components/ci_environments_dropdown.vue';
import CiVariableDrawer from '~/ci/ci_variable_list/components/ci_variable_drawer.vue';
import { awsTokenList } from '~/ci/ci_variable_list/components/ci_variable_autocomplete_tokens';
@@ -20,6 +30,8 @@ describe('CI Variable Drawer', () => {
let wrapper;
let trackingSpy;
+ const itif = (condition) => (condition ? it : it.skip);
+
const mockProjectVariable = mockVariablesWithScopes(projectString)[0];
const mockProjectVariableFileType = mockVariablesWithScopes(projectString)[1];
const mockEnvScope = 'staging';
@@ -74,6 +86,7 @@ describe('CI Variable Drawer', () => {
const findDrawer = () => wrapper.findComponent(GlDrawer);
const findEnvironmentScopeDropdown = () => wrapper.findComponent(CiEnvironmentsDropdown);
const findExpandedCheckbox = () => wrapper.findByTestId('ci-variable-expanded-checkbox');
+ const findFlagsDocsLink = () => wrapper.findByTestId('ci-variable-flags-docs-link');
const findKeyField = () => wrapper.findComponent(GlFormCombobox);
const findMaskedCheckbox = () => wrapper.findByTestId('ci-variable-masked-checkbox');
const findProtectedCheckbox = () => wrapper.findByTestId('ci-variable-protected-checkbox');
@@ -81,6 +94,26 @@ describe('CI Variable Drawer', () => {
const findValueLabel = () => wrapper.findByTestId('ci-variable-value-label');
const findTitle = () => findDrawer().find('h2');
const findTypeDropdown = () => wrapper.findComponent(GlFormSelect);
+ const findVariablesPrecedenceDocsLink = () =>
+ wrapper.findByTestId('ci-variable-precedence-docs-link');
+
+ describe('template', () => {
+ beforeEach(() => {
+ createComponent({ stubs: { GlFormGroup, GlLink, GlSprintf } });
+ });
+
+ it('renders docs link for variables precendece', () => {
+ expect(findVariablesPrecedenceDocsLink().attributes('href')).toBe(
+ helpPagePath('ci/variables/index', { anchor: 'cicd-variable-precedence' }),
+ );
+ });
+
+ it('renders docs link for flags', () => {
+ expect(findFlagsDocsLink().attributes('href')).toBe(
+ helpPagePath('ci/variables/index', { anchor: 'define-a-cicd-variable-in-the-ui' }),
+ );
+ });
+ });
describe('validations', () => {
describe('type dropdown', () => {
@@ -263,12 +296,22 @@ describe('CI Variable Drawer', () => {
expect(findKeyField().props('tokenList')).toBe(awsTokenList);
});
- it('cannot submit with empty key', async () => {
- expect(findConfirmBtn().attributes('disabled')).toBeDefined();
-
- await findKeyField().vm.$emit('input', 'NEW_VARIABLE');
-
- expect(findConfirmBtn().attributes('disabled')).toBeUndefined();
+ const keyFeedbackMessage = "A variable key can only contain letters, numbers, and '_'.";
+ describe.each`
+ key | feedbackMessage | submitButtonDisabledState
+ ${'validKey123'} | ${''} | ${undefined}
+ ${'VALID_KEY'} | ${''} | ${undefined}
+ ${''} | ${''} | ${'true'}
+ ${'invalid!!key'} | ${keyFeedbackMessage} | ${'true'}
+ ${'key with whitespace'} | ${keyFeedbackMessage} | ${'true'}
+ ${'multiline\nkey'} | ${keyFeedbackMessage} | ${'true'}
+ `('key validation', ({ key, feedbackMessage, submitButtonDisabledState }) => {
+ it(`validates key ${key} correctly`, async () => {
+ await findKeyField().vm.$emit('input', key);
+
+ expect(findConfirmBtn().attributes('disabled')).toBe(submitButtonDisabledState);
+ expect(wrapper.text()).toContain(feedbackMessage);
+ });
});
});
@@ -284,52 +327,106 @@ describe('CI Variable Drawer', () => {
expect(findConfirmBtn().attributes('disabled')).toBeUndefined();
});
- describe.each`
- value | canSubmit | trackingErrorProperty
- ${'secretValue'} | ${true} | ${null}
- ${'~v@lid:symbols.'} | ${true} | ${null}
- ${'short'} | ${false} | ${null}
- ${'multiline\nvalue'} | ${false} | ${'\n'}
- ${'dollar$ign'} | ${false} | ${'$'}
- ${'unsupported|char'} | ${false} | ${'|'}
- `('masking requirements', ({ value, canSubmit, trackingErrorProperty }) => {
- beforeEach(async () => {
- createComponent();
-
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- await findKeyField().vm.$emit('input', 'NEW_VARIABLE');
- await findValueField().vm.$emit('input', value);
- await findMaskedCheckbox().vm.$emit('input', true);
- });
+ const invalidValues = {
+ short: 'short',
+ multiLine: 'multiline\nvalue',
+ unsupportedChar: 'unsupported|char',
+ twoUnsupportedChars: 'unsupported|chars!',
+ threeUnsupportedChars: '%unsupported|chars!',
+ shortAndMultiLine: 'sho\nrt',
+ shortAndUnsupportedChar: 'short!',
+ shortAndMultiLineAndUnsupportedChar: 'short\n!',
+ multiLineAndUnsupportedChar: 'multiline\nvalue!',
+ };
+ const maskedValidationIssuesText = {
+ short: 'The value must have at least 8 characters.',
+ multiLine:
+ 'This value cannot be masked because it contains the following characters: whitespace characters.',
+ unsupportedChar:
+ 'This value cannot be masked because it contains the following characters: |.',
+ unsupportedDollarChar:
+ 'This value cannot be masked because it contains the following characters: $.',
+ twoUnsupportedChars:
+ 'This value cannot be masked because it contains the following characters: |, !.',
+ threeUnsupportedChars:
+ 'This value cannot be masked because it contains the following characters: %, |, !.',
+ shortAndMultiLine:
+ 'This value cannot be masked because it contains the following characters: whitespace characters. The value must have at least 8 characters.',
+ shortAndUnsupportedChar:
+ 'This value cannot be masked because it contains the following characters: !. The value must have at least 8 characters.',
+ shortAndMultiLineAndUnsupportedChar:
+ 'This value cannot be masked because it contains the following characters: ! and whitespace characters. The value must have at least 8 characters.',
+ multiLineAndUnsupportedChar:
+ 'This value cannot be masked because it contains the following characters: ! and whitespace characters.',
+ };
- it(`${
- canSubmit ? 'can submit' : 'shows validation errors and disables submit button'
- } when value is '${value}'`, () => {
- if (canSubmit) {
+ describe.each`
+ value | canSubmit | trackingErrorProperty | validationIssueKey
+ ${'secretValue'} | ${true} | ${null} | ${''}
+ ${'~v@lid:symbols.'} | ${true} | ${null} | ${''}
+ ${invalidValues.short} | ${false} | ${null} | ${'short'}
+ ${invalidValues.multiLine} | ${false} | ${'\n'} | ${'multiLine'}
+ ${'dollar$ign'} | ${false} | ${'$'} | ${'unsupportedDollarChar'}
+ ${invalidValues.unsupportedChar} | ${false} | ${'|'} | ${'unsupportedChar'}
+ ${invalidValues.twoUnsupportedChars} | ${false} | ${'|!'} | ${'twoUnsupportedChars'}
+ ${invalidValues.threeUnsupportedChars} | ${false} | ${'%|!'} | ${'threeUnsupportedChars'}
+ ${invalidValues.shortAndMultiLine} | ${false} | ${'\n'} | ${'shortAndMultiLine'}
+ ${invalidValues.shortAndUnsupportedChar} | ${false} | ${'!'} | ${'shortAndUnsupportedChar'}
+ ${invalidValues.shortAndMultiLineAndUnsupportedChar} | ${false} | ${'\n!'} | ${'shortAndMultiLineAndUnsupportedChar'}
+ ${invalidValues.multiLineAndUnsupportedChar} | ${false} | ${'\n!'} | ${'multiLineAndUnsupportedChar'}
+ `(
+ 'masking requirements',
+ ({ value, canSubmit, trackingErrorProperty, validationIssueKey }) => {
+ beforeEach(() => {
+ createComponent();
+
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ findKeyField().vm.$emit('input', 'NEW_VARIABLE');
+ findValueField().vm.$emit('input', value);
+ findMaskedCheckbox().vm.$emit('input', true);
+ });
+
+ itif(canSubmit)(`can submit when value is ${value}`, () => {
+ /* eslint-disable jest/no-standalone-expect */
expect(findValueLabel().attributes('invalid-feedback')).toBe('');
expect(findConfirmBtn().attributes('disabled')).toBeUndefined();
- } else {
- expect(findValueLabel().attributes('invalid-feedback')).toBe(
- 'This variable value does not meet the masking requirements.',
- );
- expect(findConfirmBtn().attributes('disabled')).toBeDefined();
- }
- });
+ /* eslint-enable jest/no-standalone-expect */
+ });
+
+ itif(!canSubmit)(
+ `shows validation errors and disables submit button when value is ${value}`,
+ () => {
+ const validationIssueText = maskedValidationIssuesText[validationIssueKey] || '';
+
+ /* eslint-disable jest/no-standalone-expect */
+ expect(findValueLabel().attributes('invalid-feedback')).toBe(validationIssueText);
+ expect(findConfirmBtn().attributes('disabled')).toBeDefined();
+ /* eslint-enable jest/no-standalone-expect */
+ },
+ );
+
+ itif(trackingErrorProperty)(
+ `sends the correct variable validation tracking event when value is ${value}`,
+ () => {
+ /* eslint-disable jest/no-standalone-expect */
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTION, {
+ label: DRAWER_EVENT_LABEL,
+ property: trackingErrorProperty,
+ });
+ /* eslint-enable jest/no-standalone-expect */
+ },
+ );
- it(`${
- trackingErrorProperty ? 'sends the correct' : 'does not send the'
- } variable validation tracking event when value is '${value}'`, () => {
- const trackingEventSent = trackingErrorProperty ? 1 : 0;
- expect(trackingSpy).toHaveBeenCalledTimes(trackingEventSent);
-
- if (trackingErrorProperty) {
- expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTION, {
- label: DRAWER_EVENT_LABEL,
- property: trackingErrorProperty,
- });
- }
- });
- });
+ itif(!trackingErrorProperty)(
+ `does not send the the correct variable validation tracking event when value is ${value}`,
+ () => {
+ // eslint-disable-next-line jest/no-standalone-expect
+ expect(trackingSpy).toHaveBeenCalledTimes(0);
+ },
+ );
+ },
+ );
it('only sends the tracking event once', async () => {
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);