Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/ci/jobs_page/components/job_cells/actions_cell_spec.js')
-rw-r--r--spec/frontend/ci/jobs_page/components/job_cells/actions_cell_spec.js240
1 files changed, 240 insertions, 0 deletions
diff --git a/spec/frontend/ci/jobs_page/components/job_cells/actions_cell_spec.js b/spec/frontend/ci/jobs_page/components/job_cells/actions_cell_spec.js
new file mode 100644
index 00000000000..1ffd680118e
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/components/job_cells/actions_cell_spec.js
@@ -0,0 +1,240 @@
+import { GlModal } from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import ActionsCell from '~/ci/jobs_page/components/job_cells/actions_cell.vue';
+import eventHub from '~/ci/jobs_page/event_hub';
+import JobPlayMutation from '~/ci/jobs_page/graphql/mutations/job_play.mutation.graphql';
+import JobRetryMutation from '~/ci/jobs_page/graphql/mutations/job_retry.mutation.graphql';
+import JobUnscheduleMutation from '~/ci/jobs_page/graphql/mutations/job_unschedule.mutation.graphql';
+import JobCancelMutation from '~/ci/jobs_page/graphql/mutations/job_cancel.mutation.graphql';
+import {
+ mockJobsNodes,
+ mockJobsNodesAsGuest,
+ playMutationResponse,
+ retryMutationResponse,
+ unscheduleMutationResponse,
+ cancelMutationResponse,
+} from 'jest/ci/jobs_mock_data';
+
+jest.mock('~/lib/utils/url_utility');
+
+Vue.use(VueApollo);
+
+describe('Job actions cell', () => {
+ let wrapper;
+
+ const findMockJob = (jobName, nodes = mockJobsNodes) => {
+ const job = nodes.find(({ name }) => name === jobName);
+ expect(job).toBeDefined(); // ensure job is present
+ return job;
+ };
+
+ const mockJob = findMockJob('build');
+ const cancelableJob = findMockJob('cancelable');
+ const playableJob = findMockJob('playable');
+ const retryableJob = findMockJob('retryable');
+ const failedJob = findMockJob('failed');
+ const scheduledJob = findMockJob('scheduled');
+ const jobWithArtifact = findMockJob('with_artifact');
+ const cannotPlayJob = findMockJob('playable', mockJobsNodesAsGuest);
+ const cannotRetryJob = findMockJob('retryable', mockJobsNodesAsGuest);
+ const cannotPlayScheduledJob = findMockJob('scheduled', mockJobsNodesAsGuest);
+
+ const findRetryButton = () => wrapper.findByTestId('retry');
+ const findPlayButton = () => wrapper.findByTestId('play');
+ const findCancelButton = () => wrapper.findByTestId('cancel-button');
+ 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 playMutationHandler = jest.fn().mockResolvedValue(playMutationResponse);
+ const retryMutationHandler = jest.fn().mockResolvedValue(retryMutationResponse);
+ const unscheduleMutationHandler = jest.fn().mockResolvedValue(unscheduleMutationResponse);
+ const cancelMutationHandler = jest.fn().mockResolvedValue(cancelMutationResponse);
+
+ const $toast = {
+ show: jest.fn(),
+ };
+
+ const createMockApolloProvider = (requestHandlers) => {
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = (job, requestHandlers, props = {}) => {
+ wrapper = shallowMountExtended(ActionsCell, {
+ propsData: {
+ job,
+ ...props,
+ },
+ apolloProvider: createMockApolloProvider(requestHandlers),
+ mocks: {
+ $toast,
+ },
+ });
+ };
+
+ it('displays the artifacts download button with correct link', () => {
+ createComponent(jobWithArtifact);
+
+ expect(findDownloadArtifactsButton().attributes('href')).toBe(
+ jobWithArtifact.artifacts.nodes[0].downloadPath,
+ );
+ });
+
+ it('does not display an artifacts download button', () => {
+ createComponent(mockJob);
+
+ expect(findDownloadArtifactsButton().exists()).toBe(false);
+ });
+
+ it.each`
+ button | action | jobType
+ ${findPlayButton} | ${'play'} | ${cannotPlayJob}
+ ${findRetryButton} | ${'retry'} | ${cannotRetryJob}
+ ${findPlayScheduledJobButton} | ${'play scheduled'} | ${cannotPlayScheduledJob}
+ `('does not display the $action button if user cannot update build', ({ button, jobType }) => {
+ createComponent(jobType);
+
+ expect(button().exists()).toBe(false);
+ });
+
+ it.each`
+ button | action | jobType
+ ${findPlayButton} | ${'play'} | ${playableJob}
+ ${findRetryButton} | ${'retry'} | ${retryableJob}
+ ${findDownloadArtifactsButton} | ${'download artifacts'} | ${jobWithArtifact}
+ ${findCancelButton} | ${'cancel'} | ${cancelableJob}
+ `('displays the $action button', ({ button, jobType }) => {
+ createComponent(jobType);
+
+ expect(button().exists()).toBe(true);
+ });
+
+ it.each`
+ button | action | jobType | mutationFile | handler | jobId
+ ${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${playableJob.id}
+ ${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${retryableJob.id}
+ ${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler} | ${cancelableJob.id}
+ `('performs the $action mutation', ({ button, jobType, mutationFile, handler, jobId }) => {
+ createComponent(jobType, [[mutationFile, handler]]);
+
+ button().vm.$emit('click');
+
+ expect(handler).toHaveBeenCalledWith({ id: jobId });
+ });
+
+ it.each`
+ button | action | jobType | mutationFile | handler
+ ${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob} | ${JobUnscheduleMutation} | ${unscheduleMutationHandler}
+ ${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler}
+ `(
+ 'the mutation action $action emits the jobActionPerformed event',
+ async ({ button, jobType, mutationFile, handler }) => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+
+ createComponent(jobType, [[mutationFile, handler]]);
+
+ button().vm.$emit('click');
+
+ await waitForPromises();
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('jobActionPerformed');
+ expect(redirectTo).not.toHaveBeenCalled(); // eslint-disable-line import/no-deprecated
+ },
+ );
+
+ it.each`
+ button | action | jobType | mutationFile | handler | redirectLink
+ ${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${'/root/project/-/jobs/1986'}
+ ${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${'/root/project/-/jobs/1985'}
+ `(
+ 'the mutation action $action redirects to the job',
+ async ({ button, jobType, mutationFile, handler, redirectLink }) => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+
+ createComponent(jobType, [[mutationFile, handler]]);
+
+ button().vm.$emit('click');
+
+ await waitForPromises();
+
+ expect(redirectTo).toHaveBeenCalledWith(redirectLink); // eslint-disable-line import/no-deprecated
+ expect(eventHub.$emit).not.toHaveBeenCalled();
+ },
+ );
+
+ it.each`
+ button | action | jobType
+ ${findPlayButton} | ${'play'} | ${playableJob}
+ ${findRetryButton} | ${'retry'} | ${retryableJob}
+ ${findCancelButton} | ${'cancel'} | ${cancelableJob}
+ ${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob}
+ `('disables the $action button after first request', async ({ button, jobType }) => {
+ createComponent(jobType);
+
+ expect(button().props('disabled')).toBe(false);
+
+ button().vm.$emit('click');
+
+ await waitForPromises();
+
+ expect(button().props('disabled')).toBe(true);
+ });
+
+ describe('Retry button title', () => {
+ it('displays retry title when job has failed and is retryable', () => {
+ createComponent(failedJob);
+
+ expect(findRetryButton().attributes('title')).toBe('Retry');
+ });
+
+ it('displays run again title when job has passed and is retryable', () => {
+ createComponent(retryableJob);
+
+ expect(findRetryButton().attributes('title')).toBe('Run again');
+ });
+ });
+
+ 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, [[JobUnscheduleMutation, unscheduleMutationHandler]]);
+
+ findUnscheduleButton().vm.$emit('click');
+
+ expect(unscheduleMutationHandler).toHaveBeenCalledWith({
+ id: scheduledJob.id,
+ });
+ });
+
+ it('shows the play job confirmation modal', async () => {
+ createComponent(scheduledJob);
+
+ findPlayScheduledJobButton().vm.$emit('click');
+
+ await nextTick();
+
+ expect(findModal().exists()).toBe(true);
+ });
+ });
+});