From 311b0269b4eb9839fa63f80c8d7a58f32b8138a0 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 18 Nov 2021 13:16:36 +0000 Subject: Add latest changes from gitlab-org/gitlab@14-5-stable-ee --- .../components/commit/commit_form_spec.js | 19 +++ .../components/commit/commit_section_spec.js | 16 ++- .../drawer/pipeline_editor_drawer_spec.js | 37 ++++-- .../components/file-nav/branch_switcher_spec.js | 38 ++++-- .../components/header/pipeline_status_spec.js | 39 +++--- .../header/pipline_editor_mini_graph_spec.js | 72 ++++++++++- .../components/pipeline_editor_tabs_spec.js | 132 ++++++++++++++++++++- .../components/ui/pipeline_editor_messages_spec.js | 2 + .../components/walkthrough_popover_spec.js | 29 +++++ 9 files changed, 341 insertions(+), 43 deletions(-) create mode 100644 spec/frontend/pipeline_editor/components/walkthrough_popover_spec.js (limited to 'spec/frontend/pipeline_editor/components') diff --git a/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js b/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js index 8040c9d701c..23219042008 100644 --- a/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js +++ b/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js @@ -5,6 +5,9 @@ import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue'; import { mockCommitMessage, mockDefaultBranch } from '../../mock_data'; +const scrollIntoViewMock = jest.fn(); +HTMLElement.prototype.scrollIntoView = scrollIntoViewMock; + describe('Pipeline Editor | Commit Form', () => { let wrapper; @@ -113,4 +116,20 @@ describe('Pipeline Editor | Commit Form', () => { expect(findSubmitBtn().attributes('disabled')).toBe('disabled'); }); }); + + describe('when scrollToCommitForm becomes true', () => { + beforeEach(async () => { + createComponent(); + wrapper.setProps({ scrollToCommitForm: true }); + await wrapper.vm.$nextTick(); + }); + + it('scrolls into view', () => { + expect(scrollIntoViewMock).toHaveBeenCalledWith({ behavior: 'smooth' }); + }); + + it('emits "scrolled-to-commit-form"', () => { + expect(wrapper.emitted()['scrolled-to-commit-form']).toBeTruthy(); + }); + }); }); diff --git a/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js b/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js index 2f934898ef1..efc345d8877 100644 --- a/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js +++ b/spec/frontend/pipeline_editor/components/commit/commit_section_spec.js @@ -52,6 +52,7 @@ describe('Pipeline Editor | Commit section', () => { const defaultProps = { ciFileContent: mockCiYml, commitSha: mockCommitSha, + isNewCiConfigFile: false, }; const createComponent = ({ props = {}, options = {}, provide = {} } = {}) => { @@ -72,7 +73,6 @@ describe('Pipeline Editor | Commit section', () => { data() { return { currentBranch: mockDefaultBranch, - isNewCiConfigFile: Boolean(options?.isNewCiConfigfile), }; }, mocks: { @@ -115,7 +115,7 @@ describe('Pipeline Editor | Commit section', () => { describe('when the user commits a new file', () => { beforeEach(async () => { - createComponent({ options: { isNewCiConfigfile: true } }); + createComponent({ props: { isNewCiConfigFile: true } }); await submitCommit(); }); @@ -277,4 +277,16 @@ describe('Pipeline Editor | Commit section', () => { expect(wrapper.emitted('resetContent')).toHaveLength(1); }); }); + + it('sets listeners on commit form', () => { + const handler = jest.fn(); + createComponent({ options: { listeners: { event: handler } } }); + findCommitForm().vm.$emit('event'); + expect(handler).toHaveBeenCalled(); + }); + + it('passes down scroll-to-commit-form prop to commit form', () => { + createComponent({ props: { 'scroll-to-commit-form': true } }); + expect(findCommitForm().props('scrollToCommitForm')).toBe(true); + }); }); diff --git a/spec/frontend/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js b/spec/frontend/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js index 1b68cd3dc43..4df7768b035 100644 --- a/spec/frontend/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js +++ b/spec/frontend/pipeline_editor/components/drawer/pipeline_editor_drawer_spec.js @@ -1,6 +1,7 @@ import { GlButton } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import { nextTick } from 'vue'; +import { stubExperiments } from 'helpers/experimentation_helper'; import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import FirstPipelineCard from '~/pipeline_editor/components/drawer/cards/first_pipeline_card.vue'; import GettingStartedCard from '~/pipeline_editor/components/drawer/cards/getting_started_card.vue'; @@ -33,19 +34,41 @@ describe('Pipeline editor drawer', () => { const clickToggleBtn = async () => findToggleBtn().vm.$emit('click'); + const originalObjects = []; + + beforeEach(() => { + originalObjects.push(window.gon, window.gl); + stubExperiments({ pipeline_editor_walkthrough: 'control' }); + }); + afterEach(() => { wrapper.destroy(); localStorage.clear(); + [window.gon, window.gl] = originalObjects; }); - it('it sets the drawer to be opened by default', async () => { - createComponent(); - - expect(findDrawerContent().exists()).toBe(false); - - await nextTick(); + describe('default expanded state', () => { + describe('when experiment control', () => { + it('sets the drawer to be opened by default', async () => { + createComponent(); + expect(findDrawerContent().exists()).toBe(false); + await nextTick(); + expect(findDrawerContent().exists()).toBe(true); + }); + }); - expect(findDrawerContent().exists()).toBe(true); + describe('when experiment candidate', () => { + beforeEach(() => { + stubExperiments({ pipeline_editor_walkthrough: 'candidate' }); + }); + + it('sets the drawer to be closed by default', async () => { + createComponent(); + expect(findDrawerContent().exists()).toBe(false); + await nextTick(); + expect(findDrawerContent().exists()).toBe(false); + }); + }); }); describe('when the drawer is collapsed', () => { diff --git a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js b/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js index b5881790b0b..6532c4e289d 100644 --- a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js +++ b/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js @@ -36,8 +36,9 @@ describe('Pipeline editor branch switcher', () => { let mockLastCommitBranchQuery; const createComponent = ( - { currentBranch, isQueryLoading, mountFn, options } = { + { currentBranch, isQueryLoading, mountFn, options, props } = { currentBranch: mockDefaultBranch, + hasUnsavedChanges: false, isQueryLoading: false, mountFn: shallowMount, options: {}, @@ -45,6 +46,7 @@ describe('Pipeline editor branch switcher', () => { ) => { wrapper = mountFn(BranchSwitcher, { propsData: { + ...props, paginationLimit: mockBranchPaginationLimit, }, provide: { @@ -70,7 +72,7 @@ describe('Pipeline editor branch switcher', () => { }); }; - const createComponentWithApollo = (mountFn = shallowMount) => { + const createComponentWithApollo = ({ mountFn = shallowMount, props = {} } = {}) => { const handlers = [[getAvailableBranchesQuery, mockAvailableBranchQuery]]; const resolvers = { Query: { @@ -86,6 +88,7 @@ describe('Pipeline editor branch switcher', () => { createComponent({ mountFn, + props, options: { localVue, apolloProvider: mockApollo, @@ -138,8 +141,8 @@ describe('Pipeline editor branch switcher', () => { createComponentWithApollo(); }); - it('does not render dropdown', () => { - expect(findDropdown().exists()).toBe(false); + it('disables the dropdown', () => { + expect(findDropdown().props('disabled')).toBe(true); }); }); @@ -149,7 +152,7 @@ describe('Pipeline editor branch switcher', () => { availableBranches: mockProjectBranches, currentBranch: mockDefaultBranch, }); - createComponentWithApollo(mount); + createComponentWithApollo({ mountFn: mount }); await waitForPromises(); }); @@ -186,7 +189,7 @@ describe('Pipeline editor branch switcher', () => { }); it('does not render dropdown', () => { - expect(findDropdown().exists()).toBe(false); + expect(findDropdown().props('disabled')).toBe(true); }); it('shows an error message', () => { @@ -201,7 +204,7 @@ describe('Pipeline editor branch switcher', () => { availableBranches: mockProjectBranches, currentBranch: mockDefaultBranch, }); - createComponentWithApollo(mount); + createComponentWithApollo({ mountFn: mount }); await waitForPromises(); }); @@ -247,6 +250,23 @@ describe('Pipeline editor branch switcher', () => { expect(wrapper.emitted('refetchContent')).toBeUndefined(); }); + + describe('with unsaved changes', () => { + beforeEach(async () => { + createComponentWithApollo({ mountFn: mount, props: { hasUnsavedChanges: true } }); + await waitForPromises(); + }); + + it('emits `select-branch` event and does not switch branch', async () => { + expect(wrapper.emitted('select-branch')).toBeUndefined(); + + const branch = findDropdownItems().at(1); + await branch.vm.$emit('click'); + + expect(wrapper.emitted('select-branch')).toEqual([[branch.text()]]); + expect(wrapper.emitted('refetchContent')).toBeUndefined(); + }); + }); }); describe('when searching', () => { @@ -255,7 +275,7 @@ describe('Pipeline editor branch switcher', () => { availableBranches: mockProjectBranches, currentBranch: mockDefaultBranch, }); - createComponentWithApollo(mount); + createComponentWithApollo({ mountFn: mount }); await waitForPromises(); }); @@ -429,7 +449,7 @@ describe('Pipeline editor branch switcher', () => { availableBranches: mockProjectBranches, currentBranch: mockDefaultBranch, }); - createComponentWithApollo(mount); + createComponentWithApollo({ mountFn: mount }); await waitForPromises(); await createNewBranch(); }); diff --git a/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js b/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js index 44656b2b67d..29ab52bde8f 100644 --- a/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js +++ b/spec/frontend/pipeline_editor/components/header/pipeline_status_spec.js @@ -16,7 +16,7 @@ describe('Pipeline Status', () => { let mockApollo; let mockPipelineQuery; - const createComponentWithApollo = (glFeatures = {}) => { + const createComponentWithApollo = () => { const handlers = [[getPipelineQuery, mockPipelineQuery]]; mockApollo = createMockApollo(handlers); @@ -27,7 +27,6 @@ describe('Pipeline Status', () => { commitSha: mockCommitSha, }, provide: { - glFeatures, projectFullPath: mockProjectFullPath, }, stubs: { GlLink, GlSprintf }, @@ -40,6 +39,8 @@ describe('Pipeline Status', () => { const findPipelineId = () => wrapper.find('[data-testid="pipeline-id"]'); const findPipelineCommit = () => wrapper.find('[data-testid="pipeline-commit"]'); const findPipelineErrorMsg = () => wrapper.find('[data-testid="pipeline-error-msg"]'); + const findPipelineNotTriggeredErrorMsg = () => + wrapper.find('[data-testid="pipeline-not-triggered-error-msg"]'); const findPipelineLoadingMsg = () => wrapper.find('[data-testid="pipeline-loading-msg"]'); const findPipelineViewBtn = () => wrapper.find('[data-testid="pipeline-view-btn"]'); const findStatusIcon = () => wrapper.find('[data-testid="pipeline-status-icon"]'); @@ -95,17 +96,18 @@ describe('Pipeline Status', () => { it('renders pipeline data', () => { const { id, + commit: { title }, detailedStatus: { detailsPath }, } = mockProjectPipeline().pipeline; expect(findStatusIcon().exists()).toBe(true); expect(findPipelineId().text()).toBe(`#${id.match(/\d+/g)[0]}`); - expect(findPipelineCommit().text()).toBe(mockCommitSha); + expect(findPipelineCommit().text()).toBe(`${mockCommitSha}: ${title}`); expect(findPipelineViewBtn().attributes('href')).toBe(detailsPath); }); - it('does not render the pipeline mini graph', () => { - expect(findPipelineEditorMiniGraph().exists()).toBe(false); + it('renders the pipeline mini graph', () => { + expect(findPipelineEditorMiniGraph().exists()).toBe(true); }); }); @@ -117,7 +119,8 @@ describe('Pipeline Status', () => { await waitForPromises(); }); - it('renders error', () => { + it('renders api error', () => { + expect(findPipelineNotTriggeredErrorMsg().exists()).toBe(false); expect(findIcon().attributes('name')).toBe('warning-solid'); expect(findPipelineErrorMsg().text()).toBe(i18n.fetchError); }); @@ -129,20 +132,22 @@ describe('Pipeline Status', () => { expect(findPipelineViewBtn().exists()).toBe(false); }); }); - }); - describe('when feature flag for pipeline mini graph is enabled', () => { - beforeEach(() => { - mockPipelineQuery.mockResolvedValue({ - data: { project: mockProjectPipeline() }, - }); + describe('when pipeline is null', () => { + beforeEach(() => { + mockPipelineQuery.mockResolvedValue({ + data: { project: { pipeline: null } }, + }); - createComponentWithApollo({ pipelineEditorMiniGraph: true }); - waitForPromises(); - }); + createComponentWithApollo(); + waitForPromises(); + }); - it('renders the pipeline mini graph', () => { - expect(findPipelineEditorMiniGraph().exists()).toBe(true); + it('renders pipeline not triggered error', () => { + expect(findPipelineErrorMsg().exists()).toBe(false); + expect(findIcon().attributes('name')).toBe('information-o'); + expect(findPipelineNotTriggeredErrorMsg().text()).toBe(i18n.pipelineNotTriggeredMsg); + }); }); }); }); diff --git a/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js b/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js index 3d7c3c839da..6b9f576917f 100644 --- a/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js +++ b/spec/frontend/pipeline_editor/components/header/pipline_editor_mini_graph_spec.js @@ -1,22 +1,54 @@ -import { shallowMount } from '@vue/test-utils'; +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; import PipelineEditorMiniGraph from '~/pipeline_editor/components/header/pipeline_editor_mini_graph.vue'; import PipelineMiniGraph from '~/pipelines/components/pipelines_list/pipeline_mini_graph.vue'; -import { mockProjectPipeline } from '../../mock_data'; +import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql'; +import { PIPELINE_FAILURE } from '~/pipeline_editor/constants'; +import { mockLinkedPipelines, mockProjectFullPath, mockProjectPipeline } from '../../mock_data'; + +const localVue = createLocalVue(); +localVue.use(VueApollo); describe('Pipeline Status', () => { let wrapper; + let mockApollo; + let mockLinkedPipelinesQuery; - const createComponent = ({ hasStages = true } = {}) => { + const createComponent = ({ hasStages = true, options } = {}) => { wrapper = shallowMount(PipelineEditorMiniGraph, { + provide: { + dataMethod: 'graphql', + projectFullPath: mockProjectFullPath, + }, propsData: { pipeline: mockProjectPipeline({ hasStages }).pipeline, }, + ...options, + }); + }; + + const createComponentWithApollo = (hasStages = true) => { + const handlers = [[getLinkedPipelinesQuery, mockLinkedPipelinesQuery]]; + mockApollo = createMockApollo(handlers); + + createComponent({ + hasStages, + options: { + localVue, + apolloProvider: mockApollo, + }, }); }; const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph); + beforeEach(() => { + mockLinkedPipelinesQuery = jest.fn(); + }); + afterEach(() => { + mockLinkedPipelinesQuery.mockReset(); wrapper.destroy(); }); @@ -39,4 +71,38 @@ describe('Pipeline Status', () => { expect(findPipelineMiniGraph().exists()).toBe(false); }); }); + + describe('when querying upstream and downstream pipelines', () => { + describe('when query succeeds', () => { + beforeEach(() => { + mockLinkedPipelinesQuery.mockResolvedValue(mockLinkedPipelines()); + createComponentWithApollo(); + }); + + it('should call the query with the correct variables', () => { + expect(mockLinkedPipelinesQuery).toHaveBeenCalledTimes(1); + expect(mockLinkedPipelinesQuery).toHaveBeenCalledWith({ + fullPath: mockProjectFullPath, + iid: mockProjectPipeline().pipeline.iid, + }); + }); + }); + + describe('when query fails', () => { + beforeEach(() => { + mockLinkedPipelinesQuery.mockRejectedValue(new Error()); + createComponentWithApollo(); + }); + + it('should emit an error event when query fails', async () => { + expect(wrapper.emitted('showError')).toHaveLength(1); + expect(wrapper.emitted('showError')[0]).toEqual([ + { + type: PIPELINE_FAILURE, + reasons: [wrapper.vm.$options.i18n.linkedPipelinesFetchError], + }, + ]); + }); + }); + }); }); diff --git a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js b/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js index 5cf8d47bc23..f6154f50bc0 100644 --- a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js +++ b/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js @@ -1,19 +1,27 @@ -import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; +import { GlAlert, GlLoadingIcon, GlTabs } from '@gitlab/ui'; import { shallowMount, mount } from '@vue/test-utils'; -import { nextTick } from 'vue'; +import Vue, { nextTick } from 'vue'; +import setWindowLocation from 'helpers/set_window_location_helper'; import CiConfigMergedPreview from '~/pipeline_editor/components/editor/ci_config_merged_preview.vue'; +import WalkthroughPopover from '~/pipeline_editor/components/walkthrough_popover.vue'; import CiLint from '~/pipeline_editor/components/lint/ci_lint.vue'; import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue'; import EditorTab from '~/pipeline_editor/components/ui/editor_tab.vue'; +import { stubExperiments } from 'helpers/experimentation_helper'; import { + CREATE_TAB, EDITOR_APP_STATUS_EMPTY, - EDITOR_APP_STATUS_ERROR, EDITOR_APP_STATUS_LOADING, EDITOR_APP_STATUS_INVALID, EDITOR_APP_STATUS_VALID, + MERGED_TAB, + TAB_QUERY_PARAM, + TABS_INDEX, } from '~/pipeline_editor/constants'; import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue'; -import { mockLintResponse, mockCiYml } from '../mock_data'; +import { mockLintResponse, mockLintResponseWithoutMerged, mockCiYml } from '../mock_data'; + +Vue.config.ignoredElements = ['gl-emoji']; describe('Pipeline editor tabs component', () => { let wrapper; @@ -22,6 +30,7 @@ describe('Pipeline editor tabs component', () => { }; const createComponent = ({ + listeners = {}, props = {}, provide = {}, appStatus = EDITOR_APP_STATUS_VALID, @@ -31,6 +40,7 @@ describe('Pipeline editor tabs component', () => { propsData: { ciConfigData: mockLintResponse, ciFileContent: mockCiYml, + isNewCiConfigFile: true, ...props, }, data() { @@ -43,6 +53,7 @@ describe('Pipeline editor tabs component', () => { TextEditor: MockTextEditor, EditorTab, }, + listeners, }); }; @@ -53,10 +64,12 @@ describe('Pipeline editor tabs component', () => { const findAlert = () => wrapper.findComponent(GlAlert); const findCiLint = () => wrapper.findComponent(CiLint); + const findGlTabs = () => wrapper.findComponent(GlTabs); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findPipelineGraph = () => wrapper.findComponent(PipelineGraph); const findTextEditor = () => wrapper.findComponent(MockTextEditor); const findMergedPreview = () => wrapper.findComponent(CiConfigMergedPreview); + const findWalkthroughPopover = () => wrapper.findComponent(WalkthroughPopover); afterEach(() => { wrapper.destroy(); @@ -137,7 +150,7 @@ describe('Pipeline editor tabs component', () => { describe('when there is a fetch error', () => { beforeEach(() => { - createComponent({ appStatus: EDITOR_APP_STATUS_ERROR }); + createComponent({ props: { ciConfigData: mockLintResponseWithoutMerged } }); }); it('show an error message', () => { @@ -181,4 +194,113 @@ describe('Pipeline editor tabs component', () => { }, ); }); + + describe('default tab based on url query param', () => { + const gitlabUrl = 'https://gitlab.test/ci/editor/'; + const matchObject = { + hostname: 'gitlab.test', + pathname: '/ci/editor/', + search: '', + }; + + it(`is ${CREATE_TAB} if the query param ${TAB_QUERY_PARAM} is not present`, () => { + setWindowLocation(gitlabUrl); + createComponent(); + + expect(window.location).toMatchObject(matchObject); + }); + + it(`is ${CREATE_TAB} tab if the query param ${TAB_QUERY_PARAM} is invalid`, () => { + const queryValue = 'FOO'; + setWindowLocation(`${gitlabUrl}?${TAB_QUERY_PARAM}=${queryValue}`); + createComponent(); + + // If the query param remains unchanged, then we have ignored it. + expect(window.location).toMatchObject({ + ...matchObject, + search: `?${TAB_QUERY_PARAM}=${queryValue}`, + }); + }); + + it('is the tab specified in query param and transform it into an index value', async () => { + setWindowLocation(`${gitlabUrl}?${TAB_QUERY_PARAM}=${MERGED_TAB}`); + createComponent(); + + // If the query param has changed to an index, it means we have synced the + // query with. + expect(window.location).toMatchObject({ + ...matchObject, + search: `?${TAB_QUERY_PARAM}=${TABS_INDEX[MERGED_TAB]}`, + }); + }); + }); + + describe('glTabs', () => { + beforeEach(() => { + createComponent(); + }); + + it('passes the `sync-active-tab-with-query-params` prop', () => { + expect(findGlTabs().props('syncActiveTabWithQueryParams')).toBe(true); + }); + }); + + describe('pipeline_editor_walkthrough experiment', () => { + describe('when in control path', () => { + beforeEach(() => { + stubExperiments({ pipeline_editor_walkthrough: 'control' }); + }); + + it('does not show walkthrough popover', async () => { + createComponent({ mountFn: mount }); + await nextTick(); + expect(findWalkthroughPopover().exists()).toBe(false); + }); + }); + + describe('when in candidate path', () => { + beforeEach(() => { + stubExperiments({ pipeline_editor_walkthrough: 'candidate' }); + }); + + describe('when isNewCiConfigFile prop is true (default)', () => { + beforeEach(async () => { + createComponent({ + mountFn: mount, + }); + await nextTick(); + }); + + it('shows walkthrough popover', async () => { + expect(findWalkthroughPopover().exists()).toBe(true); + }); + }); + + describe('when isNewCiConfigFile prop is false', () => { + it('does not show walkthrough popover', async () => { + createComponent({ props: { isNewCiConfigFile: false }, mountFn: mount }); + await nextTick(); + expect(findWalkthroughPopover().exists()).toBe(false); + }); + }); + }); + }); + + it('sets listeners on walkthrough popover', async () => { + stubExperiments({ pipeline_editor_walkthrough: 'candidate' }); + + const handler = jest.fn(); + + createComponent({ + mountFn: mount, + listeners: { + event: handler, + }, + }); + await nextTick(); + + findWalkthroughPopover().vm.$emit('event'); + + expect(handler).toHaveBeenCalled(); + }); }); diff --git a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_messages_spec.js b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_messages_spec.js index 9f910ed4f9c..a55176ccd79 100644 --- a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_messages_spec.js +++ b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_messages_spec.js @@ -11,6 +11,7 @@ import { DEFAULT_FAILURE, DEFAULT_SUCCESS, LOAD_FAILURE_UNKNOWN, + PIPELINE_FAILURE, } from '~/pipeline_editor/constants'; beforeEach(() => { @@ -65,6 +66,7 @@ describe('Pipeline Editor messages', () => { failureType | message | expectedFailureType ${COMMIT_FAILURE} | ${'failed commit'} | ${COMMIT_FAILURE} ${LOAD_FAILURE_UNKNOWN} | ${'loading failure'} | ${LOAD_FAILURE_UNKNOWN} + ${PIPELINE_FAILURE} | ${'pipeline failure'} | ${PIPELINE_FAILURE} ${'random'} | ${'error without a specified type'} | ${DEFAULT_FAILURE} `('shows a message for $message', ({ failureType, expectedFailureType }) => { createComponent({ failureType, showFailure: true }); diff --git a/spec/frontend/pipeline_editor/components/walkthrough_popover_spec.js b/spec/frontend/pipeline_editor/components/walkthrough_popover_spec.js new file mode 100644 index 00000000000..a9ce89ff521 --- /dev/null +++ b/spec/frontend/pipeline_editor/components/walkthrough_popover_spec.js @@ -0,0 +1,29 @@ +import { mount, shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; +import WalkthroughPopover from '~/pipeline_editor/components/walkthrough_popover.vue'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; + +Vue.config.ignoredElements = ['gl-emoji']; + +describe('WalkthroughPopover component', () => { + let wrapper; + + const createComponent = (mountFn = shallowMount) => { + return extendedWrapper(mountFn(WalkthroughPopover)); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('CTA button clicked', () => { + beforeEach(async () => { + wrapper = createComponent(mount); + await wrapper.findByTestId('ctaBtn').trigger('click'); + }); + + it('emits "walkthrough-popover-cta-clicked" event', async () => { + expect(wrapper.emitted()['walkthrough-popover-cta-clicked']).toBeTruthy(); + }); + }); +}); -- cgit v1.2.3