diff options
Diffstat (limited to 'spec/frontend/jobs')
-rw-r--r-- | spec/frontend/jobs/components/job_app_spec.js | 4 | ||||
-rw-r--r-- | spec/frontend/jobs/components/table/cells/actions_cell_spec.js | 126 | ||||
-rw-r--r-- | spec/frontend/jobs/components/table/cells/duration_cell_spec.js (renamed from spec/frontend/jobs/components/table/cells.vue/duration_cell_spec.js) | 0 | ||||
-rw-r--r-- | spec/frontend/jobs/components/table/cells/job_cell_spec.js (renamed from spec/frontend/jobs/components/table/cells.vue/job_cell_spec.js) | 0 | ||||
-rw-r--r-- | spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js (renamed from spec/frontend/jobs/components/table/cells.vue/pipeline_cell_spec.js) | 0 | ||||
-rw-r--r-- | spec/frontend/jobs/mock_data.js | 182 |
6 files changed, 309 insertions, 3 deletions
diff --git a/spec/frontend/jobs/components/job_app_spec.js b/spec/frontend/jobs/components/job_app_spec.js index 1f4dd7d6216..f8a0059bf21 100644 --- a/spec/frontend/jobs/components/job_app_spec.js +++ b/spec/frontend/jobs/components/job_app_spec.js @@ -140,7 +140,7 @@ describe('Job App', () => { it('should render provided job information', () => { expect(wrapper.find('.header-main-content').text().replace(/\s+/g, ' ').trim()).toContain( - 'passed Job #4757 triggered 1 year ago by Root', + 'passed Job test triggered 1 year ago by Root', ); }); @@ -154,7 +154,7 @@ describe('Job App', () => { setupAndMount().then(() => { expect( wrapper.find('.header-main-content').text().replace(/\s+/g, ' ').trim(), - ).toContain('passed Job #4757 created 3 weeks ago by Root'); + ).toContain('passed Job test created 3 weeks ago by Root'); })); }); }); diff --git a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js new file mode 100644 index 00000000000..1b1e2d4df8f --- /dev/null +++ b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js @@ -0,0 +1,126 @@ +import { GlModal } from '@gitlab/ui'; +import { nextTick } from 'vue'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import ActionsCell from '~/jobs/components/table/cells/actions_cell.vue'; +import JobPlayMutation from '~/jobs/components/table/graphql/mutations/job_play.mutation.graphql'; +import JobRetryMutation from '~/jobs/components/table/graphql/mutations/job_retry.mutation.graphql'; +import JobUnscheduleMutation from '~/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql'; +import { playableJob, retryableJob, scheduledJob } from '../../../mock_data'; + +describe('Job actions cell', () => { + let wrapper; + let mutate; + + const findRetryButton = () => wrapper.findByTestId('retry'); + const findPlayButton = () => wrapper.findByTestId('play'); + const findDownloadArtifactsButton = () => wrapper.findByTestId('download-artifacts'); + const findCountdownButton = () => wrapper.findByTestId('countdown'); + const findPlayScheduledJobButton = () => wrapper.findByTestId('play-scheduled'); + const findUnscheduleButton = () => wrapper.findByTestId('unschedule'); + + const findModal = () => wrapper.findComponent(GlModal); + + const MUTATION_SUCCESS = { data: { JobRetryMutation: { jobId: retryableJob.id } } }; + const MUTATION_SUCCESS_UNSCHEDULE = { + data: { JobUnscheduleMutation: { jobId: scheduledJob.id } }, + }; + const MUTATION_SUCCESS_PLAY = { data: { JobPlayMutation: { jobId: playableJob.id } } }; + + const $toast = { + show: jest.fn(), + }; + + const createComponent = (jobType, mutationType = MUTATION_SUCCESS, props = {}) => { + mutate = jest.fn().mockResolvedValue(mutationType); + + wrapper = shallowMountExtended(ActionsCell, { + propsData: { + job: jobType, + ...props, + }, + mocks: { + $apollo: { + mutate, + }, + $toast, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + it('does not display an artifacts download button', () => { + createComponent(retryableJob); + + expect(findDownloadArtifactsButton().exists()).toBe(false); + }); + + it.each` + button | action | jobType + ${findPlayButton} | ${'play'} | ${playableJob} + ${findRetryButton} | ${'retry'} | ${retryableJob} + ${findDownloadArtifactsButton} | ${'download artifacts'} | ${playableJob} + `('displays the $action button', ({ button, jobType }) => { + createComponent(jobType); + + expect(button().exists()).toBe(true); + }); + + it.each` + button | mutationResult | action | jobType | mutationFile + ${findPlayButton} | ${MUTATION_SUCCESS_PLAY} | ${'play'} | ${playableJob} | ${JobPlayMutation} + ${findRetryButton} | ${MUTATION_SUCCESS} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} + `('performs the $action mutation', ({ button, mutationResult, jobType, mutationFile }) => { + createComponent(jobType, mutationResult); + + button().vm.$emit('click'); + + expect(mutate).toHaveBeenCalledWith({ + mutation: mutationFile, + variables: { + id: jobType.id, + }, + }); + }); + + describe('Scheduled Jobs', () => { + const today = () => new Date('2021-08-31'); + + beforeEach(() => { + jest.spyOn(Date, 'now').mockImplementation(today); + }); + + it('displays the countdown, play and unschedule buttons', () => { + createComponent(scheduledJob); + + expect(findCountdownButton().exists()).toBe(true); + expect(findPlayScheduledJobButton().exists()).toBe(true); + expect(findUnscheduleButton().exists()).toBe(true); + }); + + it('unschedules a job', () => { + createComponent(scheduledJob, MUTATION_SUCCESS_UNSCHEDULE); + + findUnscheduleButton().vm.$emit('click'); + + expect(mutate).toHaveBeenCalledWith({ + mutation: JobUnscheduleMutation, + variables: { + id: scheduledJob.id, + }, + }); + }); + + it('shows the play job confirmation modal', async () => { + createComponent(scheduledJob, MUTATION_SUCCESS); + + findPlayScheduledJobButton().vm.$emit('click'); + + await nextTick(); + + expect(findModal().exists()).toBe(true); + }); + }); +}); diff --git a/spec/frontend/jobs/components/table/cells.vue/duration_cell_spec.js b/spec/frontend/jobs/components/table/cells/duration_cell_spec.js index 763a4b0eaa2..763a4b0eaa2 100644 --- a/spec/frontend/jobs/components/table/cells.vue/duration_cell_spec.js +++ b/spec/frontend/jobs/components/table/cells/duration_cell_spec.js diff --git a/spec/frontend/jobs/components/table/cells.vue/job_cell_spec.js b/spec/frontend/jobs/components/table/cells/job_cell_spec.js index fc4e5586349..fc4e5586349 100644 --- a/spec/frontend/jobs/components/table/cells.vue/job_cell_spec.js +++ b/spec/frontend/jobs/components/table/cells/job_cell_spec.js diff --git a/spec/frontend/jobs/components/table/cells.vue/pipeline_cell_spec.js b/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js index 1f5e0a7aa21..1f5e0a7aa21 100644 --- a/spec/frontend/jobs/components/table/cells.vue/pipeline_cell_spec.js +++ b/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js index 57f0b852ff8..43755b46bc9 100644 --- a/spec/frontend/jobs/mock_data.js +++ b/spec/frontend/jobs/mock_data.js @@ -1555,7 +1555,11 @@ export const mockJobsQueryResponse = { cancelable: false, active: false, stuck: false, - userPermissions: { readBuild: true, __typename: 'JobPermissions' }, + userPermissions: { + readBuild: true, + readJobArtifacts: true, + __typename: 'JobPermissions', + }, __typename: 'CiJob', }, ], @@ -1573,3 +1577,179 @@ export const mockJobsQueryEmptyResponse = { }, }, }; + +export const retryableJob = { + artifacts: { nodes: [], __typename: 'CiJobArtifactConnection' }, + allowFailure: false, + status: 'SUCCESS', + scheduledAt: null, + manualJob: false, + triggered: null, + createdByTag: false, + detailedStatus: { + detailsPath: '/root/test-job-artifacts/-/jobs/1981', + group: 'success', + icon: 'status_success', + label: 'passed', + text: 'passed', + tooltip: 'passed', + action: { + buttonTitle: 'Retry this job', + icon: 'retry', + method: 'post', + path: '/root/test-job-artifacts/-/jobs/1981/retry', + title: 'Retry', + __typename: 'StatusAction', + }, + __typename: 'DetailedStatus', + }, + id: 'gid://gitlab/Ci::Build/1981', + refName: 'main', + refPath: '/root/test-job-artifacts/-/commits/main', + tags: [], + shortSha: '75daf01b', + commitPath: '/root/test-job-artifacts/-/commit/75daf01b465e7eab5a04a315e44660c9a17c8055', + pipeline: { + id: 'gid://gitlab/Ci::Pipeline/288', + path: '/root/test-job-artifacts/-/pipelines/288', + user: { + webPath: '/root', + avatarUrl: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + __typename: 'UserCore', + }, + __typename: 'Pipeline', + }, + stage: { name: 'test', __typename: 'CiStage' }, + name: 'hello_world', + duration: 7, + finishedAt: '2021-08-30T20:33:56Z', + coverage: null, + retryable: true, + playable: false, + cancelable: false, + active: false, + stuck: false, + userPermissions: { readBuild: true, __typename: 'JobPermissions' }, + __typename: 'CiJob', +}; + +export const playableJob = { + artifacts: { + nodes: [ + { + downloadPath: '/root/test-job-artifacts/-/jobs/1982/artifacts/download?file_type=trace', + __typename: 'CiJobArtifact', + }, + ], + __typename: 'CiJobArtifactConnection', + }, + allowFailure: false, + status: 'SUCCESS', + scheduledAt: null, + manualJob: true, + triggered: null, + createdByTag: false, + detailedStatus: { + detailsPath: '/root/test-job-artifacts/-/jobs/1982', + group: 'success', + icon: 'status_success', + label: 'manual play action', + text: 'passed', + tooltip: 'passed', + action: { + buttonTitle: 'Trigger this manual action', + icon: 'play', + method: 'post', + path: '/root/test-job-artifacts/-/jobs/1982/play', + title: 'Play', + __typename: 'StatusAction', + }, + __typename: 'DetailedStatus', + }, + id: 'gid://gitlab/Ci::Build/1982', + refName: 'main', + refPath: '/root/test-job-artifacts/-/commits/main', + tags: [], + shortSha: '75daf01b', + commitPath: '/root/test-job-artifacts/-/commit/75daf01b465e7eab5a04a315e44660c9a17c8055', + pipeline: { + id: 'gid://gitlab/Ci::Pipeline/288', + path: '/root/test-job-artifacts/-/pipelines/288', + user: { + webPath: '/root', + avatarUrl: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + __typename: 'UserCore', + }, + __typename: 'Pipeline', + }, + stage: { name: 'test', __typename: 'CiStage' }, + name: 'hello_world_delayed', + duration: 6, + finishedAt: '2021-08-30T20:36:12Z', + coverage: null, + retryable: true, + playable: true, + cancelable: false, + active: false, + stuck: false, + userPermissions: { readBuild: true, readJobArtifacts: true, __typename: 'JobPermissions' }, + __typename: 'CiJob', +}; + +export const scheduledJob = { + artifacts: { nodes: [], __typename: 'CiJobArtifactConnection' }, + allowFailure: false, + status: 'SCHEDULED', + scheduledAt: '2021-08-31T22:36:05Z', + manualJob: true, + triggered: null, + createdByTag: false, + detailedStatus: { + detailsPath: '/root/test-job-artifacts/-/jobs/1986', + group: 'scheduled', + icon: 'status_scheduled', + label: 'unschedule action', + text: 'delayed', + tooltip: 'delayed manual action (%{remainingTime})', + action: { + buttonTitle: 'Unschedule job', + icon: 'time-out', + method: 'post', + path: '/root/test-job-artifacts/-/jobs/1986/unschedule', + title: 'Unschedule', + __typename: 'StatusAction', + }, + __typename: 'DetailedStatus', + }, + id: 'gid://gitlab/Ci::Build/1986', + refName: 'main', + refPath: '/root/test-job-artifacts/-/commits/main', + tags: [], + shortSha: '75daf01b', + commitPath: '/root/test-job-artifacts/-/commit/75daf01b465e7eab5a04a315e44660c9a17c8055', + pipeline: { + id: 'gid://gitlab/Ci::Pipeline/290', + path: '/root/test-job-artifacts/-/pipelines/290', + user: { + webPath: '/root', + avatarUrl: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + __typename: 'UserCore', + }, + __typename: 'Pipeline', + }, + stage: { name: 'test', __typename: 'CiStage' }, + name: 'hello_world_delayed', + duration: null, + finishedAt: null, + coverage: null, + retryable: false, + playable: true, + cancelable: false, + active: false, + stuck: false, + userPermissions: { readBuild: true, __typename: 'JobPermissions' }, + __typename: 'CiJob', +}; |