summaryrefslogtreecommitdiff
path: root/spec/frontend/pipelines
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/pipelines')
-rw-r--r--spec/frontend/pipelines/components/dag/dag_spec.js119
-rw-r--r--spec/frontend/pipelines/components/dag/drawing_utils_spec.js4
-rw-r--r--spec/frontend/pipelines/components/dag/mock_data.js436
-rw-r--r--spec/frontend/pipelines/components/dag/parsing_utils_spec.js69
-rw-r--r--spec/frontend/pipelines/components/pipelines_filtered_search_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/action_component_spec.js3
-rw-r--r--spec/frontend/pipelines/graph/graph_component_spec.js2
-rw-r--r--spec/frontend/pipelines/graph/linked_pipeline_spec.js20
-rw-r--r--spec/frontend/pipelines/header_component_spec.js6
-rw-r--r--spec/frontend/pipelines/pipeline_details_mediator_spec.js2
-rw-r--r--spec/frontend/pipelines/pipelines_actions_spec.js4
-rw-r--r--spec/frontend/pipelines/pipelines_artifacts_spec.js2
-rw-r--r--spec/frontend/pipelines/pipelines_spec.js10
-rw-r--r--spec/frontend/pipelines/stage_spec.js2
-rw-r--r--spec/frontend/pipelines/test_reports/stores/actions_spec.js124
-rw-r--r--spec/frontend/pipelines/test_reports/stores/mutations_spec.js33
-rw-r--r--spec/frontend/pipelines/test_reports/test_reports_spec.js28
-rw-r--r--spec/frontend/pipelines/test_reports/test_suite_table_spec.js20
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js2
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js2
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js2
21 files changed, 496 insertions, 398 deletions
diff --git a/spec/frontend/pipelines/components/dag/dag_spec.js b/spec/frontend/pipelines/components/dag/dag_spec.js
index 7dea6d819b9..989f6c17197 100644
--- a/spec/frontend/pipelines/components/dag/dag_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_spec.js
@@ -1,7 +1,4 @@
import { mount, shallowMount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import waitForPromises from 'helpers/wait_for_promises';
import { GlAlert, GlEmptyState } from '@gitlab/ui';
import Dag from '~/pipelines/components/dag/dag.vue';
import DagGraph from '~/pipelines/components/dag/dag_graph.vue';
@@ -11,13 +8,11 @@ import {
ADD_NOTE,
REMOVE_NOTE,
REPLACE_NOTES,
- DEFAULT,
PARSE_FAILURE,
- LOAD_FAILURE,
UNSUPPORTED_DATA,
} from '~/pipelines/components/dag//constants';
import {
- mockBaseData,
+ mockParsedGraphQLNodes,
tooSmallGraph,
unparseableGraph,
graphWithoutDependencies,
@@ -27,7 +22,6 @@ import {
describe('Pipeline DAG graph wrapper', () => {
let wrapper;
- let mock;
const getAlert = () => wrapper.find(GlAlert);
const getAllAlerts = () => wrapper.findAll(GlAlert);
const getGraph = () => wrapper.find(DagGraph);
@@ -35,45 +29,46 @@ describe('Pipeline DAG graph wrapper', () => {
const getErrorText = type => wrapper.vm.$options.errorTexts[type];
const getEmptyState = () => wrapper.find(GlEmptyState);
- const dataPath = '/root/test/pipelines/90/dag.json';
-
- const createComponent = (propsData = {}, method = shallowMount) => {
+ const createComponent = ({
+ graphData = mockParsedGraphQLNodes,
+ provideOverride = {},
+ method = shallowMount,
+ } = {}) => {
if (wrapper?.destroy) {
wrapper.destroy();
}
wrapper = method(Dag, {
- propsData: {
+ provide: {
+ pipelineProjectPath: 'root/abc-dag',
+ pipelineIid: '1',
emptySvgPath: '/my-svg',
dagDocPath: '/my-doc',
- ...propsData,
+ ...provideOverride,
},
data() {
return {
+ graphData,
showFailureAlert: false,
};
},
});
};
- beforeEach(() => {
- mock = new MockAdapter(axios);
- });
-
afterEach(() => {
- mock.restore();
wrapper.destroy();
wrapper = null;
});
- describe('when there is no dataUrl', () => {
+ describe('when a query argument is undefined', () => {
beforeEach(() => {
- createComponent({ graphUrl: undefined });
+ createComponent({
+ provideOverride: { pipelineProjectPath: undefined },
+ graphData: null,
+ });
});
- it('shows the DEFAULT alert and not the graph', () => {
- expect(getAlert().exists()).toBe(true);
- expect(getAlert().text()).toBe(getErrorText(DEFAULT));
+ it('does not render the graph', async () => {
expect(getGraph().exists()).toBe(false);
});
@@ -82,36 +77,12 @@ describe('Pipeline DAG graph wrapper', () => {
});
});
- describe('when there is a dataUrl', () => {
- describe('but the data fetch fails', () => {
+ describe('when all query variables are defined', () => {
+ describe('but the parse fails', () => {
beforeEach(async () => {
- mock.onGet(dataPath).replyOnce(500);
- createComponent({ graphUrl: dataPath });
-
- await wrapper.vm.$nextTick();
-
- return waitForPromises();
- });
-
- it('shows the LOAD_FAILURE alert and not the graph', () => {
- expect(getAlert().exists()).toBe(true);
- expect(getAlert().text()).toBe(getErrorText(LOAD_FAILURE));
- expect(getGraph().exists()).toBe(false);
- });
-
- it('does not render the empty state', () => {
- expect(getEmptyState().exists()).toBe(false);
- });
- });
-
- describe('the data fetch succeeds but the parse fails', () => {
- beforeEach(async () => {
- mock.onGet(dataPath).replyOnce(200, unparseableGraph);
- createComponent({ graphUrl: dataPath });
-
- await wrapper.vm.$nextTick();
-
- return waitForPromises();
+ createComponent({
+ graphData: unparseableGraph,
+ });
});
it('shows the PARSE_FAILURE alert and not the graph', () => {
@@ -125,19 +96,12 @@ describe('Pipeline DAG graph wrapper', () => {
});
});
- describe('and the data fetch and parse succeeds', () => {
+ describe('parse succeeds', () => {
beforeEach(async () => {
- mock.onGet(dataPath).replyOnce(200, mockBaseData);
- createComponent({ graphUrl: dataPath }, mount);
-
- await wrapper.vm.$nextTick();
-
- return waitForPromises();
+ createComponent({ method: mount });
});
- it('shows the graph and the beta alert', () => {
- expect(getAllAlerts().length).toBe(1);
- expect(getAlert().text()).toContain('This feature is currently in beta.');
+ it('shows the graph', () => {
expect(getGraph().exists()).toBe(true);
});
@@ -146,14 +110,11 @@ describe('Pipeline DAG graph wrapper', () => {
});
});
- describe('the data fetch and parse succeeds, but the resulting graph is too small', () => {
+ describe('parse succeeds, but the resulting graph is too small', () => {
beforeEach(async () => {
- mock.onGet(dataPath).replyOnce(200, tooSmallGraph);
- createComponent({ graphUrl: dataPath });
-
- await wrapper.vm.$nextTick();
-
- return waitForPromises();
+ createComponent({
+ graphData: tooSmallGraph,
+ });
});
it('shows the UNSUPPORTED_DATA alert and not the graph', () => {
@@ -167,19 +128,16 @@ describe('Pipeline DAG graph wrapper', () => {
});
});
- describe('the data fetch succeeds but the returned data is empty', () => {
+ describe('the returned data is empty', () => {
beforeEach(async () => {
- mock.onGet(dataPath).replyOnce(200, graphWithoutDependencies);
- createComponent({ graphUrl: dataPath }, mount);
-
- await wrapper.vm.$nextTick();
-
- return waitForPromises();
+ createComponent({
+ method: mount,
+ graphData: graphWithoutDependencies,
+ });
});
it('does not render an error alert or the graph', () => {
- expect(getAllAlerts().length).toBe(1);
- expect(getAlert().text()).toContain('This feature is currently in beta.');
+ expect(getAllAlerts().length).toBe(0);
expect(getGraph().exists()).toBe(false);
});
@@ -191,12 +149,7 @@ describe('Pipeline DAG graph wrapper', () => {
describe('annotations', () => {
beforeEach(async () => {
- mock.onGet(dataPath).replyOnce(200, mockBaseData);
- createComponent({ graphUrl: dataPath }, mount);
-
- await wrapper.vm.$nextTick();
-
- return waitForPromises();
+ createComponent();
});
it('toggles on link mouseover and mouseout', async () => {
diff --git a/spec/frontend/pipelines/components/dag/drawing_utils_spec.js b/spec/frontend/pipelines/components/dag/drawing_utils_spec.js
index a50163411ed..37a7d07485b 100644
--- a/spec/frontend/pipelines/components/dag/drawing_utils_spec.js
+++ b/spec/frontend/pipelines/components/dag/drawing_utils_spec.js
@@ -1,9 +1,9 @@
import { createSankey } from '~/pipelines/components/dag/drawing_utils';
import { parseData } from '~/pipelines/components/dag/parsing_utils';
-import { mockBaseData } from './mock_data';
+import { mockParsedGraphQLNodes } from './mock_data';
describe('DAG visualization drawing utilities', () => {
- const parsed = parseData(mockBaseData.stages);
+ const parsed = parseData(mockParsedGraphQLNodes);
const layoutSettings = {
width: 200,
diff --git a/spec/frontend/pipelines/components/dag/mock_data.js b/spec/frontend/pipelines/components/dag/mock_data.js
index 3b39b9cd21c..e7e93804195 100644
--- a/spec/frontend/pipelines/components/dag/mock_data.js
+++ b/spec/frontend/pipelines/components/dag/mock_data.js
@@ -1,127 +1,56 @@
-/*
- It is important that the simple base include parallel jobs
- as well as non-parallel jobs with spaces in the name to prevent
- us relying on spaces as an indicator.
-*/
-export const mockBaseData = {
- stages: [
- {
- name: 'test',
- groups: [
- {
- name: 'jest',
- size: 2,
- jobs: [{ name: 'jest 1/2', needs: ['frontend fixtures'] }, { name: 'jest 2/2' }],
- },
- {
- name: 'rspec',
- size: 1,
- jobs: [{ name: 'rspec', needs: ['frontend fixtures'] }],
- },
- ],
- },
- {
- name: 'fixtures',
- groups: [
- {
- name: 'frontend fixtures',
- size: 1,
- jobs: [{ name: 'frontend fixtures' }],
- },
- ],
- },
- {
- name: 'un-needed',
- groups: [
- {
- name: 'un-needed',
- size: 1,
- jobs: [{ name: 'un-needed' }],
- },
- ],
- },
- ],
-};
-
-export const tooSmallGraph = {
- stages: [
- {
- name: 'test',
- groups: [
- {
- name: 'jest',
- size: 2,
- jobs: [{ name: 'jest 1/2' }, { name: 'jest 2/2' }],
- },
- {
- name: 'rspec',
- size: 1,
- jobs: [{ name: 'rspec', needs: ['frontend fixtures'] }],
- },
- ],
- },
- {
- name: 'fixtures',
- groups: [
- {
- name: 'frontend fixtures',
- size: 1,
- jobs: [{ name: 'frontend fixtures' }],
- },
- ],
- },
- {
- name: 'un-needed',
- groups: [
- {
- name: 'un-needed',
- size: 1,
- jobs: [{ name: 'un-needed' }],
- },
- ],
- },
- ],
-};
+export const tooSmallGraph = [
+ {
+ category: 'test',
+ name: 'jest',
+ size: 2,
+ jobs: [{ name: 'jest 1/2' }, { name: 'jest 2/2' }],
+ },
+ {
+ category: 'test',
+ name: 'rspec',
+ size: 1,
+ jobs: [{ name: 'rspec', needs: ['frontend fixtures'] }],
+ },
+ {
+ category: 'fixtures',
+ name: 'frontend fixtures',
+ size: 1,
+ jobs: [{ name: 'frontend fixtures' }],
+ },
+ {
+ category: 'un-needed',
+ name: 'un-needed',
+ size: 1,
+ jobs: [{ name: 'un-needed' }],
+ },
+];
-export const graphWithoutDependencies = {
- stages: [
- {
- name: 'test',
- groups: [
- {
- name: 'jest',
- size: 2,
- jobs: [{ name: 'jest 1/2' }, { name: 'jest 2/2' }],
- },
- {
- name: 'rspec',
- size: 1,
- jobs: [{ name: 'rspec' }],
- },
- ],
- },
- {
- name: 'fixtures',
- groups: [
- {
- name: 'frontend fixtures',
- size: 1,
- jobs: [{ name: 'frontend fixtures' }],
- },
- ],
- },
- {
- name: 'un-needed',
- groups: [
- {
- name: 'un-needed',
- size: 1,
- jobs: [{ name: 'un-needed' }],
- },
- ],
- },
- ],
-};
+export const graphWithoutDependencies = [
+ {
+ category: 'test',
+ name: 'jest',
+ size: 2,
+ jobs: [{ name: 'jest 1/2' }, { name: 'jest 2/2' }],
+ },
+ {
+ category: 'test',
+ name: 'rspec',
+ size: 1,
+ jobs: [{ name: 'rspec' }],
+ },
+ {
+ category: 'fixtures',
+ name: 'frontend fixtures',
+ size: 1,
+ jobs: [{ name: 'frontend fixtures' }],
+ },
+ {
+ category: 'un-needed',
+ name: 'un-needed',
+ size: 1,
+ jobs: [{ name: 'un-needed' }],
+ },
+];
export const unparseableGraph = [
{
@@ -468,3 +397,264 @@ export const multiNote = {
},
},
};
+
+/*
+ It is important that the base include parallel jobs
+ as well as non-parallel jobs with spaces in the name to prevent
+ us relying on spaces as an indicator.
+*/
+
+export const mockParsedGraphQLNodes = [
+ {
+ category: 'build',
+ name: 'build_a',
+ size: 1,
+ jobs: [
+ {
+ name: 'build_a',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'build',
+ name: 'build_b',
+ size: 1,
+ jobs: [
+ {
+ name: 'build_b',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'test',
+ name: 'test_a',
+ size: 1,
+ jobs: [
+ {
+ name: 'test_a',
+ needs: ['build_a'],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'test',
+ name: 'test_b',
+ size: 1,
+ jobs: [
+ {
+ name: 'test_b',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'test',
+ name: 'test_c',
+ size: 1,
+ jobs: [
+ {
+ name: 'test_c',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'test',
+ name: 'test_d',
+ size: 1,
+ jobs: [
+ {
+ name: 'test_d',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'post-test',
+ name: 'post_test_a',
+ size: 1,
+ jobs: [
+ {
+ name: 'post_test_a',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'post-test',
+ name: 'post_test_b',
+ size: 1,
+ jobs: [
+ {
+ name: 'post_test_b',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'post-test',
+ name: 'post_test_c',
+ size: 1,
+ jobs: [
+ {
+ name: 'post_test_c',
+ needs: ['test_b', 'test_a'],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'staging',
+ name: 'staging_a',
+ size: 1,
+ jobs: [
+ {
+ name: 'staging_a',
+ needs: ['post_test_a'],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'staging',
+ name: 'staging_b',
+ size: 1,
+ jobs: [
+ {
+ name: 'staging_b',
+ needs: ['post_test_b'],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'staging',
+ name: 'staging_c',
+ size: 1,
+ jobs: [
+ {
+ name: 'staging_c',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'staging',
+ name: 'staging_d',
+ size: 1,
+ jobs: [
+ {
+ name: 'staging_d',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'staging',
+ name: 'staging_e',
+ size: 1,
+ jobs: [
+ {
+ name: 'staging_e',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'canary',
+ name: 'canary_a',
+ size: 1,
+ jobs: [
+ {
+ name: 'canary_a',
+ needs: ['staging_b', 'staging_a'],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'canary',
+ name: 'canary_b',
+ size: 1,
+ jobs: [
+ {
+ name: 'canary_b',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'canary',
+ name: 'canary_c',
+ size: 1,
+ jobs: [
+ {
+ name: 'canary_c',
+ needs: ['staging_b'],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'production',
+ name: 'production_a',
+ size: 1,
+ jobs: [
+ {
+ name: 'production_a',
+ needs: ['canary_a'],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'production',
+ name: 'production_b',
+ size: 1,
+ jobs: [
+ {
+ name: 'production_b',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'production',
+ name: 'production_c',
+ size: 1,
+ jobs: [
+ {
+ name: 'production_c',
+ needs: [],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+ {
+ category: 'production',
+ name: 'production_d',
+ size: 1,
+ jobs: [
+ {
+ name: 'production_d',
+ needs: ['canary_c'],
+ },
+ ],
+ __typename: 'CiGroup',
+ },
+];
diff --git a/spec/frontend/pipelines/components/dag/parsing_utils_spec.js b/spec/frontend/pipelines/components/dag/parsing_utils_spec.js
index d9a1296e572..e93fa8e6760 100644
--- a/spec/frontend/pipelines/components/dag/parsing_utils_spec.js
+++ b/spec/frontend/pipelines/components/dag/parsing_utils_spec.js
@@ -1,5 +1,5 @@
import {
- createNodesStructure,
+ createNodeDict,
makeLinksFromNodes,
filterByAncestors,
parseData,
@@ -8,56 +8,17 @@ import {
} from '~/pipelines/components/dag/parsing_utils';
import { createSankey } from '~/pipelines/components/dag/drawing_utils';
-import { mockBaseData } from './mock_data';
+import { mockParsedGraphQLNodes } from './mock_data';
describe('DAG visualization parsing utilities', () => {
- const { nodes, nodeDict } = createNodesStructure(mockBaseData.stages);
- const unfilteredLinks = makeLinksFromNodes(nodes, nodeDict);
- const parsed = parseData(mockBaseData.stages);
-
- const layoutSettings = {
- width: 200,
- height: 200,
- nodeWidth: 10,
- nodePadding: 20,
- paddingForLabels: 100,
- };
-
- const sankeyLayout = createSankey(layoutSettings)(parsed);
-
- describe('createNodesStructure', () => {
- const parallelGroupName = 'jest';
- const parallelJobName = 'jest 1/2';
- const singleJobName = 'frontend fixtures';
-
- const { name, jobs, size } = mockBaseData.stages[0].groups[0];
-
- it('returns the expected node structure', () => {
- expect(nodes[0]).toHaveProperty('category', mockBaseData.stages[0].name);
- expect(nodes[0]).toHaveProperty('name', name);
- expect(nodes[0]).toHaveProperty('jobs', jobs);
- expect(nodes[0]).toHaveProperty('size', size);
- });
-
- it('adds needs to top level of nodeDict entries', () => {
- expect(nodeDict[parallelGroupName]).toHaveProperty('needs');
- expect(nodeDict[parallelJobName]).toHaveProperty('needs');
- expect(nodeDict[singleJobName]).toHaveProperty('needs');
- });
-
- it('makes entries in nodeDict for jobs and parallel jobs', () => {
- const nodeNames = Object.keys(nodeDict);
-
- expect(nodeNames.includes(parallelGroupName)).toBe(true);
- expect(nodeNames.includes(parallelJobName)).toBe(true);
- expect(nodeNames.includes(singleJobName)).toBe(true);
- });
- });
+ const nodeDict = createNodeDict(mockParsedGraphQLNodes);
+ const unfilteredLinks = makeLinksFromNodes(mockParsedGraphQLNodes, nodeDict);
+ const parsed = parseData(mockParsedGraphQLNodes);
describe('makeLinksFromNodes', () => {
it('returns the expected link structure', () => {
- expect(unfilteredLinks[0]).toHaveProperty('source', 'frontend fixtures');
- expect(unfilteredLinks[0]).toHaveProperty('target', 'jest');
+ expect(unfilteredLinks[0]).toHaveProperty('source', 'build_a');
+ expect(unfilteredLinks[0]).toHaveProperty('target', 'test_a');
expect(unfilteredLinks[0]).toHaveProperty('value', 10);
});
});
@@ -107,8 +68,22 @@ describe('DAG visualization parsing utilities', () => {
describe('removeOrphanNodes', () => {
it('removes sankey nodes that have no needs and are not needed', () => {
+ const layoutSettings = {
+ width: 200,
+ height: 200,
+ nodeWidth: 10,
+ nodePadding: 20,
+ paddingForLabels: 100,
+ };
+
+ const sankeyLayout = createSankey(layoutSettings)(parsed);
const cleanedNodes = removeOrphanNodes(sankeyLayout.nodes);
- expect(cleanedNodes).toHaveLength(sankeyLayout.nodes.length - 1);
+ /*
+ These lengths are determined by the mock data.
+ If the data changes, the numbers may also change.
+ */
+ expect(parsed.nodes).toHaveLength(21);
+ expect(cleanedNodes).toHaveLength(12);
});
});
diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
index add7b56845e..c5b7318d3af 100644
--- a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
+++ b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
@@ -1,10 +1,10 @@
-import Api from '~/api';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
+import { GlFilteredSearch } from '@gitlab/ui';
+import Api from '~/api';
import axios from '~/lib/utils/axios_utils';
import PipelinesFilteredSearch from '~/pipelines/components/pipelines_list/pipelines_filtered_search.vue';
import { users, mockSearch, branches, tags } from '../mock_data';
-import { GlFilteredSearch } from '@gitlab/ui';
describe('Pipelines filtered search', () => {
let wrapper;
diff --git a/spec/frontend/pipelines/graph/action_component_spec.js b/spec/frontend/pipelines/graph/action_component_spec.js
index 3c5938cfa1f..ab477292bc1 100644
--- a/spec/frontend/pipelines/graph/action_component_spec.js
+++ b/spec/frontend/pipelines/graph/action_component_spec.js
@@ -1,4 +1,5 @@
import { mount } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
@@ -7,7 +8,7 @@ import ActionComponent from '~/pipelines/components/graph/action_component.vue';
describe('pipeline graph action component', () => {
let wrapper;
let mock;
- const findButton = () => wrapper.find('button');
+ const findButton = () => wrapper.find(GlButton);
beforeEach(() => {
mock = new MockAdapter(axios);
diff --git a/spec/frontend/pipelines/graph/graph_component_spec.js b/spec/frontend/pipelines/graph/graph_component_spec.js
index 9731ce3f8a6..1389649abea 100644
--- a/spec/frontend/pipelines/graph/graph_component_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_spec.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import { mount } from '@vue/test-utils';
+import { setHTMLFixture } from 'helpers/fixtures';
import PipelineStore from '~/pipelines/stores/pipeline_store';
import graphComponent from '~/pipelines/components/graph/graph_component.vue';
import stageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
@@ -7,7 +8,6 @@ import linkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines
import graphJSON from './mock_data';
import linkedPipelineJSON from './linked_pipelines_mock_data';
import PipelinesMediator from '~/pipelines/pipeline_details_mediator';
-import { setHTMLFixture } from 'helpers/fixtures';
describe('graph component', () => {
const store = new PipelineStore();
diff --git a/spec/frontend/pipelines/graph/linked_pipeline_spec.js b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
index 133d5695afb..59121c54ff3 100644
--- a/spec/frontend/pipelines/graph/linked_pipeline_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
@@ -1,4 +1,5 @@
import { mount } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
import LinkedPipelineComponent from '~/pipelines/components/graph/linked_pipeline.vue';
import CiStatus from '~/vue_shared/components/ci_icon.vue';
@@ -12,7 +13,7 @@ const invalidTriggeredPipelineId = mockPipeline.project.id + 5;
describe('Linked pipeline', () => {
let wrapper;
- const findButton = () => wrapper.find('button');
+ const findButton = () => wrapper.find(GlButton);
const findPipelineLabel = () => wrapper.find('[data-testid="downstream-pipeline-label"]');
const findLinkedPipeline = () => wrapper.find({ ref: 'linkedPipeline' });
@@ -42,9 +43,7 @@ describe('Linked pipeline', () => {
});
it('should render a button', () => {
- const linkElement = wrapper.find('.js-linked-pipeline-content');
-
- expect(linkElement.exists()).toBe(true);
+ expect(findButton().exists()).toBe(true);
});
it('should render the project name', () => {
@@ -62,7 +61,7 @@ describe('Linked pipeline', () => {
});
it('should have a ci-status child component', () => {
- expect(wrapper.find('.js-linked-pipeline-status').exists()).toBe(true);
+ expect(wrapper.find(CiStatus).exists()).toBe(true);
});
it('should render the pipeline id', () => {
@@ -77,15 +76,14 @@ describe('Linked pipeline', () => {
});
it('should render the tooltip text as the title attribute', () => {
- const tooltipRef = wrapper.find('.js-linked-pipeline-content');
- const titleAttr = tooltipRef.attributes('title');
+ const titleAttr = findButton().attributes('title');
expect(titleAttr).toContain(mockPipeline.project.name);
expect(titleAttr).toContain(mockPipeline.details.status.label);
});
- it('does not render the loading icon when isLoading is false', () => {
- expect(wrapper.find('.js-linked-pipeline-loading').exists()).toBe(false);
+ it('sets the loading prop to false', () => {
+ expect(findButton().props('loading')).toBe(false);
});
it('should display multi-project label when pipeline project id is not the same as triggered pipeline project id', () => {
@@ -132,8 +130,8 @@ describe('Linked pipeline', () => {
createWrapper(props);
});
- it('renders a loading icon', () => {
- expect(wrapper.find('.js-linked-pipeline-loading').exists()).toBe(true);
+ it('sets the loading prop to true', () => {
+ expect(findButton().props('loading')).toBe(true);
});
});
diff --git a/spec/frontend/pipelines/header_component_spec.js b/spec/frontend/pipelines/header_component_spec.js
index 1c3a6c545a0..5388d624d3c 100644
--- a/spec/frontend/pipelines/header_component_spec.js
+++ b/spec/frontend/pipelines/header_component_spec.js
@@ -1,8 +1,8 @@
import { shallowMount } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
import HeaderComponent from '~/pipelines/components/header_component.vue';
import CiHeader from '~/vue_shared/components/header_ci_component.vue';
import eventHub from '~/pipelines/event_hub';
-import { GlModal } from '@gitlab/ui';
describe('Pipeline details header', () => {
let wrapper;
@@ -85,13 +85,13 @@ describe('Pipeline details header', () => {
});
it('should call postAction when retry button action is clicked', () => {
- wrapper.find('.js-retry-button').vm.$emit('click');
+ wrapper.find('[data-testid="retryButton"]').vm.$emit('click');
expect(eventHub.$emit).toHaveBeenCalledWith('headerPostAction', 'retry');
});
it('should call postAction when cancel button action is clicked', () => {
- wrapper.find('.js-btn-cancel-pipeline').vm.$emit('click');
+ wrapper.find('[data-testid="cancelPipeline"]').vm.$emit('click');
expect(eventHub.$emit).toHaveBeenCalledWith('headerPostAction', 'cancel');
});
diff --git a/spec/frontend/pipelines/pipeline_details_mediator_spec.js b/spec/frontend/pipelines/pipeline_details_mediator_spec.js
index 083e97666ed..d6699a43b54 100644
--- a/spec/frontend/pipelines/pipeline_details_mediator_spec.js
+++ b/spec/frontend/pipelines/pipeline_details_mediator_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
import PipelineMediator from '~/pipelines/pipeline_details_mediator';
-import waitForPromises from 'helpers/wait_for_promises';
describe('PipelineMdediator', () => {
let mediator;
diff --git a/spec/frontend/pipelines/pipelines_actions_spec.js b/spec/frontend/pipelines/pipelines_actions_spec.js
index aef54d94974..cce4c2dfa7b 100644
--- a/spec/frontend/pipelines/pipelines_actions_spec.js
+++ b/spec/frontend/pipelines/pipelines_actions_spec.js
@@ -1,11 +1,11 @@
import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'spec/test_constants';
+import { GlDeprecatedButton } from '@gitlab/ui';
+import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
import PipelinesActions from '~/pipelines/components/pipelines_list/pipelines_actions.vue';
-import { GlDeprecatedButton } from '@gitlab/ui';
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
-import waitForPromises from 'helpers/wait_for_promises';
describe('Pipelines Actions dropdown', () => {
let wrapper;
diff --git a/spec/frontend/pipelines/pipelines_artifacts_spec.js b/spec/frontend/pipelines/pipelines_artifacts_spec.js
index 512205c3fc3..83f6cb68eba 100644
--- a/spec/frontend/pipelines/pipelines_artifacts_spec.js
+++ b/spec/frontend/pipelines/pipelines_artifacts_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
-import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
import { GlLink } from '@gitlab/ui';
+import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
describe('Pipelines Artifacts dropdown', () => {
let wrapper;
diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js
index 66446b9aa1d..b0ad6bbd228 100644
--- a/spec/frontend/pipelines/pipelines_spec.js
+++ b/spec/frontend/pipelines/pipelines_spec.js
@@ -1,16 +1,16 @@
-import Api from '~/api';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
import waitForPromises from 'helpers/wait_for_promises';
+import { GlFilteredSearch } from '@gitlab/ui';
+import Api from '~/api';
+import axios from '~/lib/utils/axios_utils';
import PipelinesComponent from '~/pipelines/components/pipelines_list/pipelines.vue';
import Store from '~/pipelines/stores/pipelines_store';
import { pipelineWithStages, stageReply, users, mockSearch, branches } from './mock_data';
import { RAW_TEXT_WARNING } from '~/pipelines/constants';
-import { GlFilteredSearch } from '@gitlab/ui';
-import createFlash from '~/flash';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
-jest.mock('~/flash', () => jest.fn());
+jest.mock('~/flash');
describe('Pipelines', () => {
const jsonFixtureName = 'pipelines/pipelines.json';
diff --git a/spec/frontend/pipelines/stage_spec.js b/spec/frontend/pipelines/stage_spec.js
index 547f8994ca5..e134b81856b 100644
--- a/spec/frontend/pipelines/stage_spec.js
+++ b/spec/frontend/pipelines/stage_spec.js
@@ -1,10 +1,10 @@
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';
import { stageReply } from './mock_data';
-import waitForPromises from 'helpers/wait_for_promises';
describe('Pipelines stage component', () => {
let wrapper;
diff --git a/spec/frontend/pipelines/test_reports/stores/actions_spec.js b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
index d4647c55a53..1809f15a6e6 100644
--- a/spec/frontend/pipelines/test_reports/stores/actions_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
@@ -5,7 +5,7 @@ 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 createFlash from '~/flash';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
jest.mock('~/flash.js');
@@ -16,14 +16,13 @@ describe('Actions TestReports Store', () => {
const testReports = getJSONFixture('pipelines/test_report.json');
const summary = { total_count: 1 };
- const fullReportEndpoint = `${TEST_HOST}/test_reports.json`;
+ const suiteEndpoint = `${TEST_HOST}/tests/:suite_name.json`;
const summaryEndpoint = `${TEST_HOST}/test_reports/summary.json`;
const defaultState = {
- fullReportEndpoint,
+ suiteEndpoint,
summaryEndpoint,
testReports: {},
selectedSuite: null,
- useBuildSummaryReport: false,
};
beforeEach(() => {
@@ -40,89 +39,63 @@ describe('Actions TestReports Store', () => {
mock.onGet(summaryEndpoint).replyOnce(200, summary, {});
});
- describe('when useBuildSummaryReport in state is true', () => {
- it('sets testReports and shows tests', done => {
- testAction(
- actions.fetchSummary,
- null,
- { ...state, useBuildSummaryReport: true },
- [{ type: types.SET_SUMMARY, payload: summary }],
- [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
- done,
- );
- });
-
- it('should create flash on API error', done => {
- testAction(
- actions.fetchSummary,
- null,
- {
- summaryEndpoint: null,
- useBuildSummaryReport: true,
- },
- [],
- [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
- () => {
- expect(createFlash).toHaveBeenCalled();
- done();
- },
- );
- });
+ it('sets testReports and shows tests', done => {
+ testAction(
+ actions.fetchSummary,
+ null,
+ state,
+ [{ type: types.SET_SUMMARY, payload: summary }],
+ [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
+ done,
+ );
});
- describe('when useBuildSummaryReport in state is false', () => {
- it('sets testReports and shows tests', done => {
- testAction(
- actions.fetchSummary,
- null,
- state,
- [{ type: types.SET_SUMMARY, payload: summary }],
- [],
- done,
- );
- });
-
- it('should create flash on API error', done => {
- testAction(
- actions.fetchSummary,
- null,
- {
- summaryEndpoint: null,
- },
- [],
- [],
- () => {
- expect(createFlash).toHaveBeenCalled();
- done();
- },
- );
- });
+ it('should create flash on API error', done => {
+ testAction(
+ actions.fetchSummary,
+ null,
+ { summaryEndpoint: null },
+ [],
+ [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
+ () => {
+ expect(createFlash).toHaveBeenCalled();
+ done();
+ },
+ );
});
});
- describe('fetch full report', () => {
+ describe('fetch test suite', () => {
beforeEach(() => {
- mock.onGet(fullReportEndpoint).replyOnce(200, testReports, {});
+ const buildIds = [1];
+ testReports.test_suites[0].build_ids = buildIds;
+ const endpoint = suiteEndpoint.replace(':suite_name', testReports.test_suites[0].name);
+ mock
+ .onGet(endpoint, { params: { build_ids: buildIds } })
+ .replyOnce(200, testReports.test_suites[0], {});
});
- it('sets testReports and shows tests', done => {
+ it('sets test suite and shows tests', done => {
+ const suite = testReports.test_suites[0];
+ const index = 0;
+
testAction(
- actions.fetchFullReport,
- null,
- state,
- [{ type: types.SET_REPORTS, payload: testReports }],
+ actions.fetchTestSuite,
+ index,
+ { ...state, testReports },
+ [{ type: types.SET_SUITE, payload: { suite, index } }],
[{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
done,
);
});
it('should create flash on API error', done => {
+ const index = 0;
+
testAction(
- actions.fetchFullReport,
- null,
- {
- fullReportEndpoint: null,
- },
+ actions.fetchTestSuite,
+ index,
+ { ...state, testReports, suiteEndpoint: null },
[],
[{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
() => {
@@ -131,6 +104,15 @@ describe('Actions TestReports Store', () => {
},
);
});
+
+ describe('when we already have the suite data', () => {
+ it('should not fetch suite', done => {
+ const index = 0;
+ testReports.test_suites[0].hasFullSuite = true;
+
+ testAction(actions.fetchTestSuite, index, { ...state, testReports }, [], [], done);
+ });
+ });
});
describe('set selected suite index', () => {
diff --git a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
index f4cc5c4bc5d..b935029bc6a 100644
--- a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
+++ b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
@@ -12,20 +12,24 @@ describe('Mutations TestReports Store', () => {
testReports: {},
selectedSuite: null,
isLoading: false,
- hasFullReport: false,
};
beforeEach(() => {
mockState = { ...defaultState };
});
- describe('set reports', () => {
- it('should set testReports', () => {
- const expectedState = { ...mockState, testReports };
- mutations[types.SET_REPORTS](mockState, testReports);
+ describe('set suite', () => {
+ it('should set the suite at the given index', () => {
+ mockState.testReports = testReports;
+ const suite = { name: 'test_suite' };
+ const index = 0;
+ const expectedState = { ...mockState };
+ expectedState.testReports.test_suites[index] = { suite, hasFullSuite: true };
+ mutations[types.SET_SUITE](mockState, { suite, index });
- expect(mockState.testReports).toEqual(expectedState.testReports);
- expect(mockState.hasFullReport).toBe(true);
+ expect(mockState.testReports.test_suites[index]).toEqual(
+ expectedState.testReports.test_suites[index],
+ );
});
});
@@ -40,10 +44,21 @@ describe('Mutations TestReports Store', () => {
describe('set summary', () => {
it('should set summary', () => {
- const summary = { total_count: 1 };
+ const summary = {
+ total: { time: 0, count: 10, success: 1, failed: 2, skipped: 3, error: 4 },
+ };
+ const expectedSummary = {
+ ...summary,
+ total_time: 0,
+ total_count: 10,
+ success_count: 1,
+ failed_count: 2,
+ skipped_count: 3,
+ error_count: 4,
+ };
mutations[types.SET_SUMMARY](mockState, summary);
- expect(mockState.testReports).toEqual(summary);
+ expect(mockState.testReports).toEqual(expectedSummary);
});
});
diff --git a/spec/frontend/pipelines/test_reports/test_reports_spec.js b/spec/frontend/pipelines/test_reports/test_reports_spec.js
index ef0bcffabe3..a709edf5184 100644
--- a/spec/frontend/pipelines/test_reports/test_reports_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_reports_spec.js
@@ -22,7 +22,7 @@ describe('Test reports app', () => {
const testSummaryTable = () => wrapper.find(TestSummaryTable);
const actionSpies = {
- fetchFullReport: jest.fn(),
+ fetchTestSuite: jest.fn(),
fetchSummary: jest.fn(),
setSelectedSuiteIndex: jest.fn(),
removeSelectedSuiteIndex: jest.fn(),
@@ -91,28 +91,14 @@ describe('Test reports app', () => {
});
describe('when a suite is clicked', () => {
- describe('when the full test report has already been received', () => {
- beforeEach(() => {
- createComponent({ hasFullReport: true });
- testSummaryTable().vm.$emit('row-click', 0);
- });
-
- it('should only call setSelectedSuiteIndex', () => {
- expect(actionSpies.setSelectedSuiteIndex).toHaveBeenCalled();
- expect(actionSpies.fetchFullReport).not.toHaveBeenCalled();
- });
+ beforeEach(() => {
+ createComponent({ hasFullReport: true });
+ testSummaryTable().vm.$emit('row-click', 0);
});
- describe('when the full test report has not been received', () => {
- beforeEach(() => {
- createComponent({ hasFullReport: false });
- testSummaryTable().vm.$emit('row-click', 0);
- });
-
- it('should call setSelectedSuiteIndex and fetchFullReport', () => {
- expect(actionSpies.setSelectedSuiteIndex).toHaveBeenCalled();
- expect(actionSpies.fetchFullReport).toHaveBeenCalled();
- });
+ it('should call setSelectedSuiteIndex and fetchTestSuite', () => {
+ expect(actionSpies.setSelectedSuiteIndex).toHaveBeenCalled();
+ expect(actionSpies.fetchTestSuite).toHaveBeenCalled();
});
});
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 65bffe7039a..3a4aa94571e 100644
--- a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
@@ -23,6 +23,8 @@ 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 allCaseNames = () =>
+ wrapper.findAll('[data-testid="caseName"]').wrappers.map(el => el.attributes('text'));
const findIconForRow = (row, status) => row.find(`.ci-status-icon-${status}`);
const createComponent = (suite = testSuite) => {
@@ -61,18 +63,14 @@ describe('Test reports suite table', () => {
expect(allCaseRows().length).toBe(testCases.length);
});
- it('renders the failed tests first', () => {
- const failedCaseNames = testCases
- .filter(x => x.status === TestStatus.FAILED)
- .map(x => x.name);
+ it('renders the failed tests first, skipped tests next, then successful tests', () => {
+ const expectedCaseOrder = [
+ ...testCases.filter(x => x.status === TestStatus.FAILED),
+ ...testCases.filter(x => x.status === TestStatus.SKIPPED),
+ ...testCases.filter(x => x.status === TestStatus.SUCCESS),
+ ].map(x => x.name);
- const skippedCaseNames = testCases
- .filter(x => x.status === TestStatus.SKIPPED)
- .map(x => x.name);
-
- expect(findCaseRowAtIndex(0).text()).toContain(failedCaseNames[0]);
- expect(findCaseRowAtIndex(1).text()).toContain(failedCaseNames[1]);
- expect(findCaseRowAtIndex(2).text()).toContain(skippedCaseNames[0]);
+ expect(allCaseNames()).toEqual(expectedCaseOrder);
});
it('renders the correct icon for each status', () => {
diff --git a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
index 650dd8a1def..2e32d62b4bd 100644
--- a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
@@ -1,6 +1,6 @@
-import Api from '~/api';
import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import Api from '~/api';
import PipelineBranchNameToken from '~/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue';
import { branches, mockBranchesAfterMap } from '../mock_data';
diff --git a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
index 15b283dc2ff..42c9dfc9ff0 100644
--- a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
@@ -1,6 +1,6 @@
-import Api from '~/api';
import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import Api from '~/api';
import PipelineTagNameToken from '~/pipelines/components/pipelines_list/tokens/pipeline_tag_name_token.vue';
import { tags, mockTagsAfterMap } from '../mock_data';
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 0b5cf2e202b..c95d2ea1b7b 100644
--- a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
+++ b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
@@ -1,6 +1,6 @@
-import Api from '~/api';
import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import Api from '~/api';
import PipelineTriggerAuthorToken from '~/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue';
import { users } from '../mock_data';