diff options
Diffstat (limited to 'spec/frontend/pipelines/pipeline_details_header_spec.js')
-rw-r--r-- | spec/frontend/pipelines/pipeline_details_header_spec.js | 210 |
1 files changed, 205 insertions, 5 deletions
diff --git a/spec/frontend/pipelines/pipeline_details_header_spec.js b/spec/frontend/pipelines/pipeline_details_header_spec.js index 08ae35fe808..7141e10fb17 100644 --- a/spec/frontend/pipelines/pipeline_details_header_spec.js +++ b/spec/frontend/pipelines/pipeline_details_header_spec.js @@ -1,23 +1,59 @@ -import { GlBadge, GlLoadingIcon } from '@gitlab/ui'; -import Vue from 'vue'; +import { GlAlert, GlBadge, GlLoadingIcon, GlModal } 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 PipelineDetailsHeader from '~/pipelines/components/pipeline_details_header.vue'; +import { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL } from '~/pipelines/constants'; import TimeAgo from '~/pipelines/components/pipelines_list/time_ago.vue'; import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue'; +import cancelPipelineMutation from '~/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql'; +import deletePipelineMutation from '~/pipelines/graphql/mutations/delete_pipeline.mutation.graphql'; +import retryPipelineMutation from '~/pipelines/graphql/mutations/retry_pipeline.mutation.graphql'; import getPipelineDetailsQuery from '~/pipelines/graphql/queries/get_pipeline_header_data.query.graphql'; -import { pipelineHeaderSuccess, pipelineHeaderRunning } from './mock_data'; +import { + pipelineHeaderSuccess, + pipelineHeaderRunning, + pipelineHeaderFailed, + pipelineRetryMutationResponseSuccess, + pipelineCancelMutationResponseSuccess, + pipelineDeleteMutationResponseSuccess, + pipelineRetryMutationResponseFailed, + pipelineCancelMutationResponseFailed, + pipelineDeleteMutationResponseFailed, +} from './mock_data'; Vue.use(VueApollo); describe('Pipeline details header', () => { let wrapper; + let glModalDirective; const successHandler = jest.fn().mockResolvedValue(pipelineHeaderSuccess); const runningHandler = jest.fn().mockResolvedValue(pipelineHeaderRunning); + const failedHandler = jest.fn().mockResolvedValue(pipelineHeaderFailed); + const retryMutationHandlerSuccess = jest + .fn() + .mockResolvedValue(pipelineRetryMutationResponseSuccess); + const cancelMutationHandlerSuccess = jest + .fn() + .mockResolvedValue(pipelineCancelMutationResponseSuccess); + const deleteMutationHandlerSuccess = jest + .fn() + .mockResolvedValue(pipelineDeleteMutationResponseSuccess); + const retryMutationHandlerFailed = jest + .fn() + .mockResolvedValue(pipelineRetryMutationResponseFailed); + const cancelMutationHandlerFailed = jest + .fn() + .mockResolvedValue(pipelineCancelMutationResponseFailed); + const deleteMutationHandlerFailed = jest + .fn() + .mockResolvedValue(pipelineDeleteMutationResponseFailed); + + const findAlert = () => wrapper.findComponent(GlAlert); const findStatus = () => wrapper.findComponent(CiBadgeLink); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findTimeAgo = () => wrapper.findComponent(TimeAgo); @@ -28,6 +64,10 @@ describe('Pipeline details header', () => { const findCommitLink = () => wrapper.findByTestId('commit-link'); const findPipelineRunningText = () => wrapper.findByTestId('pipeline-running-text').text(); const findPipelineRefText = () => wrapper.findByTestId('pipeline-ref-text').text(); + const findRetryButton = () => wrapper.findByTestId('retry-pipeline'); + const findCancelButton = () => wrapper.findByTestId('cancel-pipeline'); + const findDeleteButton = () => wrapper.findByTestId('delete-pipeline'); + const findDeleteModal = () => wrapper.findComponent(GlModal); const defaultHandlers = [[getPipelineDetailsQuery, successHandler]]; @@ -58,7 +98,7 @@ describe('Pipeline details header', () => { stuck: false, }, refText: - 'For merge request <a class="mr-iid" href="/root/ci-project/-/merge_requests/1">!1</a> to merge <a class="ref-name" href="/root/ci-project/-/commits/test">test</a>', + 'Related merge request <a class="mr-iid" href="/root/ci-project/-/merge_requests/1">!1</a> to merge <a class="ref-name" href="/root/ci-project/-/commits/test">test</a>', }; const createMockApolloProvider = (handlers) => { @@ -66,6 +106,8 @@ describe('Pipeline details header', () => { }; const createComponent = (handlers = defaultHandlers, props = defaultProps) => { + glModalDirective = jest.fn(); + wrapper = shallowMountExtended(PipelineDetailsHeader, { provide: { ...defaultProvideOptions, @@ -73,6 +115,13 @@ describe('Pipeline details header', () => { propsData: { ...props, }, + directives: { + glModal: { + bind(_, { value }) { + glModalDirective(value); + }, + }, + }, apolloProvider: createMockApolloProvider(handlers), }); }; @@ -125,7 +174,7 @@ describe('Pipeline details header', () => { }); it('displays ref text', () => { - expect(findPipelineRefText()).toBe('For merge request !1 to merge test'); + expect(findPipelineRefText()).toBe('Related merge request !1 to merge test'); }); }); @@ -164,4 +213,155 @@ describe('Pipeline details header', () => { expect(findPipelineRunningText()).toBe('In progress, queued for 3600 seconds'); }); }); + + describe('actions', () => { + describe('retry action', () => { + beforeEach(async () => { + createComponent([ + [getPipelineDetailsQuery, failedHandler], + [retryPipelineMutation, retryMutationHandlerSuccess], + ]); + + await waitForPromises(); + }); + + it('should call retryPipeline Mutation with pipeline id', () => { + findRetryButton().vm.$emit('click'); + + expect(retryMutationHandlerSuccess).toHaveBeenCalledWith({ + id: pipelineHeaderFailed.data.project.pipeline.id, + }); + expect(findAlert().exists()).toBe(false); + }); + + it('should render retry action tooltip', () => { + expect(findRetryButton().attributes('title')).toBe(BUTTON_TOOLTIP_RETRY); + }); + }); + + describe('retry action failed', () => { + beforeEach(async () => { + createComponent([ + [getPipelineDetailsQuery, failedHandler], + [retryPipelineMutation, retryMutationHandlerFailed], + ]); + + await waitForPromises(); + }); + + it('should display error message on failure', async () => { + findRetryButton().vm.$emit('click'); + + await waitForPromises(); + + expect(findAlert().exists()).toBe(true); + }); + + it('retry button loading state should reset on error', async () => { + findRetryButton().vm.$emit('click'); + + await nextTick(); + + expect(findRetryButton().props('loading')).toBe(true); + + await waitForPromises(); + + expect(findRetryButton().props('loading')).toBe(false); + }); + }); + + describe('cancel action', () => { + it('should call cancelPipeline Mutation with pipeline id', async () => { + createComponent([ + [getPipelineDetailsQuery, runningHandler], + [cancelPipelineMutation, cancelMutationHandlerSuccess], + ]); + + await waitForPromises(); + + findCancelButton().vm.$emit('click'); + + expect(cancelMutationHandlerSuccess).toHaveBeenCalledWith({ + id: pipelineHeaderRunning.data.project.pipeline.id, + }); + expect(findAlert().exists()).toBe(false); + }); + + it('should render cancel action tooltip', async () => { + createComponent([ + [getPipelineDetailsQuery, runningHandler], + [cancelPipelineMutation, cancelMutationHandlerSuccess], + ]); + + await waitForPromises(); + + expect(findCancelButton().attributes('title')).toBe(BUTTON_TOOLTIP_CANCEL); + }); + + it('should display error message on failure', async () => { + createComponent([ + [getPipelineDetailsQuery, runningHandler], + [cancelPipelineMutation, cancelMutationHandlerFailed], + ]); + + await waitForPromises(); + + findCancelButton().vm.$emit('click'); + + await waitForPromises(); + + expect(findAlert().exists()).toBe(true); + }); + }); + + describe('delete action', () => { + it('displays delete modal when clicking on delete and does not call the delete action', async () => { + createComponent([ + [getPipelineDetailsQuery, successHandler], + [deletePipelineMutation, deleteMutationHandlerSuccess], + ]); + + await waitForPromises(); + + findDeleteButton().vm.$emit('click'); + + const modalId = 'pipeline-delete-modal'; + + expect(findDeleteModal().props('modalId')).toBe(modalId); + expect(glModalDirective).toHaveBeenCalledWith(modalId); + expect(deleteMutationHandlerSuccess).not.toHaveBeenCalled(); + expect(findAlert().exists()).toBe(false); + }); + + it('should call deletePipeline Mutation with pipeline id when modal is submitted', async () => { + createComponent([ + [getPipelineDetailsQuery, successHandler], + [deletePipelineMutation, deleteMutationHandlerSuccess], + ]); + + await waitForPromises(); + + findDeleteModal().vm.$emit('primary'); + + expect(deleteMutationHandlerSuccess).toHaveBeenCalledWith({ + id: pipelineHeaderSuccess.data.project.pipeline.id, + }); + }); + + it('should display error message on failure', async () => { + createComponent([ + [getPipelineDetailsQuery, successHandler], + [deletePipelineMutation, deleteMutationHandlerFailed], + ]); + + await waitForPromises(); + + findDeleteModal().vm.$emit('primary'); + + await waitForPromises(); + + expect(findAlert().exists()).toBe(true); + }); + }); + }); }); |