summaryrefslogtreecommitdiff
path: root/spec/frontend/pipelines
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/pipelines')
-rw-r--r--spec/frontend/pipelines/blank_state_spec.js2
-rw-r--r--spec/frontend/pipelines/components/dag/dag_annotations_spec.js6
-rw-r--r--spec/frontend/pipelines/components/dag/dag_graph_spec.js26
-rw-r--r--spec/frontend/pipelines/components/dag/dag_spec.js2
-rw-r--r--spec/frontend/pipelines/components/dag/parsing_utils_spec.js5
-rw-r--r--spec/frontend/pipelines/components/pipelines_filtered_search_spec.js6
-rw-r--r--spec/frontend/pipelines/empty_state_spec.js105
-rw-r--r--spec/frontend/pipelines/graph/action_component_spec.js6
-rw-r--r--spec/frontend/pipelines/graph/graph_component_legacy_spec.js80
-rw-r--r--spec/frontend/pipelines/graph/graph_component_spec.js45
-rw-r--r--spec/frontend/pipelines/graph/graph_component_wrapper_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/job_item_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/linked_pipelines_column_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/mock_data.js76
-rw-r--r--spec/frontend/pipelines/graph/stage_column_component_legacy_spec.js7
-rw-r--r--spec/frontend/pipelines/graph/stage_column_component_spec.js66
-rw-r--r--spec/frontend/pipelines/nav_controls_spec.js2
-rw-r--r--spec/frontend/pipelines/pipeline_graph/mock_data.js10
-rw-r--r--spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js18
-rw-r--r--spec/frontend/pipelines/pipeline_graph/utils_spec.js44
-rw-r--r--spec/frontend/pipelines/pipeline_url_spec.js2
-rw-r--r--spec/frontend/pipelines/pipelines_actions_spec.js28
-rw-r--r--spec/frontend/pipelines/pipelines_artifacts_spec.js16
-rw-r--r--spec/frontend/pipelines/pipelines_spec.js98
-rw-r--r--spec/frontend/pipelines/pipelines_store_spec.js5
-rw-r--r--spec/frontend/pipelines/pipelines_table_row_spec.js21
-rw-r--r--spec/frontend/pipelines/pipelines_table_spec.js2
-rw-r--r--spec/frontend/pipelines/shared/links_layer_spec.js99
-rw-r--r--spec/frontend/pipelines/stage_spec.js77
-rw-r--r--spec/frontend/pipelines/stores/pipeline_store_spec.js4
-rw-r--r--spec/frontend/pipelines/test_reports/stores/actions_spec.js22
-rw-r--r--spec/frontend/pipelines/test_reports/stores/getters_spec.js4
-rw-r--r--spec/frontend/pipelines/test_reports/test_case_details_spec.js2
-rw-r--r--spec/frontend/pipelines/test_reports/test_suite_table_spec.js6
-rw-r--r--spec/frontend/pipelines/test_reports/test_summary_spec.js2
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js2
-rw-r--r--spec/frontend/pipelines/unwrapping_utils_spec.js26
37 files changed, 573 insertions, 361 deletions
diff --git a/spec/frontend/pipelines/blank_state_spec.js b/spec/frontend/pipelines/blank_state_spec.js
index bb069fdc2c8..c09d9232569 100644
--- a/spec/frontend/pipelines/blank_state_spec.js
+++ b/spec/frontend/pipelines/blank_state_spec.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
+import mountComponent from 'helpers/vue_mount_component_helper';
import component from '~/pipelines/components/pipelines_list/blank_state.vue';
-import mountComponent from '../helpers/vue_mount_component_helper';
describe('Pipelines Blank State', () => {
let vm;
diff --git a/spec/frontend/pipelines/components/dag/dag_annotations_spec.js b/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
index 5747c91bee8..80807c0b330 100644
--- a/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
@@ -66,11 +66,7 @@ describe('The DAG annotations', () => {
expect(getAllTextBlocks().length).toBe(Object.keys(multiNote).length);
Object.values(multiNote).forEach((item, idx) => {
- expect(
- getAllTextBlocks()
- .at(idx)
- .text(),
- ).toBe(`${item.source.name} → ${item.target.name}`);
+ expect(getAllTextBlocks().at(idx).text()).toBe(`${item.source.name} → ${item.target.name}`);
});
});
diff --git a/spec/frontend/pipelines/components/dag/dag_graph_spec.js b/spec/frontend/pipelines/components/dag/dag_graph_spec.js
index 7786212cb69..ccfb2ae7cee 100644
--- a/spec/frontend/pipelines/components/dag/dag_graph_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_graph_spec.js
@@ -20,7 +20,7 @@ describe('The DAG graph', () => {
}
wrapper = shallowMount(DagGraph, {
- attachToDocument: true,
+ attachTo: document.body,
propsData,
data() {
return {
@@ -88,17 +88,13 @@ describe('The DAG graph', () => {
});
it('renders the title as text', () => {
- expect(
- getAllLabels()
- .at(0)
- .text(),
- ).toBe(parsedData.nodes[0].name);
+ expect(getAllLabels().at(0).text()).toBe(parsedData.nodes[0].name);
});
});
});
describe('interactions', () => {
- const strokeOpacity = opacity => `stroke-opacity: ${opacity};`;
+ const strokeOpacity = (opacity) => `stroke-opacity: ${opacity};`;
const baseOpacity = () => wrapper.vm.$options.viewOptions.baseOpacity;
describe('links', () => {
@@ -168,10 +164,10 @@ describe('The DAG graph', () => {
describe('nodes', () => {
const liveNode = () => getAllNodes().at(10);
const anotherLiveNode = () => getAllNodes().at(5);
- const nodesNotHighlighted = () => getAllNodes().filter(n => !n.classes(IS_HIGHLIGHTED));
- const linksNotHighlighted = () => getAllLinks().filter(n => !n.classes(IS_HIGHLIGHTED));
- const nodesHighlighted = () => getAllNodes().filter(n => n.classes(IS_HIGHLIGHTED));
- const linksHighlighted = () => getAllLinks().filter(n => n.classes(IS_HIGHLIGHTED));
+ const nodesNotHighlighted = () => getAllNodes().filter((n) => !n.classes(IS_HIGHLIGHTED));
+ const linksNotHighlighted = () => getAllLinks().filter((n) => !n.classes(IS_HIGHLIGHTED));
+ const nodesHighlighted = () => getAllNodes().filter((n) => n.classes(IS_HIGHLIGHTED));
+ const linksHighlighted = () => getAllLinks().filter((n) => n.classes(IS_HIGHLIGHTED));
describe('on click', () => {
it('highlights the clicked node and predecessors', () => {
@@ -180,19 +176,19 @@ describe('The DAG graph', () => {
expect(nodesNotHighlighted().length < getAllNodes().length).toBe(true);
expect(linksNotHighlighted().length < getAllLinks().length).toBe(true);
- linksHighlighted().wrappers.forEach(link => {
+ linksHighlighted().wrappers.forEach((link) => {
expect(link.attributes('style')).toBe(strokeOpacity(highlightIn));
});
- nodesHighlighted().wrappers.forEach(node => {
+ nodesHighlighted().wrappers.forEach((node) => {
expect(node.attributes('stroke')).not.toBe('#f2f2f2');
});
- linksNotHighlighted().wrappers.forEach(link => {
+ linksNotHighlighted().wrappers.forEach((link) => {
expect(link.attributes('style')).toBe(strokeOpacity(highlightOut));
});
- nodesNotHighlighted().wrappers.forEach(node => {
+ nodesNotHighlighted().wrappers.forEach((node) => {
expect(node.attributes('stroke')).toBe('#f2f2f2');
});
});
diff --git a/spec/frontend/pipelines/components/dag/dag_spec.js b/spec/frontend/pipelines/components/dag/dag_spec.js
index 08a43199594..f6195e30e44 100644
--- a/spec/frontend/pipelines/components/dag/dag_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_spec.js
@@ -21,7 +21,7 @@ describe('Pipeline DAG graph wrapper', () => {
const getAllAlerts = () => wrapper.findAll(GlAlert);
const getGraph = () => wrapper.find(DagGraph);
const getNotes = () => wrapper.find(DagAnnotations);
- const getErrorText = type => wrapper.vm.$options.errorTexts[type];
+ const getErrorText = (type) => wrapper.vm.$options.errorTexts[type];
const getEmptyState = () => wrapper.find(GlEmptyState);
const createComponent = ({
diff --git a/spec/frontend/pipelines/components/dag/parsing_utils_spec.js b/spec/frontend/pipelines/components/dag/parsing_utils_spec.js
index ceb6b64d4ad..5d3f680a57c 100644
--- a/spec/frontend/pipelines/components/dag/parsing_utils_spec.js
+++ b/spec/frontend/pipelines/components/dag/parsing_utils_spec.js
@@ -30,7 +30,10 @@ describe('DAG visualization parsing utilities', () => {
{ source: 'job2', target: 'job4' },
];
- const dedupedLinks = [{ source: 'job1', target: 'job2' }, { source: 'job2', target: 'job4' }];
+ const dedupedLinks = [
+ { source: 'job1', target: 'job2' },
+ { source: 'job2', target: 'job4' },
+ ];
const nodeLookup = {
job1: {
diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
index 8a6586a7d7d..00fe9e784b3 100644
--- a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
+++ b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
@@ -11,10 +11,10 @@ describe('Pipelines filtered search', () => {
let mock;
const findFilteredSearch = () => wrapper.find(GlFilteredSearch);
- const getSearchToken = type =>
+ const getSearchToken = (type) =>
findFilteredSearch()
.props('availableTokens')
- .find(token => token.type === type);
+ .find((token) => token.type === type);
const findBranchToken = () => getSearchToken('ref');
const findTagToken = () => getSearchToken('tag');
const findUserToken = () => getSearchToken('username');
@@ -26,7 +26,7 @@ describe('Pipelines filtered search', () => {
projectId: '21',
params,
},
- attachToDocument: true,
+ attachTo: document.body,
});
};
diff --git a/spec/frontend/pipelines/empty_state_spec.js b/spec/frontend/pipelines/empty_state_spec.js
index 28a73c8863c..7e42a3b5ae9 100644
--- a/spec/frontend/pipelines/empty_state_spec.js
+++ b/spec/frontend/pipelines/empty_state_spec.js
@@ -1,5 +1,7 @@
import { shallowMount } from '@vue/test-utils';
+import { withGonExperiment } from 'helpers/experimentation_helper';
import EmptyState from '~/pipelines/components/pipelines_list/empty_state.vue';
+import Tracking from '~/tracking';
describe('Pipelines Empty State', () => {
let wrapper;
@@ -38,15 +40,104 @@ describe('Pipelines Empty State', () => {
expect(findGetStartedButton().attributes('href')).toBe('foo');
});
- it('should render empty state information', () => {
- expect(findInfoText()).toContain(
- 'Continuous Integration can help catch bugs by running your tests automatically',
- 'while Continuous Deployment can help you deliver code to your product environment',
- );
+ describe('when in control group', () => {
+ it('should render empty state information', () => {
+ expect(findInfoText()).toContain(
+ 'Continuous Integration can help catch bugs by running your tests automatically',
+ 'while Continuous Deployment can help you deliver code to your product environment',
+ );
+ });
+
+ it('should render a button', () => {
+ expect(findGetStartedButton().text()).toBe('Get started with Pipelines');
+ });
+ });
+
+ describe('when in experiment group', () => {
+ withGonExperiment('pipelinesEmptyState');
+
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('should render empty state information', () => {
+ expect(findInfoText()).toContain(
+ 'GitLab CI/CD can automatically build, test, and deploy your code. Let GitLab take care of time',
+ 'consuming tasks, so you can spend more time creating',
+ );
+ });
+
+ it('should render button text', () => {
+ expect(findGetStartedButton().text()).toBe('Get started with CI/CD');
+ });
});
- it('should render a button', () => {
- expect(findGetStartedButton().text()).toBe('Get started with Pipelines');
+ describe('tracking', () => {
+ let origGon;
+
+ describe('when data is set', () => {
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event').mockImplementation(() => {});
+ origGon = window.gon;
+
+ window.gon = {
+ tracking_data: {
+ category: 'Growth::Activation::Experiment::PipelinesEmptyState',
+ value: 1,
+ property: 'experimental_group',
+ label: 'label',
+ },
+ };
+ createWrapper();
+ });
+
+ afterEach(() => {
+ window.gon = origGon;
+ });
+
+ it('tracks when mounted', () => {
+ expect(Tracking.event).toHaveBeenCalledWith(
+ 'Growth::Activation::Experiment::PipelinesEmptyState',
+ 'viewed',
+ {
+ value: 1,
+ label: 'label',
+ property: 'experimental_group',
+ },
+ );
+ });
+
+ it('tracks when button is clicked', () => {
+ findGetStartedButton().vm.$emit('click');
+
+ expect(Tracking.event).toHaveBeenCalledWith(
+ 'Growth::Activation::Experiment::PipelinesEmptyState',
+ 'documentation_clicked',
+ {
+ value: 1,
+ label: 'label',
+ property: 'experimental_group',
+ },
+ );
+ });
+ });
+
+ describe('when no data is defined', () => {
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event').mockImplementation(() => {});
+
+ createWrapper();
+ });
+
+ it('does not track on view', () => {
+ expect(Tracking.event).not.toHaveBeenCalled();
+ });
+
+ it('does not track when button is clicked', () => {
+ findGetStartedButton().vm.$emit('click');
+ expect(Tracking.event).not.toHaveBeenCalled();
+ });
+ });
});
});
});
diff --git a/spec/frontend/pipelines/graph/action_component_spec.js b/spec/frontend/pipelines/graph/action_component_spec.js
index ab477292bc1..95d96e127c6 100644
--- a/spec/frontend/pipelines/graph/action_component_spec.js
+++ b/spec/frontend/pipelines/graph/action_component_spec.js
@@ -33,7 +33,7 @@ describe('pipeline graph action component', () => {
expect(wrapper.attributes('title')).toBe('bar');
});
- it('should update bootstrap tooltip when title changes', done => {
+ it('should update bootstrap tooltip when title changes', (done) => {
wrapper.setProps({ tooltipText: 'changed' });
wrapper.vm
@@ -51,7 +51,7 @@ describe('pipeline graph action component', () => {
});
describe('on click', () => {
- it('emits `pipelineActionRequestComplete` after a successful request', done => {
+ it('emits `pipelineActionRequestComplete` after a successful request', (done) => {
jest.spyOn(wrapper.vm, '$emit');
findButton().trigger('click');
@@ -64,7 +64,7 @@ describe('pipeline graph action component', () => {
.catch(done.fail);
});
- it('renders a loading icon while waiting for request', done => {
+ it('renders a loading icon while waiting for request', (done) => {
findButton().trigger('click');
wrapper.vm.$nextTick(() => {
diff --git a/spec/frontend/pipelines/graph/graph_component_legacy_spec.js b/spec/frontend/pipelines/graph/graph_component_legacy_spec.js
index 3b1909b6564..840b1f8baf5 100644
--- a/spec/frontend/pipelines/graph/graph_component_legacy_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_legacy_spec.js
@@ -1,4 +1,4 @@
-import Vue from 'vue';
+import { nextTick } from 'vue';
import { mount } from '@vue/test-utils';
import { GlLoadingIcon } from '@gitlab/ui';
import { setHTMLFixture } from 'helpers/fixtures';
@@ -18,7 +18,7 @@ describe('graph component', () => {
const findExpandPipelineBtn = () => wrapper.find('[data-testid="expand-pipeline-button"]');
const findAllExpandPipelineBtns = () => wrapper.findAll('[data-testid="expand-pipeline-button"]');
const findStageColumns = () => wrapper.findAll(StageColumnComponentLegacy);
- const findStageColumnAt = i => findStageColumns().at(i);
+ const findStageColumnAt = (i) => findStageColumns().at(i);
beforeEach(() => {
mediator = new PipelinesMediator({ endpoint: '' });
@@ -104,11 +104,9 @@ describe('graph component', () => {
});
it('should include the left-connector class in the build of the second child', () => {
- expect(
- findStageColumnAt(1)
- .find('.build:nth-child(1)')
- .classes('left-connector'),
- ).toBe(true);
+ expect(findStageColumnAt(1).find('.build:nth-child(1)').classes('left-connector')).toBe(
+ true,
+ );
});
it('should include the js-has-linked-pipelines flag', () => {
@@ -119,12 +117,7 @@ describe('graph component', () => {
describe('computeds and methods', () => {
describe('capitalizeStageName', () => {
it('it capitalizes the stage name', () => {
- expect(
- wrapper
- .findAll('.stage-column .stage-name')
- .at(1)
- .text(),
- ).toBe('Prebuild');
+ expect(wrapper.findAll('.stage-column .stage-name').at(1).text()).toBe('Prebuild');
});
});
@@ -160,21 +153,20 @@ describe('graph component', () => {
describe('triggered by', () => {
describe('on click', () => {
- it('should emit `onClickUpstreamPipeline` when triggered by linked pipeline is clicked', () => {
+ it('should emit `onClickUpstreamPipeline` when triggered by linked pipeline is clicked', async () => {
const btnWrapper = findExpandPipelineBtn();
btnWrapper.trigger('click');
- btnWrapper.vm.$nextTick(() => {
- expect(wrapper.emitted().onClickUpstreamPipeline).toEqual([
- store.state.pipeline.triggered_by,
- ]);
- });
+ await nextTick();
+ expect(wrapper.emitted().onClickUpstreamPipeline).toEqual([
+ store.state.pipeline.triggered_by,
+ ]);
});
});
describe('with expanded pipeline', () => {
- it('should render expanded pipeline', done => {
+ it('should render expanded pipeline', async () => {
// expand the pipeline
store.state.pipeline.triggered_by[0].isExpanded = true;
@@ -186,40 +178,46 @@ describe('graph component', () => {
},
});
- Vue.nextTick()
- .then(() => {
- expect(wrapper.find('.js-upstream-pipeline-12').exists()).toBe(true);
- })
- .then(done)
- .catch(done.fail);
+ await nextTick();
+ expect(wrapper.find('.js-upstream-pipeline-12').exists()).toBe(true);
});
});
});
describe('triggered', () => {
describe('on click', () => {
- it('should emit `onClickTriggered`', () => {
- // We have to mock this method since we do both style change and
- // emit and event, not mocking returns an error.
- wrapper.setMethods({
- handleClickedDownstream: jest.fn(() =>
- wrapper.vm.$emit('onClickTriggered', ...store.state.pipeline.triggered),
- ),
+ // We have to mock this property of HTMLElement since component relies on it
+ let offsetParentDescriptor;
+ beforeAll(() => {
+ offsetParentDescriptor = Object.getOwnPropertyDescriptor(
+ HTMLElement.prototype,
+ 'offsetParent',
+ );
+ Object.defineProperty(HTMLElement.prototype, 'offsetParent', {
+ get() {
+ return this.parentNode;
+ },
});
+ });
+ afterAll(() => {
+ Object.defineProperty(HTMLElement.prototype, offsetParentDescriptor);
+ });
+ it('should emit `onClickDownstreamPipeline`', async () => {
const btnWrappers = findAllExpandPipelineBtns();
const downstreamBtnWrapper = btnWrappers.at(btnWrappers.length - 1);
downstreamBtnWrapper.trigger('click');
- downstreamBtnWrapper.vm.$nextTick(() => {
- expect(wrapper.emitted().onClickTriggered).toEqual([store.state.pipeline.triggered]);
- });
+ await nextTick();
+ expect(wrapper.emitted().onClickDownstreamPipeline).toEqual([
+ [store.state.pipeline.triggered[1]],
+ ]);
});
});
describe('with expanded pipeline', () => {
- it('should render expanded pipeline', done => {
+ it('should render expanded pipeline', async () => {
// expand the pipeline
store.state.pipeline.triggered[0].isExpanded = true;
@@ -231,12 +229,8 @@ describe('graph component', () => {
},
});
- Vue.nextTick()
- .then(() => {
- expect(wrapper.find('.js-downstream-pipeline-34993051')).not.toBeNull();
- })
- .then(done)
- .catch(done.fail);
+ await nextTick();
+ expect(wrapper.find('.js-downstream-pipeline-34993051')).not.toBeNull();
});
});
diff --git a/spec/frontend/pipelines/graph/graph_component_spec.js b/spec/frontend/pipelines/graph/graph_component_spec.js
index 7572dd83798..cfc3b7af282 100644
--- a/spec/frontend/pipelines/graph/graph_component_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_spec.js
@@ -1,7 +1,9 @@
import { mount, shallowMount } from '@vue/test-utils';
import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
+import JobItem from '~/pipelines/components/graph/job_item.vue';
import LinkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue';
+import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue';
import { GRAPHQL } from '~/pipelines/components/graph/constants';
import {
generateResponse,
@@ -13,21 +15,37 @@ describe('graph component', () => {
let wrapper;
const findLinkedColumns = () => wrapper.findAll(LinkedPipelinesColumn);
+ const findLinksLayer = () => wrapper.find(LinksLayer);
const findStageColumns = () => wrapper.findAll(StageColumnComponent);
const defaultProps = {
pipeline: generateResponse(mockPipelineResponse, 'root/fungi-xoxo'),
};
- const createComponent = ({ mountFn = shallowMount, props = {} } = {}) => {
+ const createComponent = ({
+ data = {},
+ mountFn = shallowMount,
+ props = {},
+ stubOverride = {},
+ } = {}) => {
wrapper = mountFn(PipelineGraph, {
propsData: {
...defaultProps,
...props,
},
+ data() {
+ return { ...data };
+ },
provide: {
dataMethod: GRAPHQL,
},
+ stubs: {
+ 'links-inner': true,
+ 'linked-pipeline': true,
+ 'job-item': true,
+ 'job-group-dropdown': true,
+ ...stubOverride,
+ },
});
};
@@ -45,17 +63,36 @@ describe('graph component', () => {
expect(findStageColumns()).toHaveLength(defaultProps.pipeline.stages.length);
});
+ it('renders the links layer', () => {
+ expect(findLinksLayer().exists()).toBe(true);
+ });
+
describe('when column requests a refresh', () => {
beforeEach(() => {
- findStageColumns()
- .at(0)
- .vm.$emit('refreshPipelineGraph');
+ findStageColumns().at(0).vm.$emit('refreshPipelineGraph');
});
it('refreshPipelineGraph is emitted', () => {
expect(wrapper.emitted().refreshPipelineGraph).toHaveLength(1);
});
});
+
+ describe('when links are present', () => {
+ beforeEach(async () => {
+ createComponent({
+ mountFn: mount,
+ stubOverride: { 'job-item': false },
+ data: { hoveredJobName: 'test_a' },
+ });
+ findLinksLayer().vm.$emit('highlightedJobsChange', ['test_c', 'build_c']);
+ });
+
+ it('dims unrelated jobs', () => {
+ const unrelatedJob = wrapper.find(JobItem);
+ expect(findLinksLayer().emitted().highlightedJobsChange).toHaveLength(1);
+ expect(unrelatedJob.classes('gl-opacity-3')).toBe(true);
+ });
+ });
});
describe('when linked pipelines are not present', () => {
diff --git a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
index 875aaa48037..54593c527cb 100644
--- a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
@@ -2,10 +2,10 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMount } from '@vue/test-utils';
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
-import createMockApollo from 'jest/helpers/mock_apollo_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
import PipelineGraphWrapper from '~/pipelines/components/graph/graph_component_wrapper.vue';
import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
-import getPipelineDetails from '~/pipelines/graphql/queries/get_pipeline_details.query.graphql';
import { mockPipelineResponse } from './mock_data';
const defaultProvide = {
diff --git a/spec/frontend/pipelines/graph/job_item_spec.js b/spec/frontend/pipelines/graph/job_item_spec.js
index 8aabb2f9cdd..cb2837cbb39 100644
--- a/spec/frontend/pipelines/graph/job_item_spec.js
+++ b/spec/frontend/pipelines/graph/job_item_spec.js
@@ -7,7 +7,7 @@ describe('pipeline graph job item', () => {
const findJobWithoutLink = () => wrapper.find('[data-testid="job-without-link"]');
const findJobWithLink = () => wrapper.find('[data-testid="job-with-link"]');
- const createWrapper = propsData => {
+ const createWrapper = (propsData) => {
wrapper = mount(JobItem, {
propsData,
});
@@ -52,7 +52,7 @@ describe('pipeline graph job item', () => {
});
describe('name with link', () => {
- it('should render the job name and status with a link', done => {
+ it('should render the job name and status with a link', (done) => {
createWrapper({ job: mockJob });
wrapper.vm.$nextTick(() => {
diff --git a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
index 37eb5f900dd..6db152f2607 100644
--- a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
@@ -1,10 +1,10 @@
import VueApollo from 'vue-apollo';
import { mount, shallowMount, createLocalVue } from '@vue/test-utils';
-import createMockApollo from 'jest/helpers/mock_apollo_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
import LinkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue';
import LinkedPipeline from '~/pipelines/components/graph/linked_pipeline.vue';
-import getPipelineDetails from '~/pipelines/graphql/queries/get_pipeline_details.query.graphql';
import { DOWNSTREAM, GRAPHQL } from '~/pipelines/components/graph/constants';
import { LOAD_FAILURE } from '~/pipelines/constants';
import {
diff --git a/spec/frontend/pipelines/graph/mock_data.js b/spec/frontend/pipelines/graph/mock_data.js
index d53a11eea0e..7650cbd2d5c 100644
--- a/spec/frontend/pipelines/graph/mock_data.js
+++ b/spec/frontend/pipelines/graph/mock_data.js
@@ -56,7 +56,7 @@ export const mockPipelineResponse = {
},
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [],
},
},
@@ -96,7 +96,7 @@ export const mockPipelineResponse = {
},
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [],
},
},
@@ -136,7 +136,7 @@ export const mockPipelineResponse = {
},
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [],
},
},
@@ -176,7 +176,7 @@ export const mockPipelineResponse = {
},
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [],
},
},
@@ -200,7 +200,7 @@ export const mockPipelineResponse = {
},
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [],
},
},
@@ -224,7 +224,7 @@ export const mockPipelineResponse = {
},
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [],
},
},
@@ -277,18 +277,18 @@ export const mockPipelineResponse = {
},
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_c',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_b',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name:
'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl',
},
@@ -331,26 +331,26 @@ export const mockPipelineResponse = {
},
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_d 3/3',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_d 2/3',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_d 1/3',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_b',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name:
'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl',
},
@@ -377,26 +377,26 @@ export const mockPipelineResponse = {
},
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_d 3/3',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_d 2/3',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_d 1/3',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_b',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name:
'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl',
},
@@ -433,18 +433,18 @@ export const mockPipelineResponse = {
action: null,
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_c',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_b',
},
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name:
'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl',
},
@@ -481,10 +481,10 @@ export const mockPipelineResponse = {
action: null,
},
needs: {
- __typename: 'CiJobConnection',
+ __typename: 'CiBuildNeedConnection',
nodes: [
{
- __typename: 'CiJob',
+ __typename: 'CiBuildNeed',
name: 'build_b',
},
],
@@ -578,41 +578,54 @@ export const upstream = {
export const wrappedPipelineReturn = {
data: {
project: {
+ __typename: 'Project',
pipeline: {
+ __typename: 'Pipeline',
id: 'gid://gitlab/Ci::Pipeline/175',
iid: '38',
downstream: {
+ __typename: 'PipelineConnection',
nodes: [],
},
upstream: {
id: 'gid://gitlab/Ci::Pipeline/174',
iid: '37',
path: '/root/elemenohpee/-/pipelines/174',
+ __typename: 'Pipeline',
status: {
+ __typename: 'DetailedStatus',
group: 'success',
label: 'passed',
icon: 'status_success',
},
sourceJob: {
name: 'test_c',
+ __typename: 'CiJob',
},
project: {
id: 'gid://gitlab/Project/25',
name: 'elemenohpee',
fullPath: 'root/elemenohpee',
+ __typename: 'Project',
},
},
stages: {
+ __typename: 'CiStageConnection',
nodes: [
{
name: 'build',
+ __typename: 'CiStage',
status: {
action: null,
+ __typename: 'DetailedStatus',
},
groups: {
+ __typename: 'CiGroupConnection',
nodes: [
{
+ __typename: 'CiGroup',
status: {
+ __typename: 'DetailedStatus',
label: 'passed',
group: 'success',
icon: 'status_success',
@@ -620,20 +633,25 @@ export const wrappedPipelineReturn = {
name: 'build_n',
size: 1,
jobs: {
+ __typename: 'CiJobConnection',
nodes: [
{
+ __typename: 'CiJob',
name: 'build_n',
scheduledAt: null,
needs: {
+ __typename: 'CiBuildNeedConnection',
nodes: [],
},
status: {
+ __typename: 'DetailedStatus',
icon: 'status_success',
tooltip: 'passed',
hasDetails: true,
detailsPath: '/root/elemenohpee/-/jobs/1662',
group: 'success',
action: {
+ __typename: 'StatusAction',
buttonTitle: 'Retry this job',
icon: 'retry',
path: '/root/elemenohpee/-/jobs/1662/retry',
@@ -656,7 +674,7 @@ export const wrappedPipelineReturn = {
export const generateResponse = (raw, mockPath) => unwrapPipelineData(mockPath, raw.data);
-export const pipelineWithUpstreamDownstream = base => {
+export const pipelineWithUpstreamDownstream = (base) => {
const pip = { ...base };
pip.data.project.pipeline.downstream = downstream;
pip.data.project.pipeline.upstream = upstream;
diff --git a/spec/frontend/pipelines/graph/stage_column_component_legacy_spec.js b/spec/frontend/pipelines/graph/stage_column_component_legacy_spec.js
index 463e4c12c7d..2965325ea7c 100644
--- a/spec/frontend/pipelines/graph/stage_column_component_legacy_spec.js
+++ b/spec/frontend/pipelines/graph/stage_column_component_legacy_spec.js
@@ -40,12 +40,7 @@ describe('stage column component', () => {
});
it('should render provided title', () => {
- expect(
- wrapper
- .find('.stage-name')
- .text()
- .trim(),
- ).toBe('foo');
+ expect(wrapper.find('.stage-name').text().trim()).toBe('foo');
});
it('should render the provided groups', () => {
diff --git a/spec/frontend/pipelines/graph/stage_column_component_spec.js b/spec/frontend/pipelines/graph/stage_column_component_spec.js
index 44803929f6d..202e25ccda3 100644
--- a/spec/frontend/pipelines/graph/stage_column_component_spec.js
+++ b/spec/frontend/pipelines/graph/stage_column_component_spec.js
@@ -30,6 +30,7 @@ const mockGroups = Array(4)
const defaultProps = {
title: 'Fish',
groups: mockGroups,
+ pipelineId: 159,
};
describe('stage column component', () => {
@@ -92,36 +93,51 @@ describe('stage column component', () => {
});
describe('job', () => {
- beforeEach(() => {
- createComponent({
- method: mount,
- props: {
- groups: [
- {
- id: 4259,
- name: '<img src=x onerror=alert(document.domain)>',
- status: {
- icon: 'status_success',
- label: 'success',
- tooltip: '<img src=x onerror=alert(document.domain)>',
+ describe('text handling', () => {
+ beforeEach(() => {
+ createComponent({
+ method: mount,
+ props: {
+ groups: [
+ {
+ id: 4259,
+ name: '<img src=x onerror=alert(document.domain)>',
+ status: {
+ icon: 'status_success',
+ label: 'success',
+ tooltip: '<img src=x onerror=alert(document.domain)>',
+ },
},
- },
- ],
- title: 'test <img src=x onerror=alert(document.domain)>',
- },
+ ],
+ title: 'test <img src=x onerror=alert(document.domain)>',
+ },
+ });
});
- });
- it('capitalizes and escapes name', () => {
- expect(findStageColumnTitle().text()).toBe(
- 'Test &lt;img src=x onerror=alert(document.domain)&gt;',
- );
+ it('capitalizes and escapes name', () => {
+ expect(findStageColumnTitle().text()).toBe(
+ 'Test &lt;img src=x onerror=alert(document.domain)&gt;',
+ );
+ });
+
+ it('escapes id', () => {
+ expect(findStageColumnGroup().attributes('id')).toBe(
+ 'ci-badge-&lt;img src=x onerror=alert(document.domain)&gt;',
+ );
+ });
});
- it('escapes id', () => {
- expect(findStageColumnGroup().attributes('id')).toBe(
- 'ci-badge-&lt;img src=x onerror=alert(document.domain)&gt;',
- );
+ describe('interactions', () => {
+ beforeEach(() => {
+ createComponent({ method: mount });
+ });
+
+ it('emits jobHovered event on mouseenter and mouseleave', async () => {
+ await findStageColumnGroup().trigger('mouseenter');
+ expect(wrapper.emitted().jobHover).toEqual([[defaultProps.groups[0].name]]);
+ await findStageColumnGroup().trigger('mouseleave');
+ expect(wrapper.emitted().jobHover).toEqual([[defaultProps.groups[0].name], ['']]);
+ });
});
});
diff --git a/spec/frontend/pipelines/nav_controls_spec.js b/spec/frontend/pipelines/nav_controls_spec.js
index 139d53881c8..305dc557b39 100644
--- a/spec/frontend/pipelines/nav_controls_spec.js
+++ b/spec/frontend/pipelines/nav_controls_spec.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
+import mountComponent from 'helpers/vue_mount_component_helper';
import navControlsComp from '~/pipelines/components/pipelines_list/nav_controls.vue';
-import mountComponent from '../helpers/vue_mount_component_helper';
describe('Pipelines Nav Controls', () => {
let NavControlsComponent;
diff --git a/spec/frontend/pipelines/pipeline_graph/mock_data.js b/spec/frontend/pipelines/pipeline_graph/mock_data.js
index a77973b293c..7d1a7a79c7f 100644
--- a/spec/frontend/pipelines/pipeline_graph/mock_data.js
+++ b/spec/frontend/pipelines/pipeline_graph/mock_data.js
@@ -1,4 +1,4 @@
-import { createUniqueLinkId } from '~/pipelines/utils';
+import { createUniqueLinkId } from '~/pipelines/components/graph_shared/drawing_utils';
export const yamlString = `stages:
- empty
@@ -78,18 +78,12 @@ export const pipelineData = {
groups: [
{
name: 'deploy_1',
- jobs: [{ script: 'yarn magick', stage: 'deploy' }],
+ jobs: [{ script: 'yarn magick', stage: 'deploy', needs: ['test_1'] }],
id: jobId4,
},
],
},
],
- jobs: {
- [jobId1]: {},
- [jobId2]: {},
- [jobId3]: {},
- [jobId4]: {},
- },
};
export const singleStageData = {
diff --git a/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js b/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
index 6704ee06c1a..b6b0a964383 100644
--- a/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
+++ b/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
@@ -1,7 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import { GlAlert } from '@gitlab/ui';
import { pipelineData, singleStageData } from './mock_data';
-import { CI_CONFIG_STATUS_INVALID } from '~/pipeline_editor/constants';
+import { CI_CONFIG_STATUS_INVALID, CI_CONFIG_STATUS_VALID } from '~/pipeline_editor/constants';
import { DRAW_FAILURE, EMPTY_PIPELINE_DATA, INVALID_CI_CONFIG } from '~/pipelines/constants';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import StagePill from '~/pipelines/components/pipeline_graph/stage_pill.vue';
@@ -23,7 +23,7 @@ describe('pipeline graph component', () => {
const findAlert = () => wrapper.find(GlAlert);
const findAllStagePills = () => wrapper.findAll(StagePill);
const findAllStageBackgroundElements = () => wrapper.findAll('[data-testid="stage-background"]');
- const findStageBackgroundElementAt = index => findAllStageBackgroundElements().at(index);
+ const findStageBackgroundElementAt = (index) => findAllStageBackgroundElements().at(index);
const findAllJobPills = () => wrapper.findAll(JobPill);
afterEach(() => {
@@ -37,7 +37,7 @@ describe('pipeline graph component', () => {
});
it('renders an empty section', () => {
- expect(wrapper.text()).toBe(wrapper.vm.$options.warningTexts[EMPTY_PIPELINE_DATA]);
+ expect(wrapper.text()).toBe(wrapper.vm.$options.errorTexts[EMPTY_PIPELINE_DATA]);
expect(findPipelineGraph().exists()).toBe(false);
expect(findAllStagePills()).toHaveLength(0);
expect(findAllJobPills()).toHaveLength(0);
@@ -51,23 +51,25 @@ describe('pipeline graph component', () => {
it('renders an error message and does not render the graph', () => {
expect(findAlert().exists()).toBe(true);
- expect(findAlert().text()).toBe(wrapper.vm.$options.warningTexts[INVALID_CI_CONFIG]);
+ expect(findAlert().text()).toBe(wrapper.vm.$options.errorTexts[INVALID_CI_CONFIG]);
expect(findPipelineGraph().exists()).toBe(false);
});
});
- describe('without `INVALID` status', () => {
+ describe('with `VALID` status', () => {
beforeEach(() => {
- wrapper = createComponent();
+ wrapper = createComponent({
+ pipelineData: { status: CI_CONFIG_STATUS_VALID, stages: [{ name: 'hello', groups: [] }] },
+ });
});
it('renders the graph with no status error', () => {
- expect(findAlert().text()).not.toBe(wrapper.vm.$options.warningTexts[INVALID_CI_CONFIG]);
+ expect(findAlert().exists()).toBe(false);
expect(findPipelineGraph().exists()).toBe(true);
});
});
- describe('with error while rendering the links', () => {
+ describe('with error while rendering the links with needs', () => {
beforeEach(() => {
wrapper = createComponent();
});
diff --git a/spec/frontend/pipelines/pipeline_graph/utils_spec.js b/spec/frontend/pipelines/pipeline_graph/utils_spec.js
index 12154df6fcf..070d3bf7dac 100644
--- a/spec/frontend/pipelines/pipeline_graph/utils_spec.js
+++ b/spec/frontend/pipelines/pipeline_graph/utils_spec.js
@@ -68,10 +68,10 @@ describe('utils functions', () => {
it('returns a hash with the jobname as key and all its data as value', () => {
const jobs = {
- [jobName1]: job1,
- [jobName2]: job2,
- [jobName3]: job3,
- [jobName4]: job4,
+ [jobName1]: { jobs: [job1], name: jobName1, needs: [] },
+ [jobName2]: { jobs: [job2], name: jobName2, needs: [] },
+ [jobName3]: { jobs: [job3], name: jobName3, needs: job3.needs },
+ [jobName4]: { jobs: [job4], name: jobName4, needs: job4.needs },
};
expect(createJobsHash(pipelineGraphData.stages)).toEqual(jobs);
@@ -110,5 +110,41 @@ describe('utils functions', () => {
[jobName4]: [jobName3, jobName1, jobName2],
});
});
+
+ it('handles parallel jobs by adding the group name as a need', () => {
+ const size = 3;
+ const jobOptimize1 = 'optimize_1';
+ const jobPrepareA = 'prepare_a';
+ const jobPrepareA1 = `${jobPrepareA} 1/${size}`;
+ const jobPrepareA2 = `${jobPrepareA} 2/${size}`;
+ const jobPrepareA3 = `${jobPrepareA} 3/${size}`;
+
+ const jobsParallel = {
+ [jobOptimize1]: {
+ jobs: [job1],
+ name: [jobOptimize1],
+ needs: [jobPrepareA1, jobPrepareA2, jobPrepareA3],
+ },
+ [jobPrepareA]: { jobs: [], name: jobPrepareA, needs: [], size },
+ [jobPrepareA1]: { jobs: [], name: jobPrepareA, needs: [], size },
+ [jobPrepareA2]: { jobs: [], name: jobPrepareA, needs: [], size },
+ [jobPrepareA3]: { jobs: [], name: jobPrepareA, needs: [], size },
+ };
+
+ expect(generateJobNeedsDict(jobsParallel)).toEqual({
+ [jobOptimize1]: [
+ jobPrepareA1,
+ // This is the important part, the `jobPrepareA` group name has been
+ // added to our list of needs.
+ jobPrepareA,
+ jobPrepareA2,
+ jobPrepareA3,
+ ],
+ [jobPrepareA]: [],
+ [jobPrepareA1]: [],
+ [jobPrepareA2]: [],
+ [jobPrepareA3]: [],
+ });
+ });
});
});
diff --git a/spec/frontend/pipelines/pipeline_url_spec.js b/spec/frontend/pipelines/pipeline_url_spec.js
index fc45af2c254..47315bd42e6 100644
--- a/spec/frontend/pipelines/pipeline_url_spec.js
+++ b/spec/frontend/pipelines/pipeline_url_spec.js
@@ -28,7 +28,7 @@ describe('Pipeline Url Component', () => {
pipelineScheduleUrl: 'foo',
};
- const createComponent = props => {
+ const createComponent = (props) => {
wrapper = shallowMount(PipelineUrlComponent, {
propsData: { ...defaultProps, ...props },
provide: {
diff --git a/spec/frontend/pipelines/pipelines_actions_spec.js b/spec/frontend/pipelines/pipelines_actions_spec.js
index 071a2b24889..69c1b7ce43d 100644
--- a/spec/frontend/pipelines/pipelines_actions_spec.js
+++ b/spec/frontend/pipelines/pipelines_actions_spec.js
@@ -55,11 +55,7 @@ describe('Pipelines Actions dropdown', () => {
});
it("renders a disabled action when it's not playable", () => {
- expect(
- findAllDropdownItems()
- .at(1)
- .attributes('disabled'),
- ).toBe('true');
+ expect(findAllDropdownItems().at(1).attributes('disabled')).toBe('true');
});
describe('on click', () => {
@@ -100,9 +96,7 @@ describe('Pipelines Actions dropdown', () => {
mock.onPost(scheduledJobAction.path).reply(200);
jest.spyOn(window, 'confirm').mockReturnValue(true);
- findAllDropdownItems()
- .at(0)
- .vm.$emit('click');
+ findAllDropdownItems().at(0).vm.$emit('click');
expect(window.confirm).toHaveBeenCalled();
@@ -115,28 +109,20 @@ describe('Pipelines Actions dropdown', () => {
mock.onPost(scheduledJobAction.path).reply(200);
jest.spyOn(window, 'confirm').mockReturnValue(false);
- findAllDropdownItems()
- .at(0)
- .vm.$emit('click');
+ findAllDropdownItems().at(0).vm.$emit('click');
expect(window.confirm).toHaveBeenCalled();
expect(mock.history.post.length).toBe(0);
});
it('displays the remaining time in the dropdown', () => {
- expect(
- findAllCountdowns()
- .at(0)
- .props('endDateString'),
- ).toBe(scheduledJobAction.scheduled_at);
+ expect(findAllCountdowns().at(0).props('endDateString')).toBe(
+ scheduledJobAction.scheduled_at,
+ );
});
it('displays 00:00:00 for expired jobs in the dropdown', () => {
- expect(
- findAllCountdowns()
- .at(1)
- .props('endDateString'),
- ).toBe(expiredJobAction.scheduled_at);
+ expect(findAllCountdowns().at(1).props('endDateString')).toBe(expiredJobAction.scheduled_at);
});
});
});
diff --git a/spec/frontend/pipelines/pipelines_artifacts_spec.js b/spec/frontend/pipelines/pipelines_artifacts_spec.js
index 83f6cb68eba..4f4c15fd4cc 100644
--- a/spec/frontend/pipelines/pipelines_artifacts_spec.js
+++ b/spec/frontend/pipelines/pipelines_artifacts_spec.js
@@ -1,12 +1,12 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlLink } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
describe('Pipelines Artifacts dropdown', () => {
let wrapper;
const createComponent = () => {
- wrapper = shallowMount(PipelineArtifacts, {
+ wrapper = mount(PipelineArtifacts, {
propsData: {
artifacts: [
{
@@ -22,8 +22,8 @@ describe('Pipelines Artifacts dropdown', () => {
});
};
- const findGlLink = () => wrapper.find(GlLink);
- const findAllGlLinks = () => wrapper.find('.dropdown-menu').findAll(GlLink);
+ const findFirstGlDropdownItem = () => wrapper.find(GlDropdownItem);
+ const findAllGlDropdownItems = () => wrapper.find(GlDropdown).findAll(GlDropdownItem);
beforeEach(() => {
createComponent();
@@ -35,12 +35,12 @@ describe('Pipelines Artifacts dropdown', () => {
});
it('should render a dropdown with all the provided artifacts', () => {
- expect(findAllGlLinks()).toHaveLength(2);
+ expect(findAllGlDropdownItems()).toHaveLength(2);
});
it('should render a link with the provided path', () => {
- expect(findGlLink().attributes('href')).toEqual('/download/path');
+ expect(findFirstGlDropdownItem().find('a').attributes('href')).toEqual('/download/path');
- expect(findGlLink().text()).toContain('artifact');
+ expect(findFirstGlDropdownItem().text()).toContain('artifact');
});
});
diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js
index ce0e76ba22d..5d82669b0b8 100644
--- a/spec/frontend/pipelines/pipelines_spec.js
+++ b/spec/frontend/pipelines/pipelines_spec.js
@@ -1,3 +1,4 @@
+import { nextTick } from 'vue';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
@@ -57,10 +58,10 @@ describe('Pipelines', () => {
};
const findFilteredSearch = () => wrapper.find(GlFilteredSearch);
- const findByTestId = id => wrapper.find(`[data-testid="${id}"]`);
+ const findByTestId = (id) => wrapper.find(`[data-testid="${id}"]`);
const findNavigationTabs = () => wrapper.find(NavigationTabs);
const findNavigationControls = () => wrapper.find(NavigationControls);
- const findTab = tab => findByTestId(`pipelines-tab-${tab}`);
+ const findTab = (tab) => findByTestId(`pipelines-tab-${tab}`);
const findRunPipelineButton = () => findByTestId('run-pipeline-button');
const findCiLintButton = () => findByTestId('ci-lint-button');
@@ -72,7 +73,7 @@ describe('Pipelines', () => {
const findTablePagination = () => wrapper.find(TablePagination);
- const createComponent = (props = defaultProps, methods) => {
+ const createComponent = (props = defaultProps) => {
wrapper = mount(PipelinesComponent, {
propsData: {
store: new Store(),
@@ -80,13 +81,15 @@ describe('Pipelines', () => {
params: {},
...props,
},
- methods: {
- ...methods,
- },
});
};
beforeEach(() => {
+ delete window.location;
+ });
+
+ beforeEach(() => {
+ window.location = { search: '' };
mock = new MockAdapter(axios);
pipelines = getJSONFixture(jsonFixtureName);
@@ -170,7 +173,7 @@ describe('Pipelines', () => {
it('renders tab empty state finished scope', () => {
wrapper.vm.scope = 'finished';
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findBlankState().text()).toBe('There are currently no finished pipelines.');
});
});
@@ -194,16 +197,8 @@ describe('Pipelines', () => {
});
it('renders empty state', () => {
- expect(
- findEmptyState()
- .find('h4')
- .text(),
- ).toBe('Build with confidence');
- expect(
- findEmptyState()
- .find(GlButton)
- .attributes('href'),
- ).toBe(paths.helpPagePath);
+ expect(findEmptyState().find('h4').text()).toBe('Build with confidence');
+ expect(findEmptyState().find(GlButton).attributes('href')).toBe(paths.helpPagePath);
});
it('does not render tabs nor buttons', () => {
@@ -320,11 +315,7 @@ describe('Pipelines', () => {
'This project is not currently set up to run pipelines.',
);
- expect(
- findEmptyState()
- .find(GlButton)
- .exists(),
- ).toBeFalsy();
+ expect(findEmptyState().find(GlButton).exists()).toBeFalsy();
});
it('does not render tabs or buttons', () => {
@@ -394,30 +385,23 @@ describe('Pipelines', () => {
});
it('should make an API request when using tabs', () => {
- const updateContentMock = jest.fn(() => {});
- createComponent(
- { hasGitlabCi: true, canCreatePipeline: true, ...paths },
- {
- updateContent: updateContentMock,
- },
- );
+ createComponent({ hasGitlabCi: true, canCreatePipeline: true, ...paths });
+ jest.spyOn(wrapper.vm.service, 'getPipelines');
return waitForPromises().then(() => {
findTab('finished').trigger('click');
- expect(updateContentMock).toHaveBeenCalledWith({ scope: 'finished', page: '1' });
+ expect(wrapper.vm.service.getPipelines).toHaveBeenCalledWith({
+ scope: 'finished',
+ page: '1',
+ });
});
});
describe('with pagination', () => {
it('should make an API request when using pagination', () => {
- const updateContentMock = jest.fn(() => {});
- createComponent(
- { hasGitlabCi: true, canCreatePipeline: true, ...paths },
- {
- updateContent: updateContentMock,
- },
- );
+ createComponent({ hasGitlabCi: true, canCreatePipeline: true, ...paths });
+ jest.spyOn(wrapper.vm.service, 'getPipelines');
return waitForPromises()
.then(() => {
@@ -430,12 +414,14 @@ describe('Pipelines', () => {
totalPages: 5,
};
- return wrapper.vm.$nextTick();
+ return nextTick();
})
.then(() => {
wrapper.find('.next-page-item').trigger('click');
-
- expect(updateContentMock).toHaveBeenCalledWith({ scope: 'all', page: '2' });
+ expect(wrapper.vm.service.getPipelines).toHaveBeenCalledWith({
+ scope: 'all',
+ page: '2',
+ });
});
});
});
@@ -554,7 +540,7 @@ describe('Pipelines', () => {
wrapper.vm.hasError = true;
wrapper.vm.isLoading = false;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findBlankState().props('message')).toBe(
'There was an error fetching the pipelines. Try again in a few moments or contact your support team.',
);
@@ -566,7 +552,7 @@ describe('Pipelines', () => {
wrapper.vm.hasError = false;
wrapper.vm.state.pipelines = pipelines.pipelines;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(wrapper.find(PipelinesTableComponent).exists()).toBe(true);
});
});
@@ -575,7 +561,7 @@ describe('Pipelines', () => {
wrapper.vm.state.count.all = 10;
wrapper.vm.isLoading = false;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findBlankState().exists()).toBe(true);
expect(findBlankState().props('message')).toBe('There are currently no pipelines.');
});
@@ -584,7 +570,7 @@ describe('Pipelines', () => {
it('shows empty tab when project has CI', () => {
wrapper.vm.isLoading = false;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findBlankState().exists()).toBe(true);
expect(findBlankState().props('message')).toBe('There are currently no pipelines.');
});
@@ -595,7 +581,7 @@ describe('Pipelines', () => {
wrapper.vm.isLoading = false;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(wrapper.find(EmptyState).exists()).toBe(true);
});
});
@@ -606,7 +592,7 @@ describe('Pipelines', () => {
wrapper.vm.isLoading = true;
wrapper.vm.hasMadeRequest = true;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findNavigationTabs().exists()).toBe(true);
});
});
@@ -616,7 +602,7 @@ describe('Pipelines', () => {
wrapper.vm.state.pipelines = pipelines.pipelines;
wrapper.vm.hasMadeRequest = true;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findNavigationTabs().exists()).toBe(true);
});
});
@@ -626,7 +612,7 @@ describe('Pipelines', () => {
wrapper.vm.hasError = true;
wrapper.vm.hasMadeRequest = true;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findNavigationTabs().exists()).toBe(true);
});
});
@@ -636,7 +622,7 @@ describe('Pipelines', () => {
wrapper.vm.state.count.all = 10;
wrapper.vm.hasMadeRequest = true;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findNavigationTabs().exists()).toBe(true);
});
});
@@ -644,7 +630,7 @@ describe('Pipelines', () => {
it('returns false when has not made first request', () => {
wrapper.vm.hasMadeRequest = false;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findNavigationTabs().exists()).toBe(false);
});
});
@@ -655,7 +641,7 @@ describe('Pipelines', () => {
wrapper.vm.isLoading = false;
wrapper.vm.hasMadeRequest = true;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findNavigationTabs().exists()).toBe(false);
});
});
@@ -665,7 +651,7 @@ describe('Pipelines', () => {
it('returns true when it has paths & has made the first request', () => {
wrapper.vm.hasMadeRequest = true;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findNavigationControls().exists()).toBe(true);
});
});
@@ -673,7 +659,7 @@ describe('Pipelines', () => {
it('returns false when it has not made the first request', () => {
wrapper.vm.hasMadeRequest = false;
- return wrapper.vm.$nextTick().then(() => {
+ return nextTick().then(() => {
expect(findNavigationControls().exists()).toBe(false);
});
});
@@ -692,7 +678,7 @@ describe('Pipelines', () => {
return waitForPromises();
});
- it('updates request data and query params on filter submit', () => {
+ it('updates request data and query params on filter submit', async () => {
const expectedQueryParams = {
page: '1',
scope: 'all',
@@ -702,15 +688,17 @@ describe('Pipelines', () => {
};
findFilteredSearch().vm.$emit('submit', mockSearch);
+ await nextTick();
expect(wrapper.vm.requestData).toEqual(expectedQueryParams);
expect(updateContentMock).toHaveBeenCalledWith(expectedQueryParams);
});
- it('does not add query params if raw text search is used', () => {
+ it('does not add query params if raw text search is used', async () => {
const expectedQueryParams = { page: '1', scope: 'all' };
findFilteredSearch().vm.$emit('submit', ['rawText']);
+ await nextTick();
expect(wrapper.vm.requestData).toEqual(expectedQueryParams);
expect(updateContentMock).toHaveBeenCalledWith(expectedQueryParams);
diff --git a/spec/frontend/pipelines/pipelines_store_spec.js b/spec/frontend/pipelines/pipelines_store_spec.js
index ce21f788ed5..f374ecd0c0a 100644
--- a/spec/frontend/pipelines/pipelines_store_spec.js
+++ b/spec/frontend/pipelines/pipelines_store_spec.js
@@ -21,7 +21,10 @@ describe('Pipelines Store', () => {
});
it('should store the provided array', () => {
- const array = [{ id: 1, status: 'running' }, { id: 2, status: 'success' }];
+ const array = [
+ { id: 1, status: 'running' },
+ { id: 2, status: 'success' },
+ ];
store.storePipelines(array);
expect(store.state.pipelines).toEqual(array);
diff --git a/spec/frontend/pipelines/pipelines_table_row_spec.js b/spec/frontend/pipelines/pipelines_table_row_spec.js
index 32d53c0f1f8..9cdd24b2ab5 100644
--- a/spec/frontend/pipelines/pipelines_table_row_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_row_spec.js
@@ -5,7 +5,7 @@ import eventHub from '~/pipelines/event_hub';
describe('Pipelines Table Row', () => {
const jsonFixtureName = 'pipelines/pipelines.json';
- const createWrapper = pipeline =>
+ const createWrapper = (pipeline) =>
mount(PipelinesTableRowComponent, {
propsData: {
pipeline,
@@ -24,9 +24,9 @@ describe('Pipelines Table Row', () => {
beforeEach(() => {
const { pipelines } = getJSONFixture(jsonFixtureName);
- pipeline = pipelines.find(p => p.user !== null && p.commit !== null);
- pipelineWithoutAuthor = pipelines.find(p => p.user === null && p.commit !== null);
- pipelineWithoutCommit = pipelines.find(p => p.user === null && p.commit === null);
+ pipeline = pipelines.find((p) => p.user !== null && p.commit !== null);
+ pipelineWithoutAuthor = pipelines.find((p) => p.user === null && p.commit !== null);
+ pipelineWithoutCommit = pipelines.find((p) => p.user === null && p.commit === null);
});
afterEach(() => {
@@ -82,10 +82,7 @@ describe('Pipelines Table Row', () => {
).toEqual(pipeline.user.path);
expect(
- wrapper
- .find('.table-section:nth-child(3) .js-user-avatar-image-toolip')
- .text()
- .trim(),
+ wrapper.find('.table-section:nth-child(3) .js-user-avatar-image-tooltip').text().trim(),
).toEqual(pipeline.user.name);
});
});
@@ -112,7 +109,7 @@ describe('Pipelines Table Row', () => {
const commitAuthorLink = commitAuthorElement.attributes('href');
const commitAuthorName = commitAuthorElement
- .find('.js-user-avatar-image-toolip')
+ .find('.js-user-avatar-image-tooltip')
.text()
.trim();
@@ -190,7 +187,7 @@ describe('Pipelines Table Row', () => {
});
it('emits `retryPipeline` event when retry button is clicked and toggles loading', () => {
- eventHub.$on('retryPipeline', endpoint => {
+ eventHub.$on('retryPipeline', (endpoint) => {
expect(endpoint).toBe('/retry');
});
@@ -199,7 +196,7 @@ describe('Pipelines Table Row', () => {
});
it('emits `openConfirmationModal` event when cancel button is clicked and toggles loading', () => {
- eventHub.$once('openConfirmationModal', data => {
+ eventHub.$once('openConfirmationModal', (data) => {
const { id, ref, commit } = pipeline;
expect(data.endpoint).toBe('/cancel');
@@ -215,7 +212,7 @@ describe('Pipelines Table Row', () => {
wrapper.find('.js-pipelines-cancel-button').trigger('click');
});
- it('renders a loading icon when `cancelingPipeline` matches pipeline id', done => {
+ it('renders a loading icon when `cancelingPipeline` matches pipeline id', (done) => {
wrapper.setProps({ cancelingPipeline: pipeline.id });
wrapper.vm
.$nextTick()
diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js
index c7d104bbde8..fd73d507919 100644
--- a/spec/frontend/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_spec.js
@@ -24,7 +24,7 @@ describe('Pipelines Table', () => {
beforeEach(() => {
const { pipelines } = getJSONFixture(jsonFixtureName);
- pipeline = pipelines.find(p => p.user !== null && p.commit !== null);
+ pipeline = pipelines.find((p) => p.user !== null && p.commit !== null);
createComponent();
});
diff --git a/spec/frontend/pipelines/shared/links_layer_spec.js b/spec/frontend/pipelines/shared/links_layer_spec.js
new file mode 100644
index 00000000000..9ef5233dbce
--- /dev/null
+++ b/spec/frontend/pipelines/shared/links_layer_spec.js
@@ -0,0 +1,99 @@
+import { mount, shallowMount } from '@vue/test-utils';
+import { GlAlert, GlButton } from '@gitlab/ui';
+import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue';
+import LinksInner from '~/pipelines/components/graph_shared/links_inner.vue';
+import { generateResponse, mockPipelineResponse } from '../graph/mock_data';
+
+describe('links layer component', () => {
+ let wrapper;
+
+ const findAlert = () => wrapper.find(GlAlert);
+ const findShowAnyways = () => findAlert().find(GlButton);
+ const findLinksInner = () => wrapper.find(LinksInner);
+
+ const pipeline = generateResponse(mockPipelineResponse, 'root/fungi-xoxo');
+ const containerId = `pipeline-links-container-${pipeline.id}`;
+ const slotContent = "<div>Ceci n'est pas un graphique</div>";
+
+ const tooManyStages = Array(101)
+ .fill(0)
+ .flatMap(() => pipeline.stages);
+
+ const defaultProps = {
+ containerId,
+ containerMeasurements: { width: 400, height: 400 },
+ pipelineId: pipeline.id,
+ pipelineData: pipeline.stages,
+ };
+
+ const createComponent = ({ mountFn = shallowMount, props = {} } = {}) => {
+ wrapper = mountFn(LinksLayer, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ slots: {
+ default: slotContent,
+ },
+ stubs: {
+ 'links-inner': true,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('with data under max stages', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the default slot', () => {
+ expect(wrapper.html()).toContain(slotContent);
+ });
+
+ it('renders the inner links component', () => {
+ expect(findLinksInner().exists()).toBe(true);
+ });
+ });
+
+ describe('with more than the max number of stages', () => {
+ describe('rendering', () => {
+ beforeEach(() => {
+ createComponent({ props: { pipelineData: tooManyStages } });
+ });
+
+ it('renders the default slot', () => {
+ expect(wrapper.html()).toContain(slotContent);
+ });
+
+ it('renders the alert component', () => {
+ expect(findAlert().exists()).toBe(true);
+ });
+
+ it('does not render the inner links component', () => {
+ expect(findLinksInner().exists()).toBe(false);
+ });
+ });
+
+ describe('interactions', () => {
+ beforeEach(() => {
+ createComponent({ mountFn: mount, props: { pipelineData: tooManyStages } });
+ });
+
+ it('renders the disable button', () => {
+ expect(findShowAnyways().exists()).toBe(true);
+ expect(findShowAnyways().text()).toBe(wrapper.vm.$options.i18n.showLinksAnyways);
+ });
+
+ it('shows links when override is clicked', async () => {
+ expect(findLinksInner().exists()).toBe(false);
+ await findShowAnyways().trigger('click');
+ expect(findLinksInner().exists()).toBe(true);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/pipelines/stage_spec.js b/spec/frontend/pipelines/stage_spec.js
index e134b81856b..e4782a1dab1 100644
--- a/spec/frontend/pipelines/stage_spec.js
+++ b/spec/frontend/pipelines/stage_spec.js
@@ -1,6 +1,6 @@
+import 'bootstrap/js/dist/dropdown';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
-import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
import StageComponent from '~/pipelines/components/pipelines_list/stage.vue';
import eventHub from '~/pipelines/event_hub';
@@ -22,8 +22,11 @@ describe('Pipelines stage component', () => {
updateDropdown: false,
};
+ const isDropdownOpen = () => wrapper.classes('show');
+
const createComponent = (props = {}) => {
wrapper = mount(StageComponent, {
+ attachTo: document.body,
propsData: {
...defaultProps,
...props,
@@ -60,38 +63,29 @@ describe('Pipelines stage component', () => {
createComponent();
});
- it('should render the received data and emit `clickedDropdown` event', () => {
+ it('should render the received data and emit `clickedDropdown` event', async () => {
jest.spyOn(eventHub, '$emit');
wrapper.find('button').trigger('click');
- return waitForPromises().then(() => {
- expect(wrapper.find('.js-builds-dropdown-container ul').text()).toContain(
- stageReply.latest_statuses[0].name,
- );
+ await axios.waitForAll();
+ expect(wrapper.find('.js-builds-dropdown-container ul').text()).toContain(
+ stageReply.latest_statuses[0].name,
+ );
- expect(eventHub.$emit).toHaveBeenCalledWith('clickedDropdown');
- });
+ expect(eventHub.$emit).toHaveBeenCalledWith('clickedDropdown');
});
});
- describe('when request fails', () => {
- beforeEach(() => {
- mock.onGet('path.json').reply(500);
- createComponent();
- });
+ it('when request fails should close the dropdown', async () => {
+ mock.onGet('path.json').reply(500);
+ createComponent();
+ wrapper.find({ ref: 'dropdown' }).trigger('click');
+ expect(isDropdownOpen()).toBe(true);
- it('should close the dropdown', () => {
- wrapper.setMethods({
- closeDropdown: jest.fn(),
- isDropdownOpen: jest.fn().mockReturnValue(false),
- });
+ wrapper.find('button').trigger('click');
+ await axios.waitForAll();
- wrapper.find('button').trigger('click');
-
- return waitForPromises().then(() => {
- expect(wrapper.vm.closeDropdown).toHaveBeenCalled();
- });
- });
+ expect(isDropdownOpen()).toBe(false);
});
describe('update endpoint correctly', () => {
@@ -109,47 +103,38 @@ describe('Pipelines stage component', () => {
dropdown_path: 'bar.json',
},
});
+ return axios.waitForAll();
});
- it('should update the stage to request the new endpoint provided', () => {
- return wrapper.vm
- .$nextTick()
- .then(() => {
- wrapper.find('button').trigger('click');
- return waitForPromises();
- })
- .then(() => {
- expect(wrapper.find('.js-builds-dropdown-container ul').text()).toContain(
- 'this is the updated content',
- );
- });
+ it('should update the stage to request the new endpoint provided', async () => {
+ wrapper.find('button').trigger('click');
+ await axios.waitForAll();
+
+ expect(wrapper.find('.js-builds-dropdown-container ul').text()).toContain(
+ 'this is the updated content',
+ );
});
});
describe('pipelineActionRequestComplete', () => {
beforeEach(() => {
mock.onGet('path.json').reply(200, stageReply);
-
mock.onPost(`${stageReply.latest_statuses[0].status.action.path}.json`).reply(200);
createComponent({ type: 'PIPELINES_TABLE' });
});
describe('within pipeline table', () => {
- it('emits `refreshPipelinesTable` event when `pipelineActionRequestComplete` is triggered', () => {
+ it('emits `refreshPipelinesTable` event when `pipelineActionRequestComplete` is triggered', async () => {
jest.spyOn(eventHub, '$emit');
wrapper.find('button').trigger('click');
+ await axios.waitForAll();
- return waitForPromises()
- .then(() => {
- wrapper.find('.js-ci-action').trigger('click');
+ wrapper.find('.js-ci-action').trigger('click');
+ await axios.waitForAll();
- return waitForPromises();
- })
- .then(() => {
- expect(eventHub.$emit).toHaveBeenCalledWith('refreshPipelinesTable');
- });
+ expect(eventHub.$emit).toHaveBeenCalledWith('refreshPipelinesTable');
});
});
});
diff --git a/spec/frontend/pipelines/stores/pipeline_store_spec.js b/spec/frontend/pipelines/stores/pipeline_store_spec.js
index 68d438109b3..2daf7e4b324 100644
--- a/spec/frontend/pipelines/stores/pipeline_store_spec.js
+++ b/spec/frontend/pipelines/stores/pipeline_store_spec.js
@@ -32,14 +32,14 @@ describe('EE Pipeline store', () => {
describe('triggered', () => {
it('adds isExpanding & isLoading keys set to false for each triggered pipeline', () => {
- store.state.pipeline.triggered.forEach(pipeline => {
+ store.state.pipeline.triggered.forEach((pipeline) => {
expect(pipeline.isExpanded).toEqual(false);
expect(pipeline.isLoading).toEqual(false);
});
});
it('parses nested triggered pipelines', () => {
- store.state.pipeline.triggered[1].triggered.forEach(pipeline => {
+ store.state.pipeline.triggered[1].triggered.forEach((pipeline) => {
expect(pipeline.isExpanded).toEqual(false);
expect(pipeline.isLoading).toEqual(false);
});
diff --git a/spec/frontend/pipelines/test_reports/stores/actions_spec.js b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
index 1809f15a6e6..f7ff36c0a46 100644
--- a/spec/frontend/pipelines/test_reports/stores/actions_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
@@ -1,10 +1,10 @@
import MockAdapter from 'axios-mock-adapter';
import { getJSONFixture } from 'helpers/fixtures';
+import { TEST_HOST } from 'helpers/test_constants';
+import testAction from 'helpers/vuex_action_helper';
import axios from '~/lib/utils/axios_utils';
import * as actions from '~/pipelines/stores/test_reports/actions';
import * as types from '~/pipelines/stores/test_reports/mutation_types';
-import { TEST_HOST } from '../../../helpers/test_constants';
-import testAction from '../../../helpers/vuex_action_helper';
import { deprecatedCreateFlash as createFlash } from '~/flash';
jest.mock('~/flash.js');
@@ -39,7 +39,7 @@ describe('Actions TestReports Store', () => {
mock.onGet(summaryEndpoint).replyOnce(200, summary, {});
});
- it('sets testReports and shows tests', done => {
+ it('sets testReports and shows tests', (done) => {
testAction(
actions.fetchSummary,
null,
@@ -50,7 +50,7 @@ describe('Actions TestReports Store', () => {
);
});
- it('should create flash on API error', done => {
+ it('should create flash on API error', (done) => {
testAction(
actions.fetchSummary,
null,
@@ -75,7 +75,7 @@ describe('Actions TestReports Store', () => {
.replyOnce(200, testReports.test_suites[0], {});
});
- it('sets test suite and shows tests', done => {
+ it('sets test suite and shows tests', (done) => {
const suite = testReports.test_suites[0];
const index = 0;
@@ -89,7 +89,7 @@ describe('Actions TestReports Store', () => {
);
});
- it('should create flash on API error', done => {
+ it('should create flash on API error', (done) => {
const index = 0;
testAction(
@@ -106,7 +106,7 @@ describe('Actions TestReports Store', () => {
});
describe('when we already have the suite data', () => {
- it('should not fetch suite', done => {
+ it('should not fetch suite', (done) => {
const index = 0;
testReports.test_suites[0].hasFullSuite = true;
@@ -116,7 +116,7 @@ describe('Actions TestReports Store', () => {
});
describe('set selected suite index', () => {
- it('sets selectedSuiteIndex', done => {
+ it('sets selectedSuiteIndex', (done) => {
const selectedSuiteIndex = 0;
testAction(
@@ -131,7 +131,7 @@ describe('Actions TestReports Store', () => {
});
describe('remove selected suite index', () => {
- it('sets selectedSuiteIndex to null', done => {
+ it('sets selectedSuiteIndex to null', (done) => {
testAction(
actions.removeSelectedSuiteIndex,
{},
@@ -144,11 +144,11 @@ describe('Actions TestReports Store', () => {
});
describe('toggles loading', () => {
- it('sets isLoading to true', done => {
+ it('sets isLoading to true', (done) => {
testAction(actions.toggleLoading, {}, state, [{ type: types.TOGGLE_LOADING }], [], done);
});
- it('toggles isLoading to false', done => {
+ it('toggles isLoading to false', (done) => {
testAction(
actions.toggleLoading,
{},
diff --git a/spec/frontend/pipelines/test_reports/stores/getters_spec.js b/spec/frontend/pipelines/test_reports/stores/getters_spec.js
index 8cef499fdb9..7382a6beefa 100644
--- a/spec/frontend/pipelines/test_reports/stores/getters_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/getters_spec.js
@@ -40,7 +40,7 @@ describe('Getters TestReports Store', () => {
setupState();
const suites = getters.getTestSuites(state);
- const expected = testReports.test_suites.map(x => ({
+ const expected = testReports.test_suites.map((x) => ({
...x,
formattedTime: formattedTime(x.total_time),
}));
@@ -72,7 +72,7 @@ describe('Getters TestReports Store', () => {
const cases = getters.getSuiteTests(state);
const expected = testReports.test_suites[0].test_cases
- .map(x => ({
+ .map((x) => ({
...x,
formattedTime: formattedTime(x.execution_time),
icon: iconForTestStatus(x.status),
diff --git a/spec/frontend/pipelines/test_reports/test_case_details_spec.js b/spec/frontend/pipelines/test_reports/test_case_details_spec.js
index 9e66012818e..bfb8b43778d 100644
--- a/spec/frontend/pipelines/test_reports/test_case_details_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_case_details_spec.js
@@ -44,7 +44,7 @@ describe('Test case details', () => {
});
it('renders the test case classname as modal title', () => {
- expect(findModal().attributes('title')).toBe(defaultTestCase.classname);
+ expect(findModal().props('title')).toBe(defaultTestCase.classname);
});
it('renders the test case name', () => {
diff --git a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
index 0e00ca670a7..b8fd056610b 100644
--- a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
@@ -23,7 +23,7 @@ describe('Test reports suite table', () => {
const noCasesMessage = () => wrapper.find('.js-no-test-cases');
const allCaseRows = () => wrapper.findAll('.js-case-row');
- const findCaseRowAtIndex = index => wrapper.findAll('.js-case-row').at(index);
+ const findCaseRowAtIndex = (index) => wrapper.findAll('.js-case-row').at(index);
const findIconForRow = (row, status) => row.find(`.ci-status-icon-${status}`);
const createComponent = (suite = testSuite, perPage = 20) => {
@@ -73,8 +73,8 @@ describe('Test reports suite table', () => {
TestStatus.SKIPPED,
TestStatus.SUCCESS,
'unknown',
- ])('renders the correct icon for test case with %s status', status => {
- const test = testCases.findIndex(x => x.status === status);
+ ])('renders the correct icon for test case with %s status', (status) => {
+ const test = testCases.findIndex((x) => x.status === status);
const row = findCaseRowAtIndex(test);
expect(findIconForRow(row, status).exists()).toBe(true);
diff --git a/spec/frontend/pipelines/test_reports/test_summary_spec.js b/spec/frontend/pipelines/test_reports/test_summary_spec.js
index dc5af7b160c..df404d87c99 100644
--- a/spec/frontend/pipelines/test_reports/test_summary_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_summary_spec.js
@@ -22,7 +22,7 @@ describe('Test reports summary', () => {
showBack: false,
};
- const createComponent = props => {
+ const createComponent = (props) => {
wrapper = mount(Summary, {
propsData: {
...defaultProps,
diff --git a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
index 375325c0c6a..371ba5a4f9b 100644
--- a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
@@ -26,7 +26,7 @@ describe('Pipeline Trigger Author Token', () => {
},
};
- const createComponent = data => {
+ const createComponent = (data) => {
wrapper = shallowMount(PipelineTriggerAuthorToken, {
propsData: {
...defaultProps,
diff --git a/spec/frontend/pipelines/unwrapping_utils_spec.js b/spec/frontend/pipelines/unwrapping_utils_spec.js
index 3533599611f..cd16ed7262e 100644
--- a/spec/frontend/pipelines/unwrapping_utils_spec.js
+++ b/spec/frontend/pipelines/unwrapping_utils_spec.js
@@ -1,5 +1,4 @@
import {
- unwrapArrayOfJobs,
unwrapGroups,
unwrapNodesWithName,
unwrapStagesWithNeeds,
@@ -89,35 +88,12 @@ const completeMock = [
{
...basicStageInfo,
groups: {
- nodes: groupsArray.map(group => ({ ...group, jobs: { nodes: jobArrayWithNeeds } })),
+ nodes: groupsArray.map((group) => ({ ...group, jobs: { nodes: jobArrayWithNeeds } })),
},
},
];
describe('Shared pipeline unwrapping utils', () => {
- describe('unwrapArrayOfJobs', () => {
- it('returns an empty array if the input is an empty undefined', () => {
- expect(unwrapArrayOfJobs(undefined)).toEqual([]);
- });
-
- it('returns an empty array if the input is an empty array', () => {
- expect(unwrapArrayOfJobs([])).toEqual([]);
- });
-
- it('returns a flatten array of each job with their data and stage name', () => {
- expect(
- unwrapArrayOfJobs([
- { name: 'build', groups: [{ name: 'job_a_1' }, { name: 'job_a_2' }] },
- { name: 'test', groups: [{ name: 'job_b' }] },
- ]),
- ).toMatchObject([
- { category: 'build', name: 'job_a_1' },
- { category: 'build', name: 'job_a_2' },
- { category: 'test', name: 'job_b' },
- ]);
- });
- });
-
describe('unwrapGroups', () => {
it('takes stages without nodes and returns the unwrapped groups', () => {
expect(unwrapGroups(stagesAndGroups)[0].groups).toEqual(groupsArray);