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:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-06-14 21:08:38 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-14 21:08:38 +0300
commit14160fad80415337f8c08755af53ee994b4a7518 (patch)
treebfe1bf6bad8cda3e3bbf905c9d8ac742420dd8a3 /spec/frontend/pipelines
parent7a33080fff9a735cbe77968d67b13ffa92c0ffae (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/pipelines')
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/failure_widget/mock.js45
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget_spec.js97
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/failure_widget/utils_spec.js58
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/failure_widget/widget_failed_job_row_spec.js43
4 files changed, 241 insertions, 2 deletions
diff --git a/spec/frontend/pipelines/components/pipelines_list/failure_widget/mock.js b/spec/frontend/pipelines/components/pipelines_list/failure_widget/mock.js
new file mode 100644
index 00000000000..a4c90fa3876
--- /dev/null
+++ b/spec/frontend/pipelines/components/pipelines_list/failure_widget/mock.js
@@ -0,0 +1,45 @@
+export const job = {
+ id: 'gid://gitlab/Ci::Build/5241',
+ allowFailure: false,
+ detailedStatus: {
+ id: 'status',
+ action: {
+ id: 'action',
+ path: '/retry',
+ icon: 'retry',
+ },
+ group: 'running',
+ icon: 'running-icon',
+ },
+ name: 'job-name',
+ retried: false,
+ stage: {
+ id: '1',
+ name: 'build',
+ },
+ trace: {
+ htmlSummary:
+ '<span>To install the missing version, run `gem install bundler:2.4.13`<br/>\tfrom /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems.rb:302:in `activate_bin_path\'<br/>\tfrom /usr/bin/bundle:23:in `&lt;main>\'<br/></span><div class="section-start" data-timestamp="1685044123" data-section="upload-artifacts-on-failure" role="button"></div><span class="term-fg-l-cyan term-bold section section-header js-s-upload-artifacts-on-failure">Uploading artifacts for failed job</span><span class="section section-header js-s-upload-artifacts-on-failure"><br/></span><span class="term-fg-l-green term-bold section line js-s-upload-artifacts-on-failure">Uploading artifacts...</span><span class="section line js-s-upload-artifacts-on-failure"><br/>Runtime platform </span><span class="section line js-s-upload-artifacts-on-failure"> arch</span><span class="section line js-s-upload-artifacts-on-failure">=arm64 os</span><span class="section line js-s-upload-artifacts-on-failure">=darwin pid</span><span class="section line js-s-upload-artifacts-on-failure">=16706 revision</span><span class="section line js-s-upload-artifacts-on-failure">=43b2dc3d version</span><span class="section line js-s-upload-artifacts-on-failure">=15.4.0<br/></span><span class="term-fg-yellow section line js-s-upload-artifacts-on-failure">WARNING: rspec.xml: no matching files. Ensure that the artifact path is relative to the working directory</span><span class="section line js-s-upload-artifacts-on-failure"> <br/></span><span class="term-fg-l-red term-bold section line js-s-upload-artifacts-on-failure">ERROR: No files to upload </span><span class="section line js-s-upload-artifacts-on-failure"> <br/></span><div class="section-end" data-section="upload-artifacts-on-failure"></div><span class="term-fg-l-red term-bold">ERROR: Job failed: exit status 1<br/></span><span><br/></span>',
+ },
+ webPath: '/',
+};
+
+export const allowedToFailJob = {
+ ...job,
+ id: 'gid://gitlab/Ci::Build/5242',
+ allowFailure: true,
+};
+
+export const failedJobsMock = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/20',
+ pipeline: {
+ id: 'gid://gitlab/Pipeline/20',
+ jobs: {
+ nodes: [allowedToFailJob, job],
+ },
+ },
+ },
+ },
+};
diff --git a/spec/frontend/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget_spec.js b/spec/frontend/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget_spec.js
index 56e3e11d936..df6d114f683 100644
--- a/spec/frontend/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget_spec.js
+++ b/spec/frontend/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget_spec.js
@@ -1,11 +1,26 @@
-import { GlIcon, GlPopover } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+
+import { GlButton, GlIcon, GlLoadingIcon, GlPopover } from '@gitlab/ui';
+import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import PipelineFailedJobsWidget from '~/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget.vue';
+import { createAlert } from '~/alert';
+import WidgetFailedJobRow from '~/pipelines/components/pipelines_list/failure_widget/widget_failed_job_row.vue';
+import * as utils from '~/pipelines/components/pipelines_list/failure_widget/utils';
+import getPipelineFailedJobs from '~/pipelines/graphql/queries/get_pipeline_failed_jobs.query.graphql';
+import { failedJobsMock } from './mock';
+
+Vue.use(VueApollo);
+jest.mock('~/alert');
describe('PipelineFailedJobsWidget component', () => {
let wrapper;
+ let mockFailedJobsResponse;
const defaultProps = {
+ pipelineIid: 1,
pipelinePath: '/pipelines/1',
};
@@ -14,6 +29,9 @@ describe('PipelineFailedJobsWidget component', () => {
};
const createComponent = ({ props = {}, provide } = {}) => {
+ const handlers = [[getPipelineFailedJobs, mockFailedJobsResponse]];
+ const mockApollo = createMockApollo(handlers);
+
wrapper = shallowMountExtended(PipelineFailedJobsWidget, {
propsData: {
...defaultProps,
@@ -23,12 +41,20 @@ describe('PipelineFailedJobsWidget component', () => {
...defaultProvide,
...provide,
},
+ apolloProvider: mockApollo,
});
};
- const findFailedJobsButton = () => wrapper.findByText('Show failed jobs');
+ const findAllHeaders = () => wrapper.findAllByTestId('header');
+ const findFailedJobsButton = () => wrapper.findComponent(GlButton);
+ const findFailedJobRows = () => wrapper.findAllComponents(WidgetFailedJobRow);
const findInfoIcon = () => wrapper.findComponent(GlIcon);
const findInfoPopover = () => wrapper.findComponent(GlPopover);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+
+ beforeEach(() => {
+ mockFailedJobsResponse = jest.fn();
+ });
describe('ui', () => {
beforeEach(() => {
@@ -47,5 +73,72 @@ describe('PipelineFailedJobsWidget component', () => {
it('renders the info popover', () => {
expect(findInfoPopover().exists()).toBe(true);
});
+
+ it('does not show the list of failed jobs', () => {
+ expect(findFailedJobRows()).toHaveLength(0);
+ });
+ });
+
+ describe('when loading failed jobs', () => {
+ beforeEach(async () => {
+ mockFailedJobsResponse.mockResolvedValue(failedJobsMock);
+ createComponent();
+ await findFailedJobsButton().vm.$emit('click');
+ });
+
+ it('shows a loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('when failed jobs have loaded', () => {
+ beforeEach(async () => {
+ mockFailedJobsResponse.mockResolvedValue(failedJobsMock);
+ jest.spyOn(utils, 'sortJobsByStatus');
+
+ createComponent();
+
+ await findFailedJobsButton().vm.$emit('click');
+ await waitForPromises();
+ });
+ it('does not renders a loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('renders table column', () => {
+ expect(findAllHeaders()).toHaveLength(3);
+ });
+
+ it('shows the list of failed jobs', () => {
+ expect(findFailedJobRows()).toHaveLength(
+ failedJobsMock.data.project.pipeline.jobs.nodes.length,
+ );
+ });
+
+ it('calls sortJobsByStatus', () => {
+ expect(utils.sortJobsByStatus).toHaveBeenCalledWith(
+ failedJobsMock.data.project.pipeline.jobs.nodes,
+ );
+ });
+ });
+
+ describe('when an error occurs loading jobs', () => {
+ const errorMessage = "We couldn't fetch jobs for you because you are not qualified";
+
+ beforeEach(async () => {
+ mockFailedJobsResponse.mockRejectedValue({ message: errorMessage });
+
+ createComponent();
+
+ await findFailedJobsButton().vm.$emit('click');
+ await waitForPromises();
+ });
+ it('does not renders a loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('calls create Alert with the error message and danger variant', () => {
+ expect(createAlert).toHaveBeenCalledWith({ message: errorMessage, variant: 'danger' });
+ });
});
});
diff --git a/spec/frontend/pipelines/components/pipelines_list/failure_widget/utils_spec.js b/spec/frontend/pipelines/components/pipelines_list/failure_widget/utils_spec.js
new file mode 100644
index 00000000000..44f16478151
--- /dev/null
+++ b/spec/frontend/pipelines/components/pipelines_list/failure_widget/utils_spec.js
@@ -0,0 +1,58 @@
+import {
+ isFailedJob,
+ sortJobsByStatus,
+} from '~/pipelines/components/pipelines_list/failure_widget/utils';
+
+describe('isFailedJob', () => {
+ describe('when the job argument is undefined', () => {
+ it('returns false', () => {
+ expect(isFailedJob()).toBe(false);
+ });
+ });
+
+ describe('when the job is of status `failed`', () => {
+ it('returns false', () => {
+ expect(isFailedJob({ detailedStatus: { group: 'success' } })).toBe(false);
+ });
+ });
+
+ describe('when the job status is `failed`', () => {
+ it('returns true', () => {
+ expect(isFailedJob({ detailedStatus: { group: 'failed' } })).toBe(true);
+ });
+ });
+});
+
+describe('sortJobsByStatus', () => {
+ describe('when the arg is undefined', () => {
+ it('returns an empty array', () => {
+ expect(sortJobsByStatus()).toEqual([]);
+ });
+ });
+
+ describe('when receiving an empty array', () => {
+ it('returns an empty array', () => {
+ expect(sortJobsByStatus([])).toEqual([]);
+ });
+ });
+
+ describe('when reciving a list of jobs', () => {
+ const jobArr = [
+ { detailedStatus: { group: 'failed' } },
+ { detailedStatus: { group: 'allowed_to_fail' } },
+ { detailedStatus: { group: 'failed' } },
+ { detailedStatus: { group: 'success' } },
+ ];
+
+ const expectedResult = [
+ { detailedStatus: { group: 'failed' } },
+ { detailedStatus: { group: 'failed' } },
+ { detailedStatus: { group: 'allowed_to_fail' } },
+ { detailedStatus: { group: 'success' } },
+ ];
+
+ it('sorts failed jobs first', () => {
+ expect(sortJobsByStatus(jobArr)).toEqual(expectedResult);
+ });
+ });
+});
diff --git a/spec/frontend/pipelines/components/pipelines_list/failure_widget/widget_failed_job_row_spec.js b/spec/frontend/pipelines/components/pipelines_list/failure_widget/widget_failed_job_row_spec.js
new file mode 100644
index 00000000000..63f5d80e95e
--- /dev/null
+++ b/spec/frontend/pipelines/components/pipelines_list/failure_widget/widget_failed_job_row_spec.js
@@ -0,0 +1,43 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import WidgetFailedJobRow from '~/pipelines/components/pipelines_list/failure_widget/widget_failed_job_row.vue';
+
+describe('WidgetFailedJobRow component', () => {
+ let wrapper;
+
+ const defaultProps = {
+ job: {
+ id: 'gid://gitlab/Ci::Build/5240',
+ detailedStatus: {
+ group: 'running',
+ icon: 'icon_status_running',
+ },
+ name: 'my-job',
+ stage: {
+ name: 'build',
+ },
+ trace: {
+ htmlSummary: '<h1>job log</h1>',
+ },
+ webpath: '/',
+ },
+ };
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMountExtended(WidgetFailedJobRow, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ describe('ui', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the job name', () => {
+ expect(wrapper.html()).toContain(defaultProps.job.name);
+ });
+ });
+});