diff options
Diffstat (limited to 'spec/frontend/ci_variable_list')
14 files changed, 0 insertions, 2243 deletions
diff --git a/spec/frontend/ci_variable_list/ci_variable_list/ci_variable_list_spec.js b/spec/frontend/ci_variable_list/ci_variable_list/ci_variable_list_spec.js deleted file mode 100644 index 2210b0f48d6..00000000000 --- a/spec/frontend/ci_variable_list/ci_variable_list/ci_variable_list_spec.js +++ /dev/null @@ -1,159 +0,0 @@ -import $ from 'jquery'; -import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; -import VariableList from '~/ci_variable_list/ci_variable_list'; - -const HIDE_CLASS = 'hide'; - -describe('VariableList', () => { - let $wrapper; - let variableList; - - describe('with only key/value inputs', () => { - describe('with no variables', () => { - beforeEach(() => { - loadHTMLFixture('pipeline_schedules/edit.html'); - $wrapper = $('.js-ci-variable-list-section'); - - variableList = new VariableList({ - container: $wrapper, - formField: 'schedule', - }); - variableList.init(); - }); - - afterEach(() => { - resetHTMLFixture(); - }); - - it('should remove the row when clicking the remove button', () => { - $wrapper.find('.js-row-remove-button').trigger('click'); - - expect($wrapper.find('.js-row').length).toBe(0); - }); - - it('should add another row when editing the last rows key input', () => { - const $row = $wrapper.find('.js-row'); - $row.find('.js-ci-variable-input-key').val('foo').trigger('input'); - - expect($wrapper.find('.js-row').length).toBe(2); - - // Check for the correct default in the new row - const $keyInput = $wrapper.find('.js-row:last-child').find('.js-ci-variable-input-key'); - - expect($keyInput.val()).toBe(''); - }); - - it('should add another row when editing the last rows value textarea', () => { - const $row = $wrapper.find('.js-row'); - $row.find('.js-ci-variable-input-value').val('foo').trigger('input'); - - expect($wrapper.find('.js-row').length).toBe(2); - - // Check for the correct default in the new row - const $valueInput = $wrapper.find('.js-row:last-child').find('.js-ci-variable-input-key'); - - expect($valueInput.val()).toBe(''); - }); - - it('should remove empty row after blurring', () => { - const $row = $wrapper.find('.js-row'); - $row.find('.js-ci-variable-input-key').val('foo').trigger('input'); - - expect($wrapper.find('.js-row').length).toBe(2); - - $row.find('.js-ci-variable-input-key').val('').trigger('input').trigger('blur'); - - expect($wrapper.find('.js-row').length).toBe(1); - }); - }); - - describe('with persisted variables', () => { - beforeEach(() => { - loadHTMLFixture('pipeline_schedules/edit_with_variables.html'); - $wrapper = $('.js-ci-variable-list-section'); - - variableList = new VariableList({ - container: $wrapper, - formField: 'schedule', - }); - variableList.init(); - }); - - afterEach(() => { - resetHTMLFixture(); - }); - - it('should have "Reveal values" button initially when there are already variables', () => { - expect($wrapper.find('.js-secret-value-reveal-button').text()).toBe('Reveal values'); - }); - - it('should reveal hidden values', () => { - const $row = $wrapper.find('.js-row:first-child'); - const $inputValue = $row.find('.js-ci-variable-input-value'); - const $placeholder = $row.find('.js-secret-value-placeholder'); - - expect($placeholder.hasClass(HIDE_CLASS)).toBe(false); - expect($inputValue.hasClass(HIDE_CLASS)).toBe(true); - - // Reveal values - $wrapper.find('.js-secret-value-reveal-button').click(); - - expect($placeholder.hasClass(HIDE_CLASS)).toBe(true); - expect($inputValue.hasClass(HIDE_CLASS)).toBe(false); - }); - }); - }); - - describe('toggleEnableRow method', () => { - beforeEach(() => { - loadHTMLFixture('pipeline_schedules/edit_with_variables.html'); - $wrapper = $('.js-ci-variable-list-section'); - - variableList = new VariableList({ - container: $wrapper, - formField: 'variables', - }); - variableList.init(); - }); - - afterEach(() => { - resetHTMLFixture(); - }); - - it('should disable all key inputs', () => { - expect($wrapper.find('.js-ci-variable-input-key:not([disabled])').length).toBe(3); - - variableList.toggleEnableRow(false); - - expect($wrapper.find('.js-ci-variable-input-key[disabled]').length).toBe(3); - }); - - it('should disable all remove buttons', () => { - expect($wrapper.find('.js-row-remove-button:not([disabled])').length).toBe(3); - - variableList.toggleEnableRow(false); - - expect($wrapper.find('.js-row-remove-button[disabled]').length).toBe(3); - }); - - it('should enable all remove buttons', () => { - variableList.toggleEnableRow(false); - - expect($wrapper.find('.js-row-remove-button[disabled]').length).toBe(3); - - variableList.toggleEnableRow(true); - - expect($wrapper.find('.js-row-remove-button:not([disabled])').length).toBe(3); - }); - - it('should enable all key inputs', () => { - variableList.toggleEnableRow(false); - - expect($wrapper.find('.js-ci-variable-input-key[disabled]').length).toBe(3); - - variableList.toggleEnableRow(true); - - expect($wrapper.find('.js-ci-variable-input-key:not([disabled])').length).toBe(3); - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js b/spec/frontend/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js deleted file mode 100644 index 57f666e29d6..00000000000 --- a/spec/frontend/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js +++ /dev/null @@ -1,40 +0,0 @@ -import $ from 'jquery'; -import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; -import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list'; - -describe('NativeFormVariableList', () => { - let $wrapper; - - beforeEach(() => { - loadHTMLFixture('pipeline_schedules/edit.html'); - $wrapper = $('.js-ci-variable-list-section'); - - setupNativeFormVariableList({ - container: $wrapper, - formField: 'schedule', - }); - }); - - afterEach(() => { - resetHTMLFixture(); - }); - - describe('onFormSubmit', () => { - it('should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)', () => { - const $row = $wrapper.find('.js-row'); - - expect($row.find('.js-ci-variable-input-key').attr('name')).toBe( - 'schedule[variables_attributes][][key]', - ); - - expect($row.find('.js-ci-variable-input-value').attr('name')).toBe( - 'schedule[variables_attributes][][secret_value]', - ); - - $wrapper.closest('form').trigger('trigger-submit'); - - expect($row.find('.js-ci-variable-input-key').attr('name')).toBe(''); - expect($row.find('.js-ci-variable-input-value').attr('name')).toBe(''); - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/components/ci_admin_variables_spec.js b/spec/frontend/ci_variable_list/components/ci_admin_variables_spec.js deleted file mode 100644 index aa83638773d..00000000000 --- a/spec/frontend/ci_variable_list/components/ci_admin_variables_spec.js +++ /dev/null @@ -1,36 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; - -import ciAdminVariables from '~/ci_variable_list/components/ci_admin_variables.vue'; -import ciVariableShared from '~/ci_variable_list/components/ci_variable_shared.vue'; - -describe('Ci Project Variable wrapper', () => { - let wrapper; - - const findCiShared = () => wrapper.findComponent(ciVariableShared); - - const createComponent = () => { - wrapper = shallowMount(ciAdminVariables); - }; - - beforeEach(() => { - createComponent(); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it('Passes down the correct props to ci_variable_shared', () => { - expect(findCiShared().props()).toEqual({ - areScopedVariablesAvailable: false, - componentName: 'InstanceVariables', - entity: '', - hideEnvironmentScope: true, - mutationData: wrapper.vm.$options.mutationData, - queryData: wrapper.vm.$options.queryData, - refetchAfterMutation: true, - fullPath: null, - id: null, - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/components/ci_environments_dropdown_spec.js b/spec/frontend/ci_variable_list/components/ci_environments_dropdown_spec.js deleted file mode 100644 index e9966576cab..00000000000 --- a/spec/frontend/ci_variable_list/components/ci_environments_dropdown_spec.js +++ /dev/null @@ -1,139 +0,0 @@ -import { GlDropdown, GlDropdownItem, GlIcon, GlSearchBoxByType } from '@gitlab/ui'; -import { mount } from '@vue/test-utils'; -import { nextTick } from 'vue'; -import { allEnvironments } from '~/ci_variable_list/constants'; -import CiEnvironmentsDropdown from '~/ci_variable_list/components/ci_environments_dropdown.vue'; - -describe('Ci environments dropdown', () => { - let wrapper; - - const envs = ['dev', 'prod', 'staging']; - const defaultProps = { environments: envs, selectedEnvironmentScope: '' }; - - const findDropdownText = () => wrapper.findComponent(GlDropdown).text(); - const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem); - const findDropdownItemByIndex = (index) => wrapper.findAllComponents(GlDropdownItem).at(index); - const findActiveIconByIndex = (index) => findDropdownItemByIndex(index).findComponent(GlIcon); - const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); - - const createComponent = ({ props = {}, searchTerm = '' } = {}) => { - wrapper = mount(CiEnvironmentsDropdown, { - propsData: { - ...defaultProps, - ...props, - }, - }); - - findSearchBox().vm.$emit('input', searchTerm); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - describe('No environments found', () => { - beforeEach(() => { - createComponent({ searchTerm: 'stable' }); - }); - - it('renders create button with search term if environments do not contain search term', () => { - expect(findAllDropdownItems()).toHaveLength(2); - expect(findDropdownItemByIndex(1).text()).toBe('Create wildcard: stable'); - }); - - it('renders empty results message', () => { - expect(findDropdownItemByIndex(0).text()).toBe('No matching results'); - }); - }); - - describe('Search term is empty', () => { - beforeEach(() => { - createComponent({ props: { environments: envs } }); - }); - - it('renders all environments when search term is empty', () => { - expect(findAllDropdownItems()).toHaveLength(3); - expect(findDropdownItemByIndex(0).text()).toBe(envs[0]); - expect(findDropdownItemByIndex(1).text()).toBe(envs[1]); - expect(findDropdownItemByIndex(2).text()).toBe(envs[2]); - }); - - it('should not display active checkmark on the inactive stage', () => { - expect(findActiveIconByIndex(0).classes('gl-visibility-hidden')).toBe(true); - }); - }); - - describe('when `*` is the value of selectedEnvironmentScope props', () => { - const wildcardScope = '*'; - - beforeEach(() => { - createComponent({ props: { selectedEnvironmentScope: wildcardScope } }); - }); - - it('shows the `All environments` text and not the wildcard', () => { - expect(findDropdownText()).toContain(allEnvironments.text); - expect(findDropdownText()).not.toContain(wildcardScope); - }); - }); - - describe('Environments found', () => { - const currentEnv = envs[2]; - - beforeEach(async () => { - createComponent({ searchTerm: currentEnv }); - await nextTick(); - }); - - it('renders only the environment searched for', () => { - expect(findAllDropdownItems()).toHaveLength(1); - expect(findDropdownItemByIndex(0).text()).toBe(currentEnv); - }); - - it('should not display create button', () => { - const environments = findAllDropdownItems().filter((env) => env.text().startsWith('Create')); - expect(environments).toHaveLength(0); - expect(findAllDropdownItems()).toHaveLength(1); - }); - - it('should not display empty results message', () => { - expect(wrapper.findComponent({ ref: 'noMatchingResults' }).exists()).toBe(false); - }); - - it('should clear the search term when showing the dropdown', () => { - wrapper.findComponent(GlDropdown).trigger('click'); - - expect(findSearchBox().text()).toBe(''); - }); - - describe('Custom events', () => { - describe('when clicking on an environment', () => { - const itemIndex = 0; - - beforeEach(() => { - createComponent(); - }); - - it('should emit `select-environment` if an environment is clicked', async () => { - await nextTick(); - - await findDropdownItemByIndex(itemIndex).vm.$emit('click'); - - expect(wrapper.emitted('select-environment')).toEqual([[envs[itemIndex]]]); - }); - }); - - describe('when creating a new environment from a search term', () => { - const search = 'new-env'; - beforeEach(() => { - createComponent({ searchTerm: search }); - }); - - it('should emit createClicked if an environment is clicked', async () => { - await nextTick(); - findDropdownItemByIndex(1).vm.$emit('click'); - expect(wrapper.emitted('create-environment-scope')).toEqual([[search]]); - }); - }); - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/components/ci_group_variables_spec.js b/spec/frontend/ci_variable_list/components/ci_group_variables_spec.js deleted file mode 100644 index ef624d8e4b4..00000000000 --- a/spec/frontend/ci_variable_list/components/ci_group_variables_spec.js +++ /dev/null @@ -1,73 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { convertToGraphQLId } from '~/graphql_shared/utils'; - -import ciGroupVariables from '~/ci_variable_list/components/ci_group_variables.vue'; -import ciVariableShared from '~/ci_variable_list/components/ci_variable_shared.vue'; - -import { GRAPHQL_GROUP_TYPE } from '~/ci_variable_list/constants'; - -const mockProvide = { - glFeatures: { - groupScopedCiVariables: false, - }, - groupPath: '/group', - groupId: 12, -}; - -describe('Ci Group Variable wrapper', () => { - let wrapper; - - const findCiShared = () => wrapper.findComponent(ciVariableShared); - - const createComponent = ({ provide = {} } = {}) => { - wrapper = shallowMount(ciGroupVariables, { - provide: { ...mockProvide, ...provide }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - describe('Props', () => { - beforeEach(() => { - createComponent(); - }); - - it('are passed down the correctly to ci_variable_shared', () => { - expect(findCiShared().props()).toEqual({ - id: convertToGraphQLId(GRAPHQL_GROUP_TYPE, mockProvide.groupId), - areScopedVariablesAvailable: false, - componentName: 'GroupVariables', - entity: 'group', - fullPath: mockProvide.groupPath, - hideEnvironmentScope: false, - mutationData: wrapper.vm.$options.mutationData, - queryData: wrapper.vm.$options.queryData, - refetchAfterMutation: false, - }); - }); - }); - - describe('feature flag', () => { - describe('When enabled', () => { - beforeEach(() => { - createComponent({ provide: { glFeatures: { groupScopedCiVariables: true } } }); - }); - - it('Passes down `true` to variable shared component', () => { - expect(findCiShared().props('areScopedVariablesAvailable')).toBe(true); - }); - }); - - describe('When disabled', () => { - beforeEach(() => { - createComponent({ provide: { glFeatures: { groupScopedCiVariables: false } } }); - }); - - it('Passes down `false` to variable shared component', () => { - expect(findCiShared().props('areScopedVariablesAvailable')).toBe(false); - }); - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js b/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js deleted file mode 100644 index 53c25e430f2..00000000000 --- a/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js +++ /dev/null @@ -1,46 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { convertToGraphQLId } from '~/graphql_shared/utils'; - -import ciProjectVariables from '~/ci_variable_list/components/ci_project_variables.vue'; -import ciVariableShared from '~/ci_variable_list/components/ci_variable_shared.vue'; - -import { GRAPHQL_PROJECT_TYPE } from '~/ci_variable_list/constants'; - -const mockProvide = { - projectFullPath: '/namespace/project', - projectId: 1, -}; - -describe('Ci Project Variable wrapper', () => { - let wrapper; - - const findCiShared = () => wrapper.findComponent(ciVariableShared); - - const createComponent = () => { - wrapper = shallowMount(ciProjectVariables, { - provide: mockProvide, - }); - }; - - beforeEach(() => { - createComponent(); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it('Passes down the correct props to ci_variable_shared', () => { - expect(findCiShared().props()).toEqual({ - id: convertToGraphQLId(GRAPHQL_PROJECT_TYPE, mockProvide.projectId), - areScopedVariablesAvailable: true, - componentName: 'ProjectVariables', - entity: 'project', - fullPath: mockProvide.projectFullPath, - hideEnvironmentScope: false, - mutationData: wrapper.vm.$options.mutationData, - queryData: wrapper.vm.$options.queryData, - refetchAfterMutation: false, - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js deleted file mode 100644 index d177e755591..00000000000 --- a/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js +++ /dev/null @@ -1,520 +0,0 @@ -import { GlButton, GlFormInput } from '@gitlab/ui'; -import { mockTracking } from 'helpers/tracking_helper'; -import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; -import CiEnvironmentsDropdown from '~/ci_variable_list/components/ci_environments_dropdown.vue'; -import CiVariableModal from '~/ci_variable_list/components/ci_variable_modal.vue'; -import { - ADD_VARIABLE_ACTION, - AWS_ACCESS_KEY_ID, - EDIT_VARIABLE_ACTION, - EVENT_LABEL, - EVENT_ACTION, - ENVIRONMENT_SCOPE_LINK_TITLE, - instanceString, - variableOptions, -} from '~/ci_variable_list/constants'; -import { mockVariablesWithScopes } from '../mocks'; -import ModalStub from '../stubs'; - -describe('Ci variable modal', () => { - let wrapper; - let trackingSpy; - - const maskableRegex = '^[a-zA-Z0-9_+=/@:.~-]{8,}$'; - const mockVariables = mockVariablesWithScopes(instanceString); - - const defaultProvide = { - awsLogoSvgPath: '/logo', - awsTipCommandsLink: '/tips', - awsTipDeployLink: '/deploy', - awsTipLearnLink: '/learn-link', - containsVariableReferenceLink: '/reference', - environmentScopeLink: '/help/environments', - isProtectedByDefault: false, - maskedEnvironmentVariablesLink: '/variables-link', - maskableRegex, - protectedEnvironmentVariablesLink: '/protected-link', - }; - - const defaultProps = { - areScopedVariablesAvailable: true, - environments: [], - hideEnvironmentScope: false, - mode: ADD_VARIABLE_ACTION, - selectedVariable: {}, - variable: [], - }; - - const createComponent = ({ mountFn = shallowMountExtended, props = {}, provide = {} } = {}) => { - wrapper = mountFn(CiVariableModal, { - attachTo: document.body, - provide: { ...defaultProvide, ...provide }, - propsData: { - ...defaultProps, - ...props, - }, - stubs: { - GlModal: ModalStub, - }, - }); - }; - - const findCiEnvironmentsDropdown = () => wrapper.findComponent(CiEnvironmentsDropdown); - const findReferenceWarning = () => wrapper.findByTestId('contains-variable-reference'); - const findModal = () => wrapper.findComponent(ModalStub); - const findAWSTip = () => wrapper.findByTestId('aws-guidance-tip'); - const findAddorUpdateButton = () => wrapper.findByTestId('ciUpdateOrAddVariableBtn'); - const deleteVariableButton = () => - findModal() - .findAllComponents(GlButton) - .wrappers.find((button) => button.props('variant') === 'danger'); - const findExpandedVariableCheckbox = () => wrapper.findByTestId('ci-variable-expanded-checkbox'); - const findProtectedVariableCheckbox = () => - wrapper.findByTestId('ci-variable-protected-checkbox'); - const findMaskedVariableCheckbox = () => wrapper.findByTestId('ci-variable-masked-checkbox'); - const findValueField = () => wrapper.find('#ci-variable-value'); - const findEnvScopeLink = () => wrapper.findByTestId('environment-scope-link'); - const findEnvScopeInput = () => - wrapper.findByTestId('environment-scope').findComponent(GlFormInput); - const findRawVarTip = () => wrapper.findByTestId('raw-variable-tip'); - const findVariableTypeDropdown = () => wrapper.find('#ci-variable-type'); - const findEnvironmentScopeText = () => wrapper.findByText('Environment scope'); - - afterEach(() => { - wrapper.destroy(); - }); - - describe('Adding a variable', () => { - describe('when no key/value pair are present', () => { - beforeEach(() => { - createComponent(); - }); - - it('shows the submit button as disabled', () => { - expect(findAddorUpdateButton().attributes('disabled')).toBe('true'); - }); - }); - - describe('when a key/value pair is present', () => { - beforeEach(() => { - createComponent({ props: { selectedVariable: mockVariables[0] } }); - }); - - it('shows the submit button as enabled', () => { - expect(findAddorUpdateButton().attributes('disabled')).toBeUndefined(); - }); - }); - - describe('events', () => { - const [currentVariable] = mockVariables; - - beforeEach(() => { - createComponent({ props: { selectedVariable: currentVariable } }); - jest.spyOn(wrapper.vm, '$emit'); - }); - - it('Dispatches `add-variable` action on submit', () => { - findAddorUpdateButton().vm.$emit('click'); - expect(wrapper.emitted('add-variable')).toEqual([[currentVariable]]); - }); - - it('Dispatches the `hideModal` event when dismissing', () => { - findModal().vm.$emit('hidden'); - expect(wrapper.emitted('hideModal')).toEqual([[]]); - }); - }); - }); - - describe('when protected by default', () => { - describe('when adding a new variable', () => { - beforeEach(() => { - createComponent({ provide: { isProtectedByDefault: true } }); - findModal().vm.$emit('shown'); - }); - - it('updates the protected value to true', () => { - expect(findProtectedVariableCheckbox().attributes('data-is-protected-checked')).toBe( - 'true', - ); - }); - }); - - describe('when editing a variable', () => { - beforeEach(() => { - createComponent({ - provide: { isProtectedByDefault: false }, - props: { - selectedVariable: {}, - mode: EDIT_VARIABLE_ACTION, - }, - }); - findModal().vm.$emit('shown'); - }); - - it('keeps the value as false', async () => { - expect( - findProtectedVariableCheckbox().attributes('data-is-protected-checked'), - ).toBeUndefined(); - }); - }); - }); - - describe('Adding a new non-AWS variable', () => { - beforeEach(() => { - const [variable] = mockVariables; - createComponent({ mountFn: mountExtended, props: { selectedVariable: variable } }); - }); - - it('does not show AWS guidance tip', () => { - const tip = findAWSTip(); - expect(tip.exists()).toBe(true); - expect(tip.isVisible()).toBe(false); - }); - }); - - describe('Adding a new AWS variable', () => { - beforeEach(() => { - const [variable] = mockVariables; - const AWSKeyVariable = { - ...variable, - key: AWS_ACCESS_KEY_ID, - value: 'AKIAIOSFODNN7EXAMPLEjdhy', - }; - createComponent({ mountFn: mountExtended, props: { selectedVariable: AWSKeyVariable } }); - }); - - it('shows AWS guidance tip', () => { - const tip = findAWSTip(); - expect(tip.exists()).toBe(true); - expect(tip.isVisible()).toBe(true); - }); - }); - - describe('when expanded', () => { - describe('with a $ character', () => { - beforeEach(() => { - const [variable] = mockVariables; - const variableWithDollarSign = { - ...variable, - value: 'valueWith$', - }; - createComponent({ - mountFn: mountExtended, - props: { selectedVariable: variableWithDollarSign }, - }); - }); - - it(`renders the variable reference warning`, () => { - expect(findReferenceWarning().exists()).toBe(true); - }); - - it(`does not render raw variable tip`, () => { - expect(findRawVarTip().exists()).toBe(false); - }); - }); - - describe('without a $ character', () => { - beforeEach(() => { - const [variable] = mockVariables; - createComponent({ - mountFn: mountExtended, - props: { selectedVariable: variable }, - }); - }); - - it(`does not render the variable reference warning`, () => { - expect(findReferenceWarning().exists()).toBe(false); - }); - - it(`does not render raw variable tip`, () => { - expect(findRawVarTip().exists()).toBe(false); - }); - }); - - describe('setting raw value', () => { - const [variable] = mockVariables; - - it('defaults to expanded and raw:false when adding a variable', () => { - createComponent({ props: { selectedVariable: variable } }); - jest.spyOn(wrapper.vm, '$emit'); - - findModal().vm.$emit('shown'); - - expect(findExpandedVariableCheckbox().attributes('checked')).toBe('true'); - - findAddorUpdateButton().vm.$emit('click'); - - expect(wrapper.emitted('add-variable')).toEqual([ - [ - { - ...variable, - raw: false, - }, - ], - ]); - }); - - it('sets correct raw value when editing', async () => { - createComponent({ - props: { - selectedVariable: variable, - mode: EDIT_VARIABLE_ACTION, - }, - }); - jest.spyOn(wrapper.vm, '$emit'); - - findModal().vm.$emit('shown'); - await findExpandedVariableCheckbox().vm.$emit('change'); - await findAddorUpdateButton().vm.$emit('click'); - - expect(wrapper.emitted('update-variable')).toEqual([ - [ - { - ...variable, - raw: true, - }, - ], - ]); - }); - }); - }); - - describe('when not expanded', () => { - describe('with a $ character', () => { - beforeEach(() => { - const selectedVariable = mockVariables[1]; - createComponent({ - mountFn: mountExtended, - props: { selectedVariable }, - }); - }); - - it(`renders raw variable tip`, () => { - expect(findRawVarTip().exists()).toBe(true); - }); - }); - }); - - describe('Editing a variable', () => { - const [variable] = mockVariables; - - beforeEach(() => { - createComponent({ props: { selectedVariable: variable, mode: EDIT_VARIABLE_ACTION } }); - jest.spyOn(wrapper.vm, '$emit'); - }); - - it('button text is Update variable when updating', () => { - expect(findAddorUpdateButton().text()).toBe('Update variable'); - }); - - it('Update variable button dispatches updateVariable with correct variable', () => { - findAddorUpdateButton().vm.$emit('click'); - expect(wrapper.emitted('update-variable')).toEqual([[variable]]); - }); - - it('Propagates the `hideModal` event', () => { - findModal().vm.$emit('hidden'); - expect(wrapper.emitted('hideModal')).toEqual([[]]); - }); - - it('dispatches `delete-variable` with correct variable to delete', () => { - deleteVariableButton().vm.$emit('click'); - expect(wrapper.emitted('delete-variable')).toEqual([[variable]]); - }); - }); - - describe('Environment scope', () => { - describe('when feature is available', () => { - describe('and section is not hidden', () => { - beforeEach(() => { - createComponent({ - mountFn: mountExtended, - props: { - areScopedVariablesAvailable: true, - hideEnvironmentScope: false, - }, - }); - }); - - it('renders the environment dropdown and section title', () => { - expect(findCiEnvironmentsDropdown().exists()).toBe(true); - expect(findCiEnvironmentsDropdown().isVisible()).toBe(true); - expect(findEnvironmentScopeText().exists()).toBe(true); - }); - - it('renders a link to documentation on scopes', () => { - const link = findEnvScopeLink(); - - expect(link.attributes('title')).toBe(ENVIRONMENT_SCOPE_LINK_TITLE); - expect(link.attributes('href')).toBe(defaultProvide.environmentScopeLink); - }); - }); - - describe('and section is hidden', () => { - beforeEach(() => { - createComponent({ - mountFn: mountExtended, - props: { - areScopedVariablesAvailable: true, - hideEnvironmentScope: true, - }, - }); - }); - - it('does not renders the environment dropdown and section title', () => { - expect(findCiEnvironmentsDropdown().exists()).toBe(false); - expect(findEnvironmentScopeText().exists()).toBe(false); - }); - }); - }); - - describe('when feature is not available', () => { - describe('and section is not hidden', () => { - beforeEach(() => { - createComponent({ - mountFn: mountExtended, - props: { - areScopedVariablesAvailable: false, - hideEnvironmentScope: false, - }, - }); - }); - - it('disables the dropdown', () => { - expect(findCiEnvironmentsDropdown().exists()).toBe(false); - expect(findEnvironmentScopeText().exists()).toBe(true); - expect(findEnvScopeInput().attributes('readonly')).toBe('readonly'); - }); - }); - - describe('and section is hidden', () => { - beforeEach(() => { - createComponent({ - mountFn: mountExtended, - props: { - areScopedVariablesAvailable: false, - hideEnvironmentScope: true, - }, - }); - }); - - it('hides the dropdown', () => { - expect(findEnvironmentScopeText().exists()).toBe(false); - expect(findCiEnvironmentsDropdown().exists()).toBe(false); - }); - }); - }); - }); - - describe('variable type dropdown', () => { - describe('default behaviour', () => { - beforeEach(() => { - createComponent({ mountFn: mountExtended }); - }); - - it('adds each option as a dropdown item', () => { - expect(findVariableTypeDropdown().findAll('option')).toHaveLength(variableOptions.length); - variableOptions.forEach((v) => { - expect(findVariableTypeDropdown().text()).toContain(v.text); - }); - }); - }); - }); - - describe('Validations', () => { - const maskError = 'This variable can not be masked.'; - - describe('when the mask state is invalid', () => { - beforeEach(async () => { - const [variable] = mockVariables; - const invalidMaskVariable = { - ...variable, - value: 'd:;', - masked: false, - }; - createComponent({ - mountFn: mountExtended, - props: { selectedVariable: invalidMaskVariable }, - }); - trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); - await findMaskedVariableCheckbox().trigger('click'); - }); - - it('disables the submit button', () => { - expect(findAddorUpdateButton().attributes('disabled')).toBe('disabled'); - }); - - it('shows the correct error text', () => { - expect(findModal().text()).toContain(maskError); - }); - - it('sends the correct tracking event', () => { - expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTION, { - label: EVENT_LABEL, - property: ';', - }); - }); - }); - - describe.each` - value | masked | eventSent | trackingErrorProperty - ${'secretValue'} | ${false} | ${0} | ${null} - ${'short'} | ${true} | ${0} | ${null} - ${'dollar$ign'} | ${false} | ${1} | ${'$'} - ${'dollar$ign'} | ${true} | ${1} | ${'$'} - ${'unsupported|char'} | ${true} | ${1} | ${'|'} - ${'unsupported|char'} | ${false} | ${0} | ${null} - `('Adding a new variable', ({ value, masked, eventSent, trackingErrorProperty }) => { - beforeEach(async () => { - const [variable] = mockVariables; - const invalidKeyVariable = { - ...variable, - value: '', - masked: false, - }; - createComponent({ - mountFn: mountExtended, - props: { selectedVariable: invalidKeyVariable }, - }); - trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); - await findValueField().vm.$emit('input', value); - if (masked) { - await findMaskedVariableCheckbox().trigger('click'); - } - }); - - it(`${ - eventSent > 0 ? 'sends the correct' : 'does not send the' - } variable validation tracking event with ${value}`, () => { - expect(trackingSpy).toHaveBeenCalledTimes(eventSent); - - if (eventSent > 0) { - expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTION, { - label: EVENT_LABEL, - property: trackingErrorProperty, - }); - } - }); - }); - - describe('when masked variable has acceptable value', () => { - beforeEach(() => { - const [variable] = mockVariables; - const validMaskandKeyVariable = { - ...variable, - key: AWS_ACCESS_KEY_ID, - value: '12345678', - masked: true, - }; - createComponent({ - mountFn: mountExtended, - props: { selectedVariable: validMaskandKeyVariable }, - }); - }); - - it('does not disable the submit button', () => { - expect(findAddorUpdateButton().attributes('disabled')).toBeUndefined(); - }); - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/components/ci_variable_settings_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_settings_spec.js deleted file mode 100644 index 5e459ee390f..00000000000 --- a/spec/frontend/ci_variable_list/components/ci_variable_settings_spec.js +++ /dev/null @@ -1,147 +0,0 @@ -import { nextTick } from 'vue'; -import { shallowMount } from '@vue/test-utils'; -import CiVariableSettings from '~/ci_variable_list/components/ci_variable_settings.vue'; -import ciVariableModal from '~/ci_variable_list/components/ci_variable_modal.vue'; -import ciVariableTable from '~/ci_variable_list/components/ci_variable_table.vue'; -import { - ADD_VARIABLE_ACTION, - EDIT_VARIABLE_ACTION, - projectString, -} from '~/ci_variable_list/constants'; -import { mapEnvironmentNames } from '~/ci_variable_list/utils'; - -import { mockEnvs, mockVariablesWithScopes, newVariable } from '../mocks'; - -describe('Ci variable table', () => { - let wrapper; - - const defaultProps = { - areScopedVariablesAvailable: true, - entity: 'project', - environments: mapEnvironmentNames(mockEnvs), - hideEnvironmentScope: false, - isLoading: false, - maxVariableLimit: 5, - variables: mockVariablesWithScopes(projectString), - }; - - const findCiVariableTable = () => wrapper.findComponent(ciVariableTable); - const findCiVariableModal = () => wrapper.findComponent(ciVariableModal); - - const createComponent = ({ props = {} } = {}) => { - wrapper = shallowMount(CiVariableSettings, { - propsData: { - ...defaultProps, - ...props, - }, - }); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - describe('props passing', () => { - it('passes props down correctly to the ci table', () => { - createComponent(); - - expect(findCiVariableTable().props()).toEqual({ - entity: 'project', - isLoading: defaultProps.isLoading, - maxVariableLimit: defaultProps.maxVariableLimit, - variables: defaultProps.variables, - }); - }); - - it('passes props down correctly to the ci modal', async () => { - createComponent(); - - findCiVariableTable().vm.$emit('set-selected-variable'); - await nextTick(); - - expect(findCiVariableModal().props()).toEqual({ - areScopedVariablesAvailable: defaultProps.areScopedVariablesAvailable, - environments: defaultProps.environments, - hideEnvironmentScope: defaultProps.hideEnvironmentScope, - variables: defaultProps.variables, - mode: ADD_VARIABLE_ACTION, - selectedVariable: {}, - }); - }); - }); - - describe('modal mode', () => { - beforeEach(() => { - createComponent(); - }); - - it('passes down ADD mode when receiving an empty variable', async () => { - findCiVariableTable().vm.$emit('set-selected-variable'); - await nextTick(); - - expect(findCiVariableModal().props('mode')).toBe(ADD_VARIABLE_ACTION); - }); - - it('passes down EDIT mode when receiving a variable', async () => { - findCiVariableTable().vm.$emit('set-selected-variable', newVariable); - await nextTick(); - - expect(findCiVariableModal().props('mode')).toBe(EDIT_VARIABLE_ACTION); - }); - }); - - describe('variable modal', () => { - beforeEach(() => { - createComponent(); - }); - - it('is hidden by default', () => { - expect(findCiVariableModal().exists()).toBe(false); - }); - - it('shows modal when adding a new variable', async () => { - findCiVariableTable().vm.$emit('set-selected-variable'); - await nextTick(); - - expect(findCiVariableModal().exists()).toBe(true); - }); - - it('shows modal when updating a variable', async () => { - findCiVariableTable().vm.$emit('set-selected-variable', newVariable); - await nextTick(); - - expect(findCiVariableModal().exists()).toBe(true); - }); - - it('hides modal when receiving the event from the modal', async () => { - findCiVariableTable().vm.$emit('set-selected-variable'); - await nextTick(); - - findCiVariableModal().vm.$emit('hideModal'); - await nextTick(); - - expect(findCiVariableModal().exists()).toBe(false); - }); - }); - - describe('variable events', () => { - beforeEach(() => { - createComponent(); - }); - - it.each` - eventName - ${'add-variable'} - ${'update-variable'} - ${'delete-variable'} - `('bubbles up the $eventName event', async ({ eventName }) => { - findCiVariableTable().vm.$emit('set-selected-variable'); - await nextTick(); - - findCiVariableModal().vm.$emit(eventName, newVariable); - await nextTick(); - - expect(wrapper.emitted(eventName)).toEqual([[newVariable]]); - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/components/ci_variable_shared_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_shared_spec.js deleted file mode 100644 index 65a58a1647f..00000000000 --- a/spec/frontend/ci_variable_list/components/ci_variable_shared_spec.js +++ /dev/null @@ -1,450 +0,0 @@ -import Vue, { nextTick } from 'vue'; -import VueApollo from 'vue-apollo'; -import { GlLoadingIcon, GlTable } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import createMockApollo from 'helpers/mock_apollo_helper'; -import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/flash'; -import { resolvers } from '~/ci_variable_list/graphql/settings'; -import { convertToGraphQLId } from '~/graphql_shared/utils'; - -import ciVariableShared from '~/ci_variable_list/components/ci_variable_shared.vue'; -import ciVariableSettings from '~/ci_variable_list/components/ci_variable_settings.vue'; -import ciVariableTable from '~/ci_variable_list/components/ci_variable_table.vue'; -import getProjectEnvironments from '~/ci_variable_list/graphql/queries/project_environments.query.graphql'; -import getAdminVariables from '~/ci_variable_list/graphql/queries/variables.query.graphql'; -import getGroupVariables from '~/ci_variable_list/graphql/queries/group_variables.query.graphql'; -import getProjectVariables from '~/ci_variable_list/graphql/queries/project_variables.query.graphql'; - -import { - ADD_MUTATION_ACTION, - DELETE_MUTATION_ACTION, - UPDATE_MUTATION_ACTION, - environmentFetchErrorText, - genericMutationErrorText, - variableFetchErrorText, -} from '~/ci_variable_list/constants'; - -import { - createGroupProps, - createInstanceProps, - createProjectProps, - createGroupProvide, - createProjectProvide, - devName, - mockProjectEnvironments, - mockProjectVariables, - newVariable, - prodName, - mockGroupVariables, - mockAdminVariables, -} from '../mocks'; - -jest.mock('~/flash'); - -Vue.use(VueApollo); - -const mockProvide = { - endpoint: '/variables', - isGroup: false, - isProject: false, -}; - -const defaultProps = { - areScopedVariablesAvailable: true, - hideEnvironmentScope: false, - refetchAfterMutation: false, -}; - -describe('Ci Variable Shared Component', () => { - let wrapper; - - let mockApollo; - let mockEnvironments; - let mockVariables; - - const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); - const findCiTable = () => wrapper.findComponent(GlTable); - const findCiSettings = () => wrapper.findComponent(ciVariableSettings); - - // eslint-disable-next-line consistent-return - async function createComponentWithApollo({ - customHandlers = null, - isLoading = false, - props = { ...createProjectProps() }, - provide = {}, - } = {}) { - const handlers = customHandlers || [ - [getProjectEnvironments, mockEnvironments], - [getProjectVariables, mockVariables], - ]; - - mockApollo = createMockApollo(handlers, resolvers); - - wrapper = shallowMount(ciVariableShared, { - propsData: { - ...defaultProps, - ...props, - }, - provide: { - ...mockProvide, - ...provide, - }, - apolloProvider: mockApollo, - stubs: { ciVariableSettings, ciVariableTable }, - }); - - if (!isLoading) { - return waitForPromises(); - } - } - - beforeEach(() => { - mockEnvironments = jest.fn(); - mockVariables = jest.fn(); - }); - - describe('while queries are being fetch', () => { - beforeEach(() => { - createComponentWithApollo({ isLoading: true }); - }); - - it('shows a loading icon', () => { - expect(findLoadingIcon().exists()).toBe(true); - expect(findCiTable().exists()).toBe(false); - }); - }); - - describe('when queries are resolved', () => { - describe('successfully', () => { - beforeEach(async () => { - mockEnvironments.mockResolvedValue(mockProjectEnvironments); - mockVariables.mockResolvedValue(mockProjectVariables); - - await createComponentWithApollo({ provide: createProjectProvide() }); - }); - - it('passes down the expected max variable limit as props', () => { - expect(findCiSettings().props('maxVariableLimit')).toBe( - mockProjectVariables.data.project.ciVariables.limit, - ); - }); - - it('passes down the expected environments as props', () => { - expect(findCiSettings().props('environments')).toEqual([prodName, devName]); - }); - - it('passes down the expected variables as props', () => { - expect(findCiSettings().props('variables')).toEqual( - mockProjectVariables.data.project.ciVariables.nodes, - ); - }); - - it('createAlert was not called', () => { - expect(createAlert).not.toHaveBeenCalled(); - }); - }); - - describe('with an error for variables', () => { - beforeEach(async () => { - mockEnvironments.mockResolvedValue(mockProjectEnvironments); - mockVariables.mockRejectedValue(); - - await createComponentWithApollo(); - }); - - it('calls createAlert with the expected error message', () => { - expect(createAlert).toHaveBeenCalledWith({ message: variableFetchErrorText }); - }); - }); - - describe('with an error for environments', () => { - beforeEach(async () => { - mockEnvironments.mockRejectedValue(); - mockVariables.mockResolvedValue(mockProjectVariables); - - await createComponentWithApollo(); - }); - - it('calls createAlert with the expected error message', () => { - expect(createAlert).toHaveBeenCalledWith({ message: environmentFetchErrorText }); - }); - }); - }); - - describe('environment query', () => { - describe('when there is an environment key in queryData', () => { - beforeEach(async () => { - mockEnvironments.mockResolvedValue(mockProjectEnvironments); - mockVariables.mockResolvedValue(mockProjectVariables); - - await createComponentWithApollo({ props: { ...createProjectProps() } }); - }); - - it('is executed', () => { - expect(mockVariables).toHaveBeenCalled(); - }); - }); - - describe('when there isnt an environment key in queryData', () => { - beforeEach(async () => { - mockVariables.mockResolvedValue(mockGroupVariables); - - await createComponentWithApollo({ props: { ...createGroupProps() } }); - }); - - it('is skipped', () => { - expect(mockVariables).not.toHaveBeenCalled(); - }); - }); - }); - - describe('mutations', () => { - const groupProps = createGroupProps(); - - beforeEach(async () => { - mockVariables.mockResolvedValue(mockGroupVariables); - - await createComponentWithApollo({ - customHandlers: [[getGroupVariables, mockVariables]], - props: groupProps, - }); - }); - it.each` - actionName | mutation | event - ${'add'} | ${groupProps.mutationData[ADD_MUTATION_ACTION]} | ${'add-variable'} - ${'update'} | ${groupProps.mutationData[UPDATE_MUTATION_ACTION]} | ${'update-variable'} - ${'delete'} | ${groupProps.mutationData[DELETE_MUTATION_ACTION]} | ${'delete-variable'} - `( - 'calls the right mutation from propsData when user performs $actionName variable', - async ({ event, mutation }) => { - jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(); - - await findCiSettings().vm.$emit(event, newVariable); - - expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({ - mutation, - variables: { - endpoint: mockProvide.endpoint, - fullPath: groupProps.fullPath, - id: convertToGraphQLId('Group', groupProps.id), - variable: newVariable, - }, - }); - }, - ); - - it.each` - actionName | event - ${'add'} | ${'add-variable'} - ${'update'} | ${'update-variable'} - ${'delete'} | ${'delete-variable'} - `( - 'throws with the specific graphql error if present when user performs $actionName variable', - async ({ event }) => { - const graphQLErrorMessage = 'There is a problem with this graphQL action'; - jest - .spyOn(wrapper.vm.$apollo, 'mutate') - .mockResolvedValue({ data: { ciVariableMutation: { errors: [graphQLErrorMessage] } } }); - await findCiSettings().vm.$emit(event, newVariable); - await nextTick(); - - expect(wrapper.vm.$apollo.mutate).toHaveBeenCalled(); - expect(createAlert).toHaveBeenCalledWith({ message: graphQLErrorMessage }); - }, - ); - - it.each` - actionName | event - ${'add'} | ${'add-variable'} - ${'update'} | ${'update-variable'} - ${'delete'} | ${'delete-variable'} - `( - 'throws generic error on failure with no graphql errors and user performs $actionName variable', - async ({ event }) => { - jest.spyOn(wrapper.vm.$apollo, 'mutate').mockImplementationOnce(() => { - throw new Error(); - }); - await findCiSettings().vm.$emit(event, newVariable); - - expect(wrapper.vm.$apollo.mutate).toHaveBeenCalled(); - expect(createAlert).toHaveBeenCalledWith({ message: genericMutationErrorText }); - }, - ); - - describe('without fullpath and ID props', () => { - beforeEach(async () => { - mockVariables.mockResolvedValue(mockAdminVariables); - - await createComponentWithApollo({ - customHandlers: [[getAdminVariables, mockVariables]], - props: createInstanceProps(), - }); - }); - - it('does not pass fullPath and ID to the mutation', async () => { - jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(); - - await findCiSettings().vm.$emit('add-variable', newVariable); - - expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({ - mutation: wrapper.props().mutationData[ADD_MUTATION_ACTION], - variables: { - endpoint: mockProvide.endpoint, - variable: newVariable, - }, - }); - }); - }); - }); - - describe('Props', () => { - const mockGroupCiVariables = mockGroupVariables.data.group.ciVariables; - const mockProjectCiVariables = mockProjectVariables.data.project.ciVariables; - - describe('in a specific context as', () => { - it.each` - name | mockVariablesValue | mockEnvironmentsValue | withEnvironments | expectedEnvironments | propsFn | provideFn | mutation | maxVariableLimit - ${'project'} | ${mockProjectVariables} | ${mockProjectEnvironments} | ${true} | ${['prod', 'dev']} | ${createProjectProps} | ${createProjectProvide} | ${null} | ${mockProjectCiVariables.limit} - ${'group'} | ${mockGroupVariables} | ${[]} | ${false} | ${[]} | ${createGroupProps} | ${createGroupProvide} | ${getGroupVariables} | ${mockGroupCiVariables.limit} - ${'instance'} | ${mockAdminVariables} | ${[]} | ${false} | ${[]} | ${createInstanceProps} | ${() => {}} | ${getAdminVariables} | ${0} - `( - 'passes down all the required props when its a $name component', - async ({ - mutation, - maxVariableLimit, - mockVariablesValue, - mockEnvironmentsValue, - withEnvironments, - expectedEnvironments, - propsFn, - provideFn, - }) => { - const props = propsFn(); - const provide = provideFn(); - - mockVariables.mockResolvedValue(mockVariablesValue); - - if (withEnvironments) { - mockEnvironments.mockResolvedValue(mockEnvironmentsValue); - } - - let customHandlers = null; - - if (mutation) { - customHandlers = [[mutation, mockVariables]]; - } - - await createComponentWithApollo({ customHandlers, props, provide }); - - expect(findCiSettings().props()).toEqual({ - areScopedVariablesAvailable: wrapper.props().areScopedVariablesAvailable, - hideEnvironmentScope: defaultProps.hideEnvironmentScope, - isLoading: false, - maxVariableLimit, - variables: wrapper.props().queryData.ciVariables.lookup(mockVariablesValue.data)?.nodes, - entity: props.entity, - environments: expectedEnvironments, - }); - }, - ); - }); - - describe('refetchAfterMutation', () => { - it.each` - bool | text - ${true} | ${'refetches the variables'} - ${false} | ${'does not refetch the variables'} - `('when $bool it $text', async ({ bool }) => { - await createComponentWithApollo({ - props: { ...createInstanceProps(), refetchAfterMutation: bool }, - }); - - jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({ data: {} }); - jest.spyOn(wrapper.vm.$apollo.queries.ciVariables, 'refetch').mockImplementation(jest.fn()); - - await findCiSettings().vm.$emit('add-variable', newVariable); - - await nextTick(); - - if (bool) { - expect(wrapper.vm.$apollo.queries.ciVariables.refetch).toHaveBeenCalled(); - } else { - expect(wrapper.vm.$apollo.queries.ciVariables.refetch).not.toHaveBeenCalled(); - } - }); - }); - - describe('Validators', () => { - describe('queryData', () => { - let error; - - beforeEach(async () => { - mockVariables.mockResolvedValue(mockGroupVariables); - }); - - it('will mount component with right data', async () => { - try { - await createComponentWithApollo({ - customHandlers: [[getGroupVariables, mockVariables]], - props: { ...createGroupProps() }, - }); - } catch (e) { - error = e; - } finally { - expect(wrapper.exists()).toBe(true); - expect(error).toBeUndefined(); - } - }); - - it('will not mount component with wrong data', async () => { - try { - await createComponentWithApollo({ - customHandlers: [[getGroupVariables, mockVariables]], - props: { ...createGroupProps(), queryData: { wrongKey: {} } }, - }); - } catch (e) { - error = e; - } finally { - expect(wrapper.exists()).toBe(false); - expect(error.toString()).toContain('custom validator check failed for prop'); - } - }); - }); - - describe('mutationData', () => { - let error; - - beforeEach(async () => { - mockVariables.mockResolvedValue(mockGroupVariables); - }); - - it('will mount component with right data', async () => { - try { - await createComponentWithApollo({ - props: { ...createGroupProps() }, - }); - } catch (e) { - error = e; - } finally { - expect(wrapper.exists()).toBe(true); - expect(error).toBeUndefined(); - } - }); - - it('will not mount component with wrong data', async () => { - try { - await createComponentWithApollo({ - props: { ...createGroupProps(), mutationData: { wrongKey: {} } }, - }); - } catch (e) { - error = e; - } finally { - expect(wrapper.exists()).toBe(false); - expect(error.toString()).toContain('custom validator check failed for prop'); - } - }); - }); - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/components/ci_variable_table_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_table_spec.js deleted file mode 100644 index 9891bc397b6..00000000000 --- a/spec/frontend/ci_variable_list/components/ci_variable_table_spec.js +++ /dev/null @@ -1,172 +0,0 @@ -import { GlAlert } from '@gitlab/ui'; -import { sprintf } from '~/locale'; -import { mountExtended } from 'helpers/vue_test_utils_helper'; -import CiVariableTable from '~/ci_variable_list/components/ci_variable_table.vue'; -import { EXCEEDS_VARIABLE_LIMIT_TEXT, projectString } from '~/ci_variable_list/constants'; -import { mockVariables } from '../mocks'; - -describe('Ci variable table', () => { - let wrapper; - - const defaultProps = { - entity: 'project', - isLoading: false, - maxVariableLimit: mockVariables(projectString).length + 1, - variables: mockVariables(projectString), - }; - - const mockMaxVariableLimit = defaultProps.variables.length; - - const createComponent = ({ props = {} } = {}) => { - wrapper = mountExtended(CiVariableTable, { - attachTo: document.body, - propsData: { - ...defaultProps, - ...props, - }, - }); - }; - - const findRevealButton = () => wrapper.findByText('Reveal values'); - const findAddButton = () => wrapper.findByLabelText('Add'); - const findEditButton = () => wrapper.findByLabelText('Edit'); - const findEmptyVariablesPlaceholder = () => wrapper.findByText('There are no variables yet.'); - const findHiddenValues = () => wrapper.findAllByTestId('hiddenValue'); - const findLimitReachedAlerts = () => wrapper.findAllComponents(GlAlert); - const findRevealedValues = () => wrapper.findAllByTestId('revealedValue'); - const findOptionsValues = (rowIndex) => - wrapper.findAllByTestId('ci-variable-table-row-options').at(rowIndex).text(); - - const generateExceedsVariableLimitText = (entity, currentVariableCount, maxVariableLimit) => { - return sprintf(EXCEEDS_VARIABLE_LIMIT_TEXT, { entity, currentVariableCount, maxVariableLimit }); - }; - - beforeEach(() => { - createComponent(); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - describe('When table is empty', () => { - beforeEach(() => { - createComponent({ props: { variables: [] } }); - }); - - it('displays empty message', () => { - expect(findEmptyVariablesPlaceholder().exists()).toBe(true); - }); - - it('hides the reveal button', () => { - expect(findRevealButton().exists()).toBe(false); - }); - }); - - describe('When table has variables', () => { - beforeEach(() => { - createComponent(); - }); - - it('does not display the empty message', () => { - expect(findEmptyVariablesPlaceholder().exists()).toBe(false); - }); - - it('displays the reveal button', () => { - expect(findRevealButton().exists()).toBe(true); - }); - - it('displays the correct amount of variables', async () => { - expect(wrapper.findAll('.js-ci-variable-row')).toHaveLength(defaultProps.variables.length); - }); - - it('displays the correct variable options', async () => { - expect(findOptionsValues(0)).toBe('Protected, Expanded'); - expect(findOptionsValues(1)).toBe('Masked'); - }); - - it('enables the Add Variable button', () => { - expect(findAddButton().props('disabled')).toBe(false); - }); - }); - - describe('When variables have exceeded the max limit', () => { - beforeEach(() => { - createComponent({ props: { maxVariableLimit: mockVariables(projectString).length } }); - }); - - it('disables the Add Variable button', () => { - expect(findAddButton().props('disabled')).toBe(true); - }); - }); - - describe('max limit reached alert', () => { - describe('when there is no variable limit', () => { - beforeEach(() => { - createComponent({ - props: { maxVariableLimit: 0 }, - }); - }); - - it('hides alert', () => { - expect(findLimitReachedAlerts().length).toBe(0); - }); - }); - - describe('when variable limit exists', () => { - it('hides alert when limit has not been reached', () => { - createComponent(); - - expect(findLimitReachedAlerts().length).toBe(0); - }); - - it('shows alert when limit has been reached', () => { - const exceedsVariableLimitText = generateExceedsVariableLimitText( - defaultProps.entity, - defaultProps.variables.length, - mockMaxVariableLimit, - ); - - createComponent({ - props: { maxVariableLimit: mockMaxVariableLimit }, - }); - - expect(findLimitReachedAlerts().length).toBe(2); - - expect(findLimitReachedAlerts().at(0).props('dismissible')).toBe(false); - expect(findLimitReachedAlerts().at(0).text()).toContain(exceedsVariableLimitText); - - expect(findLimitReachedAlerts().at(1).props('dismissible')).toBe(false); - expect(findLimitReachedAlerts().at(1).text()).toContain(exceedsVariableLimitText); - }); - }); - }); - - describe('Table click actions', () => { - beforeEach(() => { - createComponent(); - }); - - it('reveals secret values when button is clicked', async () => { - expect(findHiddenValues()).toHaveLength(defaultProps.variables.length); - expect(findRevealedValues()).toHaveLength(0); - - await findRevealButton().trigger('click'); - - expect(findHiddenValues()).toHaveLength(0); - expect(findRevealedValues()).toHaveLength(defaultProps.variables.length); - }); - - it('dispatches `setSelectedVariable` with correct variable to edit', async () => { - await findEditButton().trigger('click'); - - expect(wrapper.emitted('set-selected-variable')).toEqual([[defaultProps.variables[0]]]); - }); - - it('dispatches `setSelectedVariable` with no variable when adding a new one', async () => { - await findAddButton().trigger('click'); - - expect(wrapper.emitted('set-selected-variable')).toEqual([[null]]); - }); - }); -}); diff --git a/spec/frontend/ci_variable_list/mocks.js b/spec/frontend/ci_variable_list/mocks.js deleted file mode 100644 index 065e9fa6667..00000000000 --- a/spec/frontend/ci_variable_list/mocks.js +++ /dev/null @@ -1,213 +0,0 @@ -import { - ADD_MUTATION_ACTION, - DELETE_MUTATION_ACTION, - UPDATE_MUTATION_ACTION, - variableTypes, - groupString, - instanceString, - projectString, -} from '~/ci_variable_list/constants'; - -import addAdminVariable from '~/ci_variable_list/graphql/mutations/admin_add_variable.mutation.graphql'; -import deleteAdminVariable from '~/ci_variable_list/graphql/mutations/admin_delete_variable.mutation.graphql'; -import updateAdminVariable from '~/ci_variable_list/graphql/mutations/admin_update_variable.mutation.graphql'; -import addGroupVariable from '~/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql'; -import deleteGroupVariable from '~/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql'; -import updateGroupVariable from '~/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql'; -import addProjectVariable from '~/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql'; -import deleteProjectVariable from '~/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql'; -import updateProjectVariable from '~/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql'; - -import getAdminVariables from '~/ci_variable_list/graphql/queries/variables.query.graphql'; -import getGroupVariables from '~/ci_variable_list/graphql/queries/group_variables.query.graphql'; -import getProjectEnvironments from '~/ci_variable_list/graphql/queries/project_environments.query.graphql'; -import getProjectVariables from '~/ci_variable_list/graphql/queries/project_variables.query.graphql'; - -export const devName = 'dev'; -export const prodName = 'prod'; - -export const mockVariables = (kind) => { - return [ - { - __typename: `Ci${kind}Variable`, - id: 1, - key: 'my-var', - masked: false, - protected: true, - raw: false, - value: 'variable_value', - variableType: variableTypes.envType, - }, - { - __typename: `Ci${kind}Variable`, - id: 2, - key: 'secret', - masked: true, - protected: false, - raw: true, - value: 'another_value', - variableType: variableTypes.fileType, - }, - ]; -}; - -export const mockVariablesWithScopes = (kind) => - mockVariables(kind).map((variable) => { - return { ...variable, environmentScope: '*' }; - }); - -const createDefaultVars = ({ withScope = true, kind } = {}) => { - let base = mockVariables(kind); - - if (withScope) { - base = mockVariablesWithScopes(kind); - } - - return { - __typename: `Ci${kind}VariableConnection`, - limit: 200, - pageInfo: { - startCursor: 'adsjsd12kldpsa', - endCursor: 'adsjsd12kldpsa', - hasPreviousPage: false, - hasNextPage: true, - }, - nodes: base, - }; -}; - -const defaultEnvs = { - __typename: 'EnvironmentConnection', - nodes: [ - { - __typename: 'Environment', - id: 1, - name: prodName, - }, - { - __typename: 'Environment', - id: 2, - name: devName, - }, - ], -}; - -export const mockEnvs = defaultEnvs.nodes; - -export const mockProjectEnvironments = { - data: { - project: { - __typename: 'Project', - id: 1, - environments: defaultEnvs, - }, - }, -}; - -export const mockProjectVariables = { - data: { - project: { - __typename: 'Project', - id: 1, - ciVariables: createDefaultVars({ kind: projectString }), - }, - }, -}; - -export const mockGroupVariables = { - data: { - group: { - __typename: 'Group', - id: 1, - ciVariables: createDefaultVars({ kind: groupString }), - }, - }, -}; - -export const mockAdminVariables = { - data: { - ciVariables: createDefaultVars({ withScope: false, kind: instanceString }), - }, -}; - -export const newVariable = { - id: 3, - environmentScope: 'new', - key: 'AWS_RANDOM_THING', - masked: true, - protected: false, - value: 'devops', - variableType: variableTypes.variableType, -}; - -export const createProjectProps = () => { - return { - componentName: 'ProjectVariable', - entity: 'project', - fullPath: '/namespace/project/', - id: 'gid://gitlab/Project/20', - mutationData: { - [ADD_MUTATION_ACTION]: addProjectVariable, - [UPDATE_MUTATION_ACTION]: updateProjectVariable, - [DELETE_MUTATION_ACTION]: deleteProjectVariable, - }, - queryData: { - ciVariables: { - lookup: (data) => data?.project?.ciVariables, - query: getProjectVariables, - }, - environments: { - lookup: (data) => data?.project?.environments, - query: getProjectEnvironments, - }, - }, - }; -}; - -export const createGroupProps = () => { - return { - componentName: 'GroupVariable', - entity: 'group', - fullPath: '/my-group', - id: 'gid://gitlab/Group/20', - mutationData: { - [ADD_MUTATION_ACTION]: addGroupVariable, - [UPDATE_MUTATION_ACTION]: updateGroupVariable, - [DELETE_MUTATION_ACTION]: deleteGroupVariable, - }, - queryData: { - ciVariables: { - lookup: (data) => data?.group?.ciVariables, - query: getGroupVariables, - }, - }, - }; -}; - -export const createInstanceProps = () => { - return { - componentName: 'InstanceVariable', - entity: '', - mutationData: { - [ADD_MUTATION_ACTION]: addAdminVariable, - [UPDATE_MUTATION_ACTION]: updateAdminVariable, - [DELETE_MUTATION_ACTION]: deleteAdminVariable, - }, - queryData: { - ciVariables: { - lookup: (data) => data?.ciVariables, - query: getAdminVariables, - }, - }, - }; -}; - -export const createGroupProvide = () => ({ - isGroup: true, - isProject: false, -}); - -export const createProjectProvide = () => ({ - isGroup: false, - isProject: true, -}); diff --git a/spec/frontend/ci_variable_list/services/mock_data.js b/spec/frontend/ci_variable_list/services/mock_data.js deleted file mode 100644 index 44f4db93c63..00000000000 --- a/spec/frontend/ci_variable_list/services/mock_data.js +++ /dev/null @@ -1,156 +0,0 @@ -export default { - mockVariables: [ - { - environment_scope: 'All (default)', - id: 113, - key: 'test_var', - masked: false, - protected: false, - secret_value: 'test_val', - value: 'test_val', - variable_type: 'Variable', - }, - ], - - mockVariablesApi: [ - { - environment_scope: '*', - id: 113, - key: 'test_var', - masked: false, - protected: false, - secret_value: 'test_val', - value: 'test_val', - variable_type: 'env_var', - }, - { - environment_scope: '*', - id: 114, - key: 'test_var_2', - masked: false, - protected: false, - secret_value: 'test_val_2', - value: 'test_val_2', - variable_type: 'file', - }, - ], - - mockVariablesDisplay: [ - { - environment_scope: 'All (default)', - id: 113, - key: 'test_var', - masked: false, - protected: false, - protected_variable: false, - secret_value: 'test_val', - value: 'test_val', - variable_type: 'Variable', - }, - { - environment_scope: 'All (default)', - id: 114, - key: 'test_var_2', - masked: false, - protected: false, - protected_variable: false, - secret_value: 'test_val_2', - value: 'test_val_2', - variable_type: 'File', - }, - ], - - mockEnvironments: [ - { - id: 28, - name: 'staging', - slug: 'staging', - external_url: 'https://staging.example.com', - state: 'available', - }, - { - id: 29, - name: 'production', - slug: 'production', - external_url: 'https://production.example.com', - state: 'available', - }, - ], - - mockPemCert: `-----BEGIN CERTIFICATE REQUEST----- - MIIB9TCCAWACAQAwgbgxGTAXBgNVBAoMEFF1b1ZhZGlzIExpbWl0ZWQxHDAaBgNV - BAsME0RvY3VtZW50IERlcGFydG1lbnQxOTA3BgNVBAMMMFdoeSBhcmUgeW91IGRl - Y29kaW5nIG1lPyAgVGhpcyBpcyBvbmx5IGEgdGVzdCEhITERMA8GA1UEBwwISGFt - aWx0b24xETAPBgNVBAgMCFBlbWJyb2tlMQswCQYDVQQGEwJCTTEPMA0GCSqGSIb3 - DQEJARYAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ9WRanG/fUvcfKiGl - EL4aRLjGt537mZ28UU9/3eiJeJznNSOuNLnF+hmabAu7H0LT4K7EdqfF+XUZW/2j - RKRYcvOUDGF9A7OjW7UfKk1In3+6QDCi7X34RE161jqoaJjrm/T18TOKcgkkhRzE - apQnIDm0Ea/HVzX/PiSOGuertwIDAQABMAsGCSqGSIb3DQEBBQOBgQBzMJdAV4QP - Awel8LzGx5uMOshezF/KfP67wJ93UW+N7zXY6AwPgoLj4Kjw+WtU684JL8Dtr9FX - ozakE+8p06BpxegR4BR3FMHf6p+0jQxUEAkAyb/mVgm66TyghDGC6/YkiKoZptXQ - 98TwDIK/39WEB/V607As+KoYazQG8drorw== - -----END CERTIFICATE REQUEST-----`, - - mockVariableScopes: [ - { - id: 13, - key: 'test_var_1', - value: 'test_val_1', - variable_type: 'File', - protected: true, - masked: true, - environment_scope: 'All (default)', - secret_value: 'test_val_1', - }, - { - id: 28, - key: 'goku_var', - value: 'goku_val', - variable_type: 'Variable', - protected: true, - masked: true, - environment_scope: 'staging', - secret_value: 'goku_val', - }, - { - id: 25, - key: 'test_var_4', - value: 'test_val_4', - variable_type: 'Variable', - protected: false, - masked: false, - environment_scope: 'production', - secret_value: 'test_val_4', - }, - { - id: 14, - key: 'test_var_2', - value: 'test_val_2', - variable_type: 'File', - protected: false, - masked: false, - environment_scope: 'staging', - secret_value: 'test_val_2', - }, - { - id: 24, - key: 'test_var_3', - value: 'test_val_3', - variable_type: 'Variable', - protected: false, - masked: false, - environment_scope: 'All (default)', - secret_value: 'test_val_3', - }, - { - id: 26, - key: 'test_var_5', - value: 'test_val_5', - variable_type: 'Variable', - protected: false, - masked: false, - environment_scope: 'production', - secret_value: 'test_val_5', - }, - ], -}; diff --git a/spec/frontend/ci_variable_list/stubs.js b/spec/frontend/ci_variable_list/stubs.js deleted file mode 100644 index 5769d6190f6..00000000000 --- a/spec/frontend/ci_variable_list/stubs.js +++ /dev/null @@ -1,14 +0,0 @@ -const ModalStub = { - name: 'glmodal-stub', - template: ` - <div> - <slot></slot> - <slot name="modal-footer"></slot> - </div> - `, - methods: { - hide: jest.fn(), - }, -}; - -export default ModalStub; diff --git a/spec/frontend/ci_variable_list/utils_spec.js b/spec/frontend/ci_variable_list/utils_spec.js deleted file mode 100644 index 081c399792f..00000000000 --- a/spec/frontend/ci_variable_list/utils_spec.js +++ /dev/null @@ -1,78 +0,0 @@ -import { - createJoinedEnvironments, - convertEnvironmentScope, - mapEnvironmentNames, -} from '~/ci_variable_list/utils'; -import { allEnvironments } from '~/ci_variable_list/constants'; - -describe('utils', () => { - const environments = ['dev', 'prod']; - const newEnvironments = ['staging']; - - describe('createJoinedEnvironments', () => { - it('returns only `environments` if `variables` argument is undefined', () => { - const variables = undefined; - - expect(createJoinedEnvironments(variables, environments, [])).toEqual(environments); - }); - - it('returns a list of environments and environment scopes taken from variables in alphabetical order', () => { - const envScope1 = 'new1'; - const envScope2 = 'new2'; - - const variables = [{ environmentScope: envScope1 }, { environmentScope: envScope2 }]; - - expect(createJoinedEnvironments(variables, environments, [])).toEqual([ - environments[0], - envScope1, - envScope2, - environments[1], - ]); - }); - - it('returns combined list with new environments included', () => { - const variables = undefined; - - expect(createJoinedEnvironments(variables, environments, newEnvironments)).toEqual([ - ...environments, - ...newEnvironments, - ]); - }); - - it('removes duplicate environments', () => { - const envScope1 = environments[0]; - const envScope2 = 'new2'; - - const variables = [{ environmentScope: envScope1 }, { environmentScope: envScope2 }]; - - expect(createJoinedEnvironments(variables, environments, [])).toEqual([ - environments[0], - envScope2, - environments[1], - ]); - }); - }); - - describe('convertEnvironmentScope', () => { - it('converts the * to the `All environments` text', () => { - expect(convertEnvironmentScope('*')).toBe(allEnvironments.text); - }); - - it('returns the environment as is if not the *', () => { - expect(convertEnvironmentScope('prod')).toBe('prod'); - }); - }); - - describe('mapEnvironmentNames', () => { - const envName = 'dev'; - const envName2 = 'prod'; - - const nodes = [ - { name: envName, otherProp: {} }, - { name: envName2, otherProp: {} }, - ]; - it('flatten a nodes array with only their names', () => { - expect(mapEnvironmentNames(nodes)).toEqual([envName, envName2]); - }); - }); -}); |