From 36a59d088eca61b834191dacea009677a96c052f Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 19 May 2022 07:33:21 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-0-stable-ee --- .../components/jobs/failed_jobs_app_spec.js | 87 +++++++++++ .../components/jobs/failed_jobs_table_spec.js | 117 +++++++++++++++ .../pipelines/components/jobs/utils_spec.js | 14 ++ .../pipelines/components/pipeline_tabs_spec.js | 9 +- .../empty_state/ci_templates_spec.js | 112 ++++++++++++++ .../empty_state/ios_templates_spec.js | 138 ++++++++++++++++++ .../empty_state/pipelines_ci_templates_spec.js | 161 +++++++++++++++++++++ .../pipelines_list/pipeline_stage_spec.js | 6 +- 8 files changed, 640 insertions(+), 4 deletions(-) create mode 100644 spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js create mode 100644 spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js create mode 100644 spec/frontend/pipelines/components/jobs/utils_spec.js create mode 100644 spec/frontend/pipelines/components/pipelines_list/empty_state/ci_templates_spec.js create mode 100644 spec/frontend/pipelines/components/pipelines_list/empty_state/ios_templates_spec.js create mode 100644 spec/frontend/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates_spec.js (limited to 'spec/frontend/pipelines/components') diff --git a/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js b/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js new file mode 100644 index 00000000000..3b5632a8a4e --- /dev/null +++ b/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js @@ -0,0 +1,87 @@ +import { GlLoadingIcon } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import createFlash from '~/flash'; +import FailedJobsApp from '~/pipelines/components/jobs/failed_jobs_app.vue'; +import FailedJobsTable from '~/pipelines/components/jobs/failed_jobs_table.vue'; +import GetFailedJobsQuery from '~/pipelines/graphql/queries/get_failed_jobs.query.graphql'; +import { mockFailedJobsQueryResponse, mockFailedJobsSummaryData } from '../../mock_data'; + +Vue.use(VueApollo); + +jest.mock('~/flash'); + +describe('Failed Jobs App', () => { + let wrapper; + let resolverSpy; + + const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon); + const findJobsTable = () => wrapper.findComponent(FailedJobsTable); + + const createMockApolloProvider = (resolver) => { + const requestHandlers = [[GetFailedJobsQuery, resolver]]; + + return createMockApollo(requestHandlers); + }; + + const createComponent = (resolver, failedJobsSummaryData = mockFailedJobsSummaryData) => { + wrapper = shallowMount(FailedJobsApp, { + provide: { + fullPath: 'root/ci-project', + pipelineIid: 1, + }, + propsData: { + failedJobsSummary: failedJobsSummaryData, + }, + apolloProvider: createMockApolloProvider(resolver), + }); + }; + + beforeEach(() => { + resolverSpy = jest.fn().mockResolvedValue(mockFailedJobsQueryResponse); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('loading spinner', () => { + beforeEach(() => { + createComponent(resolverSpy); + }); + + it('displays loading spinner when fetching failed jobs', () => { + expect(findLoadingSpinner().exists()).toBe(true); + }); + + it('hides loading spinner after the failed jobs have been fetched', async () => { + await waitForPromises(); + + expect(findLoadingSpinner().exists()).toBe(false); + }); + }); + + it('displays the failed jobs table', async () => { + createComponent(resolverSpy); + + await waitForPromises(); + + expect(findJobsTable().exists()).toBe(true); + expect(createFlash).not.toHaveBeenCalled(); + }); + + it('handles query fetch error correctly', async () => { + resolverSpy = jest.fn().mockRejectedValue(new Error('GraphQL error')); + + createComponent(resolverSpy); + + await waitForPromises(); + + expect(createFlash).toHaveBeenCalledWith({ + message: 'There was a problem fetching the failed jobs.', + }); + }); +}); diff --git a/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js b/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js new file mode 100644 index 00000000000..b597a3bf4b0 --- /dev/null +++ b/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js @@ -0,0 +1,117 @@ +import { GlButton, GlLink, GlTableLite } from '@gitlab/ui'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import createFlash from '~/flash'; +import { redirectTo } from '~/lib/utils/url_utility'; +import FailedJobsTable from '~/pipelines/components/jobs/failed_jobs_table.vue'; +import RetryFailedJobMutation from '~/pipelines/graphql/mutations/retry_failed_job.mutation.graphql'; +import { + successRetryMutationResponse, + failedRetryMutationResponse, + mockPreparedFailedJobsData, + mockPreparedFailedJobsDataNoPermission, +} from '../../mock_data'; + +jest.mock('~/flash'); +jest.mock('~/lib/utils/url_utility'); + +Vue.use(VueApollo); + +describe('Failed Jobs Table', () => { + let wrapper; + + const successRetryMutationHandler = jest.fn().mockResolvedValue(successRetryMutationResponse); + const failedRetryMutationHandler = jest.fn().mockResolvedValue(failedRetryMutationResponse); + + const findJobsTable = () => wrapper.findComponent(GlTableLite); + const findRetryButton = () => wrapper.findComponent(GlButton); + const findJobLink = () => wrapper.findComponent(GlLink); + const findJobLog = () => wrapper.findByTestId('job-log'); + + const createMockApolloProvider = (resolver) => { + const requestHandlers = [[RetryFailedJobMutation, resolver]]; + return createMockApollo(requestHandlers); + }; + + const createComponent = (resolver, failedJobsData = mockPreparedFailedJobsData) => { + wrapper = mountExtended(FailedJobsTable, { + propsData: { + failedJobs: failedJobsData, + }, + apolloProvider: createMockApolloProvider(resolver), + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + it('displays the failed jobs table', () => { + createComponent(); + + expect(findJobsTable().exists()).toBe(true); + }); + + it('calls the retry failed job mutation correctly', () => { + createComponent(successRetryMutationHandler); + + findRetryButton().trigger('click'); + + expect(successRetryMutationHandler).toHaveBeenCalledWith({ + id: mockPreparedFailedJobsData[0].id, + }); + }); + + it('redirects to the new job after the mutation', async () => { + const { + data: { + jobRetry: { job }, + }, + } = successRetryMutationResponse; + + createComponent(successRetryMutationHandler); + + findRetryButton().trigger('click'); + + await waitForPromises(); + + expect(redirectTo).toHaveBeenCalledWith(job.detailedStatus.detailsPath); + }); + + it('shows error message if the retry failed job mutation fails', async () => { + createComponent(failedRetryMutationHandler); + + findRetryButton().trigger('click'); + + await waitForPromises(); + + expect(createFlash).toHaveBeenCalledWith({ + message: 'There was a problem retrying the failed job.', + }); + }); + + it('hides the job log and retry button if a user does not have permission', () => { + createComponent([[]], mockPreparedFailedJobsDataNoPermission); + + expect(findJobLog().exists()).toBe(false); + expect(findRetryButton().exists()).toBe(false); + }); + + it('displays the job log and retry button if a user has permission', () => { + createComponent(); + + expect(findJobLog().exists()).toBe(true); + expect(findRetryButton().exists()).toBe(true); + }); + + it('job name links to the correct job', () => { + createComponent(); + + expect(findJobLink().attributes('href')).toBe( + mockPreparedFailedJobsData[0].detailedStatus.detailsPath, + ); + }); +}); diff --git a/spec/frontend/pipelines/components/jobs/utils_spec.js b/spec/frontend/pipelines/components/jobs/utils_spec.js new file mode 100644 index 00000000000..720446cfda3 --- /dev/null +++ b/spec/frontend/pipelines/components/jobs/utils_spec.js @@ -0,0 +1,14 @@ +import { prepareFailedJobs } from '~/pipelines/components/jobs/utils'; +import { + mockFailedJobsData, + mockFailedJobsSummaryData, + mockPreparedFailedJobsData, +} from '../../mock_data'; + +describe('Utils', () => { + it('prepares failed jobs data correctly', () => { + expect(prepareFailedJobs(mockFailedJobsData, mockFailedJobsSummaryData)).toEqual( + mockPreparedFailedJobsData, + ); + }); +}); diff --git a/spec/frontend/pipelines/components/pipeline_tabs_spec.js b/spec/frontend/pipelines/components/pipeline_tabs_spec.js index e18c3edbad9..89002ee47a8 100644 --- a/spec/frontend/pipelines/components/pipeline_tabs_spec.js +++ b/spec/frontend/pipelines/components/pipeline_tabs_spec.js @@ -21,14 +21,19 @@ describe('The Pipeline Tabs', () => { const findPipelineApp = () => wrapper.findComponent(PipelineGraphWrapper); const findTestsApp = () => wrapper.findComponent(TestReports); + const defaultProvide = { + defaultTabValue: '', + }; + const createComponent = (propsData = {}) => { wrapper = extendedWrapper( shallowMount(PipelineTabs, { propsData, + provide: { + ...defaultProvide, + }, stubs: { - Dag: { template: '
' }, JobsApp: { template: '
' }, - PipelineGraph: { template: '
' }, TestReports: { template: '
' }, }, }), diff --git a/spec/frontend/pipelines/components/pipelines_list/empty_state/ci_templates_spec.js b/spec/frontend/pipelines/components/pipelines_list/empty_state/ci_templates_spec.js new file mode 100644 index 00000000000..6531a15ab8e --- /dev/null +++ b/spec/frontend/pipelines/components/pipelines_list/empty_state/ci_templates_spec.js @@ -0,0 +1,112 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; +import CiTemplates from '~/pipelines/components/pipelines_list/empty_state/ci_templates.vue'; + +const pipelineEditorPath = '/-/ci/editor'; +const suggestedCiTemplates = [ + { name: 'Android', logo: '/assets/illustrations/logos/android.svg' }, + { name: 'Bash', logo: '/assets/illustrations/logos/bash.svg' }, + { name: 'C++', logo: '/assets/illustrations/logos/c_plus_plus.svg' }, +]; + +describe('CI Templates', () => { + let wrapper; + let trackingSpy; + + const createWrapper = (propsData = {}) => { + wrapper = shallowMountExtended(CiTemplates, { + provide: { + pipelineEditorPath, + suggestedCiTemplates, + }, + propsData, + }); + }; + + const findTemplateDescription = () => wrapper.findByTestId('template-description'); + const findTemplateLink = () => wrapper.findByTestId('template-link'); + const findTemplateNames = () => wrapper.findAllByTestId('template-name'); + const findTemplateName = () => wrapper.findByTestId('template-name'); + const findTemplateLogo = () => wrapper.findByTestId('template-logo'); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('renders template list', () => { + beforeEach(() => { + createWrapper(); + }); + + it('renders all suggested templates', () => { + expect(findTemplateNames().length).toBe(3); + expect(wrapper.text()).toContain('Android', 'Bash', 'C++'); + }); + + it('has the correct template name', () => { + expect(findTemplateName().text()).toBe('Android'); + }); + + it('links to the correct template', () => { + expect(findTemplateLink().attributes('href')).toBe( + pipelineEditorPath.concat('?template=Android'), + ); + }); + + it('has the link button enabled', () => { + expect(findTemplateLink().props('disabled')).toBe(false); + }); + + it('has the description of the template', () => { + expect(findTemplateDescription().text()).toBe( + 'Continuous integration and deployment template to test and deploy your Android project.', + ); + }); + + it('has the right logo of the template', () => { + expect(findTemplateLogo().attributes('src')).toBe('/assets/illustrations/logos/android.svg'); + }); + }); + + describe('filtering the templates', () => { + beforeEach(() => { + createWrapper({ filterTemplates: ['Bash'] }); + }); + + it('renders only the filtered templates', () => { + expect(findTemplateNames()).toHaveLength(1); + expect(findTemplateName().text()).toBe('Bash'); + }); + }); + + describe('disabling the templates', () => { + beforeEach(() => { + createWrapper({ disabled: true }); + }); + + it('has the link button disabled', () => { + expect(findTemplateLink().props('disabled')).toBe(true); + }); + }); + + describe('tracking', () => { + beforeEach(() => { + createWrapper(); + trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); + }); + + afterEach(() => { + unmockTracking(); + }); + + it('sends an event when template is clicked', () => { + findTemplateLink().vm.$emit('click'); + + expect(trackingSpy).toHaveBeenCalledTimes(1); + expect(trackingSpy).toHaveBeenCalledWith(undefined, 'template_clicked', { + label: 'Android', + }); + }); + }); +}); diff --git a/spec/frontend/pipelines/components/pipelines_list/empty_state/ios_templates_spec.js b/spec/frontend/pipelines/components/pipelines_list/empty_state/ios_templates_spec.js new file mode 100644 index 00000000000..0c2938921d6 --- /dev/null +++ b/spec/frontend/pipelines/components/pipelines_list/empty_state/ios_templates_spec.js @@ -0,0 +1,138 @@ +import '~/commons'; +import { nextTick } from 'vue'; +import { GlPopover, GlButton } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue'; +import IosTemplates from '~/pipelines/components/pipelines_list/empty_state/ios_templates.vue'; +import CiTemplates from '~/pipelines/components/pipelines_list/empty_state/ci_templates.vue'; + +const pipelineEditorPath = '/-/ci/editor'; +const registrationToken = 'SECRET_TOKEN'; +const iOSTemplateName = 'iOS-Fastlane'; + +describe('iOS Templates', () => { + let wrapper; + + const createWrapper = (providedPropsData = {}) => { + return shallowMountExtended(IosTemplates, { + provide: { + pipelineEditorPath, + iosRunnersAvailable: true, + ...providedPropsData, + }, + propsData: { + registrationToken, + }, + stubs: { + GlButton, + }, + }); + }; + + const findIosTemplate = () => wrapper.findComponent(CiTemplates); + const findRunnerInstructionsModal = () => wrapper.findComponent(RunnerInstructionsModal); + const findRunnerInstructionsPopover = () => wrapper.findComponent(GlPopover); + const findRunnerSetupTodoEmoji = () => wrapper.findByTestId('runner-setup-marked-todo'); + const findRunnerSetupCompletedEmoji = () => wrapper.findByTestId('runner-setup-marked-completed'); + const findSetupRunnerLink = () => wrapper.findByText('Set up a runner'); + const configurePipelineLink = () => wrapper.findByTestId('configure-pipeline-link'); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('when ios runners are not available', () => { + beforeEach(() => { + wrapper = createWrapper({ iosRunnersAvailable: false }); + }); + + describe('the runner setup section', () => { + it('marks the section as todo', () => { + expect(findRunnerSetupTodoEmoji().isVisible()).toBe(true); + expect(findRunnerSetupCompletedEmoji().isVisible()).toBe(false); + }); + + it('renders the setup runner link', () => { + expect(findSetupRunnerLink().exists()).toBe(true); + }); + + it('renders the runner instructions modal with a popover once clicked', async () => { + findSetupRunnerLink().element.parentElement.click(); + + await nextTick(); + + expect(findRunnerInstructionsModal().exists()).toBe(true); + expect(findRunnerInstructionsModal().props('registrationToken')).toBe(registrationToken); + expect(findRunnerInstructionsModal().props('defaultPlatformName')).toBe('osx'); + + findRunnerInstructionsModal().vm.$emit('shown'); + + await nextTick(); + + expect(findRunnerInstructionsPopover().exists()).toBe(true); + }); + }); + + describe('the configure pipeline section', () => { + it('has a disabled link button', () => { + expect(configurePipelineLink().props('disabled')).toBe(true); + }); + }); + + describe('the ios-Fastlane template', () => { + it('renders the template', () => { + expect(findIosTemplate().props('filterTemplates')).toStrictEqual([iOSTemplateName]); + }); + + it('has a disabled link button', () => { + expect(findIosTemplate().props('disabled')).toBe(true); + }); + }); + }); + + describe('when ios runners are available', () => { + beforeEach(() => { + wrapper = createWrapper(); + }); + + describe('the runner setup section', () => { + it('marks the section as completed', () => { + expect(findRunnerSetupTodoEmoji().isVisible()).toBe(false); + expect(findRunnerSetupCompletedEmoji().isVisible()).toBe(true); + }); + + it('does not render the setup runner link', () => { + expect(findSetupRunnerLink().exists()).toBe(false); + }); + }); + + describe('the configure pipeline section', () => { + it('has an enabled link button', () => { + expect(configurePipelineLink().props('disabled')).toBe(false); + }); + + it('links to the pipeline editor with the right template', () => { + expect(configurePipelineLink().attributes('href')).toBe( + `${pipelineEditorPath}?template=${iOSTemplateName}`, + ); + }); + }); + + describe('the ios-Fastlane template', () => { + it('renders the template', () => { + expect(findIosTemplate().props('filterTemplates')).toStrictEqual([iOSTemplateName]); + }); + + it('has an enabled link button', () => { + expect(findIosTemplate().props('disabled')).toBe(false); + }); + + it('links to the pipeline editor with the right template', () => { + expect(configurePipelineLink().attributes('href')).toBe( + `${pipelineEditorPath}?template=${iOSTemplateName}`, + ); + }); + }); + }); +}); diff --git a/spec/frontend/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates_spec.js b/spec/frontend/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates_spec.js new file mode 100644 index 00000000000..b537c81da3f --- /dev/null +++ b/spec/frontend/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates_spec.js @@ -0,0 +1,161 @@ +import '~/commons'; +import { GlButton, GlSprintf } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; +import { stubExperiments } from 'helpers/experimentation_helper'; +import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue'; +import ExperimentTracking from '~/experimentation/experiment_tracking'; +import PipelinesCiTemplates from '~/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue'; +import CiTemplates from '~/pipelines/components/pipelines_list/empty_state/ci_templates.vue'; +import { + RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME, + RUNNERS_SETTINGS_LINK_CLICKED_EVENT, + RUNNERS_DOCUMENTATION_LINK_CLICKED_EVENT, + RUNNERS_SETTINGS_BUTTON_CLICKED_EVENT, + I18N, +} from '~/pipeline_editor/constants'; + +const pipelineEditorPath = '/-/ci/editor'; +const ciRunnerSettingsPath = '/-/settings/ci_cd'; + +jest.mock('~/experimentation/experiment_tracking'); + +describe('Pipelines CI Templates', () => { + let wrapper; + let trackingSpy; + + const createWrapper = (propsData = {}, stubs = {}) => { + return shallowMountExtended(PipelinesCiTemplates, { + provide: { + pipelineEditorPath, + ciRunnerSettingsPath, + anyRunnersAvailable: true, + ...propsData, + }, + stubs, + }); + }; + + const findTestTemplateLink = () => wrapper.findByTestId('test-template-link'); + const findCiTemplates = () => wrapper.findComponent(CiTemplates); + const findSettingsLink = () => wrapper.findByTestId('settings-link'); + const findDocumentationLink = () => wrapper.findByTestId('documentation-link'); + const findSettingsButton = () => wrapper.findByTestId('settings-button'); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('renders test template', () => { + beforeEach(() => { + wrapper = createWrapper(); + }); + + it('links to the getting started template', () => { + expect(findTestTemplateLink().attributes('href')).toBe( + pipelineEditorPath.concat('?template=Getting-Started'), + ); + }); + }); + + describe('tracking', () => { + beforeEach(() => { + wrapper = createWrapper(); + trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); + }); + + afterEach(() => { + unmockTracking(); + }); + + it('sends an event when Getting-Started template is clicked', () => { + findTestTemplateLink().vm.$emit('click'); + + expect(trackingSpy).toHaveBeenCalledTimes(1); + expect(trackingSpy).toHaveBeenCalledWith(undefined, 'template_clicked', { + label: 'Getting-Started', + }); + }); + }); + + describe('when the runners_availability_section experiment is active', () => { + beforeEach(() => { + stubExperiments({ runners_availability_section: 'candidate' }); + }); + + describe('when runners are available', () => { + beforeEach(() => { + wrapper = createWrapper({ anyRunnersAvailable: true }, { GitlabExperiment, GlSprintf }); + }); + + it('show the runners available section', () => { + expect(wrapper.text()).toContain(I18N.runners.title); + }); + + it('tracks an event when clicking the settings link', () => { + findSettingsLink().vm.$emit('click'); + + expect(ExperimentTracking).toHaveBeenCalledWith( + RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME, + ); + expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith( + RUNNERS_SETTINGS_LINK_CLICKED_EVENT, + ); + }); + + it('tracks an event when clicking the documentation link', () => { + findDocumentationLink().vm.$emit('click'); + + expect(ExperimentTracking).toHaveBeenCalledWith( + RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME, + ); + expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith( + RUNNERS_DOCUMENTATION_LINK_CLICKED_EVENT, + ); + }); + }); + + describe('when runners are not available', () => { + beforeEach(() => { + wrapper = createWrapper({ anyRunnersAvailable: false }, { GitlabExperiment, GlButton }); + }); + + it('show the no runners available section', () => { + expect(wrapper.text()).toContain(I18N.noRunners.title); + }); + + it('tracks an event when clicking the settings button', () => { + findSettingsButton().trigger('click'); + + expect(ExperimentTracking).toHaveBeenCalledWith( + RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME, + ); + expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith( + RUNNERS_SETTINGS_BUTTON_CLICKED_EVENT, + ); + }); + }); + }); + + describe.each` + experimentVariant | anyRunnersAvailable | templatesRendered + ${'control'} | ${true} | ${true} + ${'control'} | ${false} | ${true} + ${'candidate'} | ${true} | ${true} + ${'candidate'} | ${false} | ${false} + `( + 'when the runners_availability_section experiment variant is $experimentVariant and runners are available: $anyRunnersAvailable', + ({ experimentVariant, anyRunnersAvailable, templatesRendered }) => { + beforeEach(() => { + stubExperiments({ runners_availability_section: experimentVariant }); + wrapper = createWrapper({ anyRunnersAvailable }); + }); + + it(`renders the templates: ${templatesRendered}`, () => { + expect(findTestTemplateLink().exists()).toBe(templatesRendered); + expect(findCiTemplates().exists()).toBe(templatesRendered); + }); + }, + ); +}); diff --git a/spec/frontend/pipelines/components/pipelines_list/pipeline_stage_spec.js b/spec/frontend/pipelines/components/pipelines_list/pipeline_stage_spec.js index 93bc8faa51b..6d0e99ff63e 100644 --- a/spec/frontend/pipelines/components/pipelines_list/pipeline_stage_spec.js +++ b/spec/frontend/pipelines/components/pipelines_list/pipeline_stage_spec.js @@ -1,6 +1,7 @@ import { GlDropdown } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; +import CiIcon from '~/vue_shared/components/ci_icon.vue'; import axios from '~/lib/utils/axios_utils'; import PipelineStage from '~/pipelines/components/pipelines_list/pipeline_stage.vue'; import eventHub from '~/pipelines/event_hub'; @@ -48,11 +49,12 @@ describe('Pipelines stage component', () => { mock.restore(); }); + const findCiActionBtn = () => wrapper.find('.js-ci-action'); + const findCiIcon = () => wrapper.findComponent(CiIcon); const findDropdown = () => wrapper.findComponent(GlDropdown); const findDropdownToggle = () => wrapper.find('button.dropdown-toggle'); const findDropdownMenu = () => wrapper.find('[data-testid="mini-pipeline-graph-dropdown-menu-list"]'); - const findCiActionBtn = () => wrapper.find('.js-ci-action'); const findMergeTrainWarning = () => wrapper.find('[data-testid="warning-message-merge-trains"]'); const openStageDropdown = () => { @@ -74,7 +76,7 @@ describe('Pipelines stage component', () => { it('should render a dropdown with the status icon', () => { expect(findDropdown().exists()).toBe(true); expect(findDropdownToggle().exists()).toBe(true); - expect(wrapper.find('[data-testid="status_success_borderless-icon"]').exists()).toBe(true); + expect(findCiIcon().exists()).toBe(true); }); }); -- cgit v1.2.3