diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-03 21:08:58 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-03 21:08:58 +0300 |
commit | 7c8468c5ba828e1c1afe6ba0b25c77c130a69413 (patch) | |
tree | 3104d62bff9040a19756b9d407003eed14314f77 /spec/frontend | |
parent | 2a7fd3827b0838a900399b0c3440942cdaa09c75 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
7 files changed, 220 insertions, 40 deletions
diff --git a/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/rules_item_spec.js b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/rules_item_spec.js new file mode 100644 index 00000000000..659ccb25996 --- /dev/null +++ b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/rules_item_spec.js @@ -0,0 +1,70 @@ +import RulesItem from '~/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/rules_item.vue'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { + JOB_TEMPLATE, + JOB_RULES_WHEN, + JOB_RULES_START_IN, +} from '~/ci/pipeline_editor/components/job_assistant_drawer/constants'; + +describe('Rules item', () => { + let wrapper; + + const findRulesWhenSelect = () => wrapper.findByTestId('rules-when-select'); + const findRulesStartInNumberInput = () => wrapper.findByTestId('rules-start-in-number-input'); + const findRulesStartInUnitSelect = () => wrapper.findByTestId('rules-start-in-unit-select'); + const findRulesAllowFailureCheckBox = () => wrapper.findByTestId('rules-allow-failure-checkbox'); + + const dummyRulesWhen = JOB_RULES_WHEN.delayed.value; + const dummyRulesStartInNumber = 2; + const dummyRulesStartInUnit = JOB_RULES_START_IN.week.value; + const dummyRulesAllowFailure = true; + + const createComponent = () => { + wrapper = shallowMountExtended(RulesItem, { + propsData: { + isStartValid: true, + job: JSON.parse(JSON.stringify(JOB_TEMPLATE)), + }, + }); + }; + + beforeEach(() => { + createComponent(); + }); + + it('should emit update job event when filling inputs', () => { + expect(wrapper.emitted('update-job')).toBeUndefined(); + + findRulesWhenSelect().vm.$emit('input', dummyRulesWhen); + + expect(wrapper.emitted('update-job')).toHaveLength(1); + expect(wrapper.emitted('update-job')[0]).toEqual([ + 'rules[0].when', + JOB_RULES_WHEN.delayed.value, + ]); + + findRulesStartInNumberInput().vm.$emit('input', dummyRulesStartInNumber); + + expect(wrapper.emitted('update-job')).toHaveLength(2); + expect(wrapper.emitted('update-job')[1]).toEqual([ + 'rules[0].start_in', + `2 ${JOB_RULES_START_IN.second.value}s`, + ]); + + findRulesStartInUnitSelect().vm.$emit('input', dummyRulesStartInUnit); + + expect(wrapper.emitted('update-job')).toHaveLength(3); + expect(wrapper.emitted('update-job')[2]).toEqual([ + 'rules[0].start_in', + `2 ${dummyRulesStartInUnit}s`, + ]); + + findRulesAllowFailureCheckBox().vm.$emit('input', dummyRulesAllowFailure); + + expect(wrapper.emitted('update-job')).toHaveLength(4); + expect(wrapper.emitted('update-job')[3]).toEqual([ + 'rules[0].allow_failure', + dummyRulesAllowFailure, + ]); + }); +}); diff --git a/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer_spec.js b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer_spec.js index 356de5b11e9..e03cd19da65 100644 --- a/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer_spec.js +++ b/spec/frontend/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer_spec.js @@ -5,6 +5,8 @@ import { stringify } from 'yaml'; import JobAssistantDrawer from '~/ci/pipeline_editor/components/job_assistant_drawer/job_assistant_drawer.vue'; import JobSetupItem from '~/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/job_setup_item.vue'; import ImageItem from '~/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/image_item.vue'; +import RulesItem from '~/ci/pipeline_editor/components/job_assistant_drawer/accordion_items/rules_item.vue'; +import { JOB_RULES_WHEN } from '~/ci/pipeline_editor/components/job_assistant_drawer/constants'; import getRunnerTags from '~/ci/pipeline_editor/graphql/queries/runner_tags.query.graphql'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; @@ -23,10 +25,14 @@ describe('Job assistant drawer', () => { const dummyJobScript = 'b'; const dummyImageName = 'c'; const dummyImageEntrypoint = 'd'; + const dummyRulesWhen = JOB_RULES_WHEN.delayed.value; + const dummyRulesStartIn = '1 second'; + const dummyRulesAllowFailure = true; const findDrawer = () => wrapper.findComponent(GlDrawer); const findJobSetupItem = () => wrapper.findComponent(JobSetupItem); const findImageItem = () => wrapper.findComponent(ImageItem); + const findRulesItem = () => wrapper.findComponent(RulesItem); const findConfirmButton = () => wrapper.findByTestId('confirm-button'); const findCancelButton = () => wrapper.findByTestId('cancel-button'); @@ -68,6 +74,10 @@ describe('Job assistant drawer', () => { expect(findImageItem().exists()).toBe(true); }); + it('should contain rules accordion', () => { + expect(findRulesItem().exists()).toBe(true); + }); + it('should emit close job assistant drawer event when closing the drawer', () => { expect(wrapper.emitted('close-job-assistant-drawer')).toBeUndefined(); @@ -84,7 +94,7 @@ describe('Job assistant drawer', () => { expect(wrapper.emitted('close-job-assistant-drawer')).toHaveLength(1); }); - it('trigger validate if job name is empty', async () => { + it('should block submit if job name is empty', async () => { findJobSetupItem().vm.$emit('update-job', 'script', 'b'); findConfirmButton().trigger('click'); @@ -95,12 +105,25 @@ describe('Job assistant drawer', () => { expect(wrapper.emitted('updateCiConfig')).toBeUndefined(); }); + it('should block submit if rules when is delayed and start in is out of range', async () => { + findRulesItem().vm.$emit('update-job', 'rules[0].when', JOB_RULES_WHEN.delayed.value); + findRulesItem().vm.$emit('update-job', 'rules[0].start_in', '2 weeks'); + findConfirmButton().trigger('click'); + + await nextTick(); + + expect(wrapper.emitted('updateCiConfig')).toBeUndefined(); + }); + describe('when enter valid input', () => { beforeEach(() => { findJobSetupItem().vm.$emit('update-job', 'name', dummyJobName); findJobSetupItem().vm.$emit('update-job', 'script', dummyJobScript); findImageItem().vm.$emit('update-job', 'image.name', dummyImageName); findImageItem().vm.$emit('update-job', 'image.entrypoint', [dummyImageEntrypoint]); + findRulesItem().vm.$emit('update-job', 'rules[0].allow_failure', dummyRulesAllowFailure); + findRulesItem().vm.$emit('update-job', 'rules[0].when', dummyRulesWhen); + findRulesItem().vm.$emit('update-job', 'rules[0].start_in', dummyRulesStartIn); }); it('passes correct prop to accordions', () => { @@ -113,6 +136,13 @@ describe('Job assistant drawer', () => { name: dummyImageName, entrypoint: [dummyImageEntrypoint], }, + rules: [ + { + allow_failure: dummyRulesAllowFailure, + when: dummyRulesWhen, + start_in: dummyRulesStartIn, + }, + ], }); }); }); @@ -138,6 +168,24 @@ describe('Job assistant drawer', () => { expect(findJobSetupItem().props('job')).toMatchObject({ name: '', script: '' }); }); + it('should omit keys with default value when click add button', () => { + findRulesItem().vm.$emit('update-job', 'rules[0].allow_failure', false); + findRulesItem().vm.$emit('update-job', 'rules[0].when', JOB_RULES_WHEN.onSuccess.value); + findRulesItem().vm.$emit('update-job', 'rules[0].start_in', dummyRulesStartIn); + findConfirmButton().trigger('click'); + + expect(wrapper.emitted('updateCiConfig')).toStrictEqual([ + [ + `${wrapper.props('ciFileContent')}\n${stringify({ + [dummyJobName]: { + script: dummyJobScript, + image: { name: dummyImageName, entrypoint: [dummyImageEntrypoint] }, + }, + })}`, + ], + ]); + }); + it('should update correct ci content when click add button', () => { findConfirmButton().trigger('click'); @@ -147,6 +195,13 @@ describe('Job assistant drawer', () => { [dummyJobName]: { script: dummyJobScript, image: { name: dummyImageName, entrypoint: [dummyImageEntrypoint] }, + rules: [ + { + allow_failure: dummyRulesAllowFailure, + when: dummyRulesWhen, + start_in: dummyRulesStartIn, + }, + ], }, })}`, ], diff --git a/spec/frontend/fixtures/projects.rb b/spec/frontend/fixtures/projects.rb index 2ccf2c0392f..8cd651c5b36 100644 --- a/spec/frontend/fixtures/projects.rb +++ b/spec/frontend/fixtures/projects.rb @@ -67,7 +67,7 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller do end end - describe 'Storage', feature_category: :subscription_cost_management do + describe 'Storage', feature_category: :consumables_cost_management do describe GraphQL::Query, type: :request do include GraphqlHelpers context 'project storage statistics query' do diff --git a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js index 60bb055b1db..6cfc80966b5 100644 --- a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js @@ -1,9 +1,11 @@ -import { GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui'; +import { GlButton, GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui'; import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import { s__ } from '~/locale'; import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants'; import ListPage from '~/packages_and_registries/package_registry/pages/list.vue'; import PackageTitle from '~/packages_and_registries/package_registry/components/list/package_title.vue'; @@ -30,6 +32,7 @@ describe('PackagesListApp', () => { emptyListIllustration: 'emptyListIllustration', isGroupPage: true, fullPath: 'gitlab-org', + settingsPath: 'settings-path', }; const PackageList = { @@ -49,6 +52,7 @@ describe('PackagesListApp', () => { const findListComponent = () => wrapper.findComponent(PackageList); const findEmptyState = () => wrapper.findComponent(GlEmptyState); const findDeletePackages = () => wrapper.findComponent(DeletePackages); + const findSettingsLink = () => wrapper.findComponent(GlButton); const mountComponent = ({ resolver = jest.fn().mockResolvedValue(packagesListQuery()), @@ -71,9 +75,13 @@ describe('PackagesListApp', () => { GlLoadingIcon, GlSprintf, GlLink, + PackageTitle, PackageList, DeletePackages, }, + directives: { + GlTooltip: createMockDirective('gl-tooltip'), + }, }); }; @@ -103,6 +111,52 @@ describe('PackagesListApp', () => { }); }); + describe('link to settings', () => { + describe('when settings path is not provided', () => { + beforeEach(() => { + mountComponent({ + provide: { + ...defaultProvide, + settingsPath: '', + }, + }); + }); + + it('is not rendered', () => { + expect(findSettingsLink().exists()).toBe(false); + }); + }); + + describe('when settings path is provided', () => { + const label = s__('PackageRegistry|Configure in settings'); + + beforeEach(() => { + mountComponent(); + }); + + it('is rendered', () => { + expect(findSettingsLink().exists()).toBe(true); + }); + + it('has the right icon', () => { + expect(findSettingsLink().props('icon')).toBe('settings'); + }); + + it('has the right attributes', () => { + expect(findSettingsLink().attributes()).toMatchObject({ + 'aria-label': label, + href: defaultProvide.settingsPath, + }); + }); + + it('sets tooltip with right label', () => { + const tooltip = getBinding(findSettingsLink().element, 'gl-tooltip'); + + expect(tooltip.value).toBe(label); + }); + }); + }); + describe('search component', () => { it('exists', () => { mountComponent(); diff --git a/spec/frontend/projects/commit/components/branches_dropdown_spec.js b/spec/frontend/projects/commit/components/branches_dropdown_spec.js index 0e68bd21cd4..5210abe154d 100644 --- a/spec/frontend/projects/commit/components/branches_dropdown_spec.js +++ b/spec/frontend/projects/commit/components/branches_dropdown_spec.js @@ -68,13 +68,11 @@ describe('BranchesDropdown', () => { describe('When searching', () => { it('invokes fetchBranches', async () => { - const spy = jest.spyOn(wrapper.vm, 'fetchBranches'); - findDropdown().vm.$emit('search', '_anything_'); await nextTick(); - expect(spy).toHaveBeenCalledWith('_anything_'); + expect(spyFetchBranches).toHaveBeenCalledWith(expect.any(Object), '_anything_'); }); }); }); diff --git a/spec/frontend/sidebar/components/subscriptions/subscriptions_spec.js b/spec/frontend/sidebar/components/subscriptions/subscriptions_spec.js index cae21189ee0..b644b7a9421 100644 --- a/spec/frontend/sidebar/components/subscriptions/subscriptions_spec.js +++ b/spec/frontend/sidebar/components/subscriptions/subscriptions_spec.js @@ -1,23 +1,24 @@ import { GlToggle } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { mockTracking } from 'helpers/tracking_helper'; import Subscriptions from '~/sidebar/components/subscriptions/subscriptions.vue'; import eventHub from '~/sidebar/event_hub'; describe('Subscriptions', () => { let wrapper; + let trackingSpy; const findToggleButton = () => wrapper.findComponent(GlToggle); + const findTooltip = () => wrapper.findComponent({ ref: 'tooltip' }); - const mountComponent = (propsData) => - extendedWrapper( - shallowMount(Subscriptions, { - propsData, - }), - ); + const mountComponent = (propsData) => { + wrapper = shallowMountExtended(Subscriptions, { + propsData, + }); + }; it('shows loading spinner when loading', () => { - wrapper = mountComponent({ + mountComponent({ loading: true, subscribed: undefined, }); @@ -26,7 +27,7 @@ describe('Subscriptions', () => { }); it('is toggled "off" when currently not subscribed', () => { - wrapper = mountComponent({ + mountComponent({ subscribed: false, }); @@ -34,7 +35,7 @@ describe('Subscriptions', () => { }); it('is toggled "on" when currently subscribed', () => { - wrapper = mountComponent({ + mountComponent({ subscribed: true, }); @@ -43,44 +44,38 @@ describe('Subscriptions', () => { it('toggleSubscription method emits `toggleSubscription` event on eventHub and Component', () => { const id = 42; - wrapper = mountComponent({ subscribed: true, id }); + mountComponent({ subscribed: true, id }); const eventHubSpy = jest.spyOn(eventHub, '$emit'); - const wrapperEmitSpy = jest.spyOn(wrapper.vm, '$emit'); - wrapper.vm.toggleSubscription(); + findToggleButton().vm.$emit('change'); expect(eventHubSpy).toHaveBeenCalledWith('toggleSubscription', id); - expect(wrapperEmitSpy).toHaveBeenCalledWith('toggleSubscription', id); - eventHubSpy.mockRestore(); - wrapperEmitSpy.mockRestore(); + expect(wrapper.emitted('toggleSubscription')).toEqual([[id]]); }); it('tracks the event when toggled', () => { - wrapper = mountComponent({ subscribed: true }); - - const wrapperTrackSpy = jest.spyOn(wrapper.vm, 'track'); + trackingSpy = mockTracking('_category_', undefined, jest.spyOn); + mountComponent({ subscribed: true }); - wrapper.vm.toggleSubscription(); + findToggleButton().vm.$emit('change'); - expect(wrapperTrackSpy).toHaveBeenCalledWith('toggle_button', { + expect(trackingSpy).toHaveBeenCalledWith(undefined, 'toggle_button', { + category: undefined, + label: 'right_sidebar', property: 'notifications', value: 0, }); - wrapperTrackSpy.mockRestore(); }); it('onClickCollapsedIcon method emits `toggleSidebar` event on component', () => { - wrapper = mountComponent({ subscribed: true }); - const spy = jest.spyOn(wrapper.vm, '$emit'); - - wrapper.vm.onClickCollapsedIcon(); + mountComponent({ subscribed: true }); + findTooltip().trigger('click'); - expect(spy).toHaveBeenCalledWith('toggleSidebar'); - spy.mockRestore(); + expect(wrapper.emitted('toggleSidebar')).toHaveLength(1); }); it('has visually hidden label', () => { - wrapper = mountComponent(); + mountComponent(); expect(findToggleButton().props()).toMatchObject({ label: 'Notifications', @@ -92,7 +87,7 @@ describe('Subscriptions', () => { const subscribeDisabledDescription = 'Notifications have been disabled'; beforeEach(() => { - wrapper = mountComponent({ + mountComponent({ subscribed: false, projectEmailsDisabled: true, subscribeDisabledDescription, @@ -103,9 +98,7 @@ describe('Subscriptions', () => { expect(wrapper.findByTestId('subscription-title').text()).toContain( subscribeDisabledDescription, ); - expect(wrapper.findComponent({ ref: 'tooltip' }).attributes('title')).toBe( - subscribeDisabledDescription, - ); + expect(findTooltip().attributes('title')).toBe(subscribeDisabledDescription); }); it('does not render the toggle button', () => { diff --git a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js index 7bda37bcaa8..3964d895b4b 100644 --- a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js +++ b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js @@ -346,6 +346,16 @@ describe('vue_shared/component/markdown/markdown_editor', () => { }); }); + describe('when contentEditor is disabled', () => { + it('resets the editingMode to markdownField', async () => { + localStorage.setItem('gl-markdown-editor-mode', 'contentEditor'); + + buildWrapper({ propsData: { autosaveKey: 'issue/1234', enableContentEditor: false } }); + + expect(wrapper.vm.editingMode).toBe(EDITING_MODE_MARKDOWN_FIELD); + }); + }); + describe(`when editingMode is ${EDITING_MODE_CONTENT_EDITOR}`, () => { beforeEach(async () => { buildWrapper({ propsData: { autosaveKey: 'issue/1234' } }); |