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/commit')
-rw-r--r--spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js216
-rw-r--r--spec/frontend/commit/commit_pipeline_status_component_spec.js4
-rw-r--r--spec/frontend/commit/mock_data.js211
-rw-r--r--spec/frontend/commit/pipelines/pipelines_table_spec.js27
4 files changed, 332 insertions, 126 deletions
diff --git a/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js b/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
index b1c8ba48475..fddc767953a 100644
--- a/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
+++ b/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
@@ -1,14 +1,24 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
+import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import createMockApollo from 'helpers/mock_apollo_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import CommitBoxPipelineMiniGraph from '~/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue';
+import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
+import { COMMIT_BOX_POLL_INTERVAL } from '~/projects/commit_box/info/constants';
import getLinkedPipelinesQuery from '~/projects/commit_box/info/graphql/queries/get_linked_pipelines.query.graphql';
import getPipelineStagesQuery from '~/projects/commit_box/info/graphql/queries/get_pipeline_stages.query.graphql';
-import { mockPipelineStagesQueryResponse, mockStages } from './mock_data';
+import * as graphQlUtils from '~/pipelines/components/graph/utils';
+import {
+ mockDownstreamQueryResponse,
+ mockPipelineStagesQueryResponse,
+ mockStages,
+ mockUpstreamDownstreamQueryResponse,
+ mockUpstreamQueryResponse,
+} from './mock_data';
jest.mock('~/flash');
@@ -17,61 +27,219 @@ Vue.use(VueApollo);
describe('Commit box pipeline mini graph', () => {
let wrapper;
- const findMiniGraph = () => wrapper.findByTestId('commit-box-mini-graph');
- const findUpstream = () => wrapper.findByTestId('commit-box-mini-graph-upstream');
- const findDownstream = () => wrapper.findByTestId('commit-box-mini-graph-downstream');
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findPipelineMiniGraph = () => wrapper.findComponent(PipelineMiniGraph);
+ const downstreamHandler = jest.fn().mockResolvedValue(mockDownstreamQueryResponse);
+ const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
const stagesHandler = jest.fn().mockResolvedValue(mockPipelineStagesQueryResponse);
+ const upstreamDownstreamHandler = jest
+ .fn()
+ .mockResolvedValue(mockUpstreamDownstreamQueryResponse);
+ const upstreamHandler = jest.fn().mockResolvedValue(mockUpstreamQueryResponse);
+ const advanceToNextFetch = () => {
+ jest.advanceTimersByTime(COMMIT_BOX_POLL_INTERVAL);
+ };
- const createComponent = ({ props = {} } = {}) => {
- const handlers = [
- [getLinkedPipelinesQuery, {}],
+ const fullPath = 'gitlab-org/gitlab';
+ const iid = '315';
+ const createMockApolloProvider = (handler = downstreamHandler) => {
+ const requestHandlers = [
+ [getLinkedPipelinesQuery, handler],
[getPipelineStagesQuery, stagesHandler],
];
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = (handler) => {
wrapper = extendedWrapper(
shallowMount(CommitBoxPipelineMiniGraph, {
propsData: {
stages: mockStages,
- ...props,
},
- apolloProvider: createMockApollo(handlers),
+ provide: {
+ fullPath,
+ iid,
+ dataMethod: 'graphql',
+ graphqlResourceEtag: '/api/graphql:pipelines/id/320',
+ },
+ apolloProvider: createMockApolloProvider(handler),
}),
);
-
- return waitForPromises();
};
afterEach(() => {
wrapper.destroy();
});
- describe('linked pipelines', () => {
+ describe('loading state', () => {
+ it('should display loading state when loading', () => {
+ createComponent();
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ expect(findPipelineMiniGraph().exists()).toBe(false);
+ });
+ });
+
+ describe('loaded state', () => {
beforeEach(async () => {
await createComponent();
});
- it('should display the mini pipeine graph', () => {
- expect(findMiniGraph().exists()).toBe(true);
+ it('should not display loading state after the query is resolved', async () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ expect(findPipelineMiniGraph().exists()).toBe(true);
});
- it('should not display linked pipelines', () => {
- expect(findUpstream().exists()).toBe(false);
- expect(findDownstream().exists()).toBe(false);
+ it('should display the pipeline mini graph', () => {
+ expect(findPipelineMiniGraph().exists()).toBe(true);
});
});
- describe('when data is mismatched', () => {
- beforeEach(async () => {
- await createComponent({ props: { stages: [] } });
+ describe('load upstream/downstream', () => {
+ const samplePipeline = {
+ __typename: expect.any(String),
+ id: expect.any(String),
+ path: expect.any(String),
+ project: expect.any(Object),
+ detailedStatus: expect.any(Object),
+ };
+
+ it('formatted stages should be passed to the pipeline mini graph', async () => {
+ const stage = mockStages[0];
+ const expectedStages = [
+ {
+ name: stage.name,
+ status: {
+ __typename: 'DetailedStatus',
+ id: stage.status.id,
+ icon: stage.status.icon,
+ group: stage.status.group,
+ },
+ dropdown_path: stage.dropdown_path,
+ title: stage.title,
+ },
+ ];
+
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findPipelineMiniGraph().props('stages')).toEqual(expectedStages);
+ });
+
+ it('should render a downstream pipeline only', async () => {
+ createComponent(downstreamHandler);
+
+ await waitForPromises();
+
+ const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
+ const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
+
+ expect(downstreamPipelines).toEqual(expect.any(Array));
+ expect(upstreamPipeline).toEqual(null);
+ });
+
+ it('should pass the pipeline path prop for the counter badge', async () => {
+ createComponent(downstreamHandler);
+
+ await waitForPromises();
+
+ const expectedPath = mockDownstreamQueryResponse.data.project.pipeline.path;
+ const pipelinePath = findPipelineMiniGraph().props('pipelinePath');
+
+ expect(pipelinePath).toBe(expectedPath);
+ });
+
+ it('should render an upstream pipeline only', async () => {
+ createComponent(upstreamHandler);
+
+ await waitForPromises();
+
+ const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
+ const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
+
+ expect(upstreamPipeline).toEqual(samplePipeline);
+ expect(downstreamPipelines).toHaveLength(0);
});
- it('calls create flash with expected arguments', () => {
+ it('should render downstream and upstream pipelines', async () => {
+ createComponent(upstreamDownstreamHandler);
+
+ await waitForPromises();
+
+ const downstreamPipelines = findPipelineMiniGraph().props('downstreamPipelines');
+ const upstreamPipeline = findPipelineMiniGraph().props('upstreamPipeline');
+
+ expect(upstreamPipeline).toEqual(samplePipeline);
+ expect(downstreamPipelines).toEqual(expect.arrayContaining([samplePipeline]));
+ });
+ });
+
+ describe('error state', () => {
+ it('createFlash should show if there is an error fetching the data', async () => {
+ createComponent({ handler: failedHandler });
+
+ await waitForPromises();
+
expect(createFlash).toHaveBeenCalledWith({
- message: 'There was a problem handling the pipeline data.',
- captureError: true,
- error: new Error('Rest stages and graphQl stages must be the same length'),
+ message: 'There was a problem fetching linked pipelines.',
});
});
});
+
+ describe('polling', () => {
+ it('polling interval is set for linked pipelines', () => {
+ createComponent();
+
+ const expectedInterval = wrapper.vm.$apollo.queries.pipeline.options.pollInterval;
+
+ expect(expectedInterval).toBe(COMMIT_BOX_POLL_INTERVAL);
+ });
+
+ it('polling interval is set for pipeline stages', () => {
+ createComponent();
+
+ const expectedInterval = wrapper.vm.$apollo.queries.pipelineStages.options.pollInterval;
+
+ expect(expectedInterval).toBe(COMMIT_BOX_POLL_INTERVAL);
+ });
+
+ it('polls for stages and linked pipelines', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(stagesHandler).toHaveBeenCalledTimes(1);
+ expect(downstreamHandler).toHaveBeenCalledTimes(1);
+
+ advanceToNextFetch();
+ await waitForPromises();
+
+ expect(stagesHandler).toHaveBeenCalledTimes(2);
+ expect(downstreamHandler).toHaveBeenCalledTimes(2);
+
+ advanceToNextFetch();
+ await waitForPromises();
+
+ expect(stagesHandler).toHaveBeenCalledTimes(3);
+ expect(downstreamHandler).toHaveBeenCalledTimes(3);
+ });
+
+ it('toggles query polling with visibility check', async () => {
+ jest.spyOn(graphQlUtils, 'toggleQueryPollingByVisibility');
+
+ createComponent();
+
+ await waitForPromises();
+
+ expect(graphQlUtils.toggleQueryPollingByVisibility).toHaveBeenCalledWith(
+ wrapper.vm.$apollo.queries.pipelineStages,
+ );
+ expect(graphQlUtils.toggleQueryPollingByVisibility).toHaveBeenCalledWith(
+ wrapper.vm.$apollo.queries.pipeline,
+ );
+ });
+ });
});
diff --git a/spec/frontend/commit/commit_pipeline_status_component_spec.js b/spec/frontend/commit/commit_pipeline_status_component_spec.js
index 43db6db00c1..73720c1cc88 100644
--- a/spec/frontend/commit/commit_pipeline_status_component_spec.js
+++ b/spec/frontend/commit/commit_pipeline_status_component_spec.js
@@ -37,9 +37,9 @@ describe('Commit pipeline status component', () => {
});
};
- const findLoader = () => wrapper.find(GlLoadingIcon);
+ const findLoader = () => wrapper.findComponent(GlLoadingIcon);
const findLink = () => wrapper.find('a');
- const findCiIcon = () => findLink().find(CiIcon);
+ const findCiIcon = () => findLink().findComponent(CiIcon);
afterEach(() => {
wrapper.destroy();
diff --git a/spec/frontend/commit/mock_data.js b/spec/frontend/commit/mock_data.js
index 8db162c07c2..aef137e6fa5 100644
--- a/spec/frontend/commit/mock_data.js
+++ b/spec/frontend/commit/mock_data.js
@@ -3,116 +3,21 @@ export const mockStages = [
name: 'build',
title: 'build: passed',
status: {
+ __typename: 'DetailedStatus',
+ id: 'success-409-409',
icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
tooltip: 'passed',
has_details: true,
- details_path: '/root/ci-project/-/pipelines/611#build',
+ details_path: '/root/ci-project/-/pipelines/318#build',
illustration: null,
favicon:
'/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
},
- path: '/root/ci-project/-/pipelines/611#build',
- dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=build',
- },
- {
- name: 'test',
- title: 'test: passed',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/ci-project/-/pipelines/611#test',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/ci-project/-/pipelines/611#test',
- dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=test',
- },
- {
- name: 'test_two',
- title: 'test_two: passed',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/ci-project/-/pipelines/611#test_two',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/ci-project/-/pipelines/611#test_two',
- dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=test_two',
- },
- {
- name: 'manual',
- title: 'manual: skipped',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/root/ci-project/-/pipelines/611#manual',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- action: {
- icon: 'play',
- title: 'Play all manual',
- path: '/root/ci-project/-/pipelines/611/stages/manual/play_manual',
- method: 'post',
- button_title: 'Play all manual',
- },
- },
- path: '/root/ci-project/-/pipelines/611#manual',
- dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=manual',
- },
- {
- name: 'deploy',
- title: 'deploy: passed',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/ci-project/-/pipelines/611#deploy',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/ci-project/-/pipelines/611#deploy',
- dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=deploy',
- },
- {
- name: 'qa',
- title: 'qa: passed',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/ci-project/-/pipelines/611#qa',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/ci-project/-/pipelines/611#qa',
- dropdown_path: '/root/ci-project/-/pipelines/611/stage.json?stage=qa',
+ path: '/root/ci-project/-/pipelines/318#build',
+ dropdown_path: '/root/ci-project/-/pipelines/318/stage.json?stage=build',
},
];
@@ -161,3 +66,109 @@ export const mockPipelineStatusResponse = {
},
},
};
+
+export const mockDownstreamQueryResponse = {
+ data: {
+ project: {
+ id: '1',
+ pipeline: {
+ path: '/root/ci-project/-/pipelines/790',
+ id: 'pipeline-1',
+ downstream: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Ci::Pipeline/612',
+ path: '/root/job-log-sections/-/pipelines/612',
+ project: { id: '1', name: 'job-log-sections', __typename: 'Project' },
+ detailedStatus: {
+ id: 'status-1',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ __typename: 'DetailedStatus',
+ },
+ __typename: 'Pipeline',
+ },
+ ],
+ __typename: 'PipelineConnection',
+ },
+ upstream: null,
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
+export const mockUpstreamDownstreamQueryResponse = {
+ data: {
+ project: {
+ id: '1',
+ pipeline: {
+ id: 'pipeline-1',
+ path: '/root/ci-project/-/pipelines/790',
+ downstream: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Ci::Pipeline/612',
+ path: '/root/job-log-sections/-/pipelines/612',
+ project: { id: '1', name: 'job-log-sections', __typename: 'Project' },
+ detailedStatus: {
+ id: 'status-1',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ __typename: 'DetailedStatus',
+ },
+ __typename: 'Pipeline',
+ },
+ ],
+ __typename: 'PipelineConnection',
+ },
+ upstream: {
+ id: 'gid://gitlab/Ci::Pipeline/610',
+ path: '/root/trigger-downstream/-/pipelines/610',
+ project: { id: '1', name: 'trigger-downstream', __typename: 'Project' },
+ detailedStatus: {
+ id: 'status-1',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ __typename: 'DetailedStatus',
+ },
+ __typename: 'Pipeline',
+ },
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
+export const mockUpstreamQueryResponse = {
+ data: {
+ project: {
+ id: '1',
+ pipeline: {
+ id: 'pipeline-1',
+ path: '/root/ci-project/-/pipelines/790',
+ downstream: {
+ nodes: [],
+ __typename: 'PipelineConnection',
+ },
+ upstream: {
+ id: 'gid://gitlab/Ci::Pipeline/610',
+ path: '/root/trigger-downstream/-/pipelines/610',
+ project: { id: '1', name: 'trigger-downstream', __typename: 'Project' },
+ detailedStatus: {
+ id: 'status-1',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ __typename: 'DetailedStatus',
+ },
+ __typename: 'Pipeline',
+ },
+ },
+ __typename: 'Project',
+ },
+ },
+};
diff --git a/spec/frontend/commit/pipelines/pipelines_table_spec.js b/spec/frontend/commit/pipelines/pipelines_table_spec.js
index 71ee12cf02d..d89a238105b 100644
--- a/spec/frontend/commit/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/commit/pipelines/pipelines_table_spec.js
@@ -302,6 +302,33 @@ describe('Pipelines table in Commits and Merge requests', () => {
expect(findModal()).not.toBeNull();
});
});
+
+ describe('when no pipelines were created on a forked merge request', () => {
+ beforeEach(async () => {
+ mock.onGet('endpoint.json').reply(200, []);
+
+ createComponent({
+ projectId: '5',
+ mergeRequestId: 3,
+ canCreatePipelineInTargetProject: true,
+ sourceProjectFullPath: 'test/parent-project',
+ targetProjectFullPath: 'test/fork-project',
+ });
+
+ jest.spyOn(findModal().vm, 'show').mockReturnValue();
+
+ await waitForPromises();
+ });
+
+ it('should show security modal from empty state run pipeline button', () => {
+ expect(findEmptyState().exists()).toBe(true);
+ expect(findModal().exists()).toBe(true);
+
+ findRunPipelineBtn().trigger('click');
+
+ expect(findModal().vm.show).toHaveBeenCalled();
+ });
+ });
});
describe('unsuccessfull request', () => {