diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-29 18:08:26 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-29 18:08:26 +0000 |
commit | b64a8161c9442d82897a341d6bf935dd3e748b06 (patch) | |
tree | b9953db8607d1393aa8ac588a15f184dd8e183f6 /spec/frontend/pipelines/components/dag | |
parent | 6e33325c1458cb31b4d36a7eec817fa00ec3faaf (diff) | |
download | gitlab-ce-b64a8161c9442d82897a341d6bf935dd3e748b06.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/pipelines/components/dag')
5 files changed, 745 insertions, 25 deletions
diff --git a/spec/frontend/pipelines/components/dag/__snapshots__/dag_graph_spec.js.snap b/spec/frontend/pipelines/components/dag/__snapshots__/dag_graph_spec.js.snap new file mode 100644 index 00000000000..5390c2f8e0c --- /dev/null +++ b/spec/frontend/pipelines/components/dag/__snapshots__/dag_graph_spec.js.snap @@ -0,0 +1,220 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`The DAG graph in the basic case renders the graph svg 1`] = ` +"<svg viewBox=\\"0,0,1000,540\\" width=\\"1000\\" height=\\"540\\"> + <g fill=\\"none\\" stroke-opacity=\\"0.8\\"> + <g id=\\"dag-link43\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad53\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"116\\" x2=\\"361.3333333333333\\"> + <stop offset=\\"0%\\" stop-color=\\"#e17223\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#83ab4a\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip63\\"> + <path d=\\" + M100, 129 + V158 + H377.3333333333333 + V100 + H100 + Z\\"></path> + </clipPath> + <path d=\\"M108,129L190,129L190,129L369.3333333333333,129\\" stroke=\\"url(#dag-grad53)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip63)\\"></path> + </g> + <g id=\\"dag-link44\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad54\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"377.3333333333333\\" x2=\\"622.6666666666666\\"> + <stop offset=\\"0%\\" stop-color=\\"#83ab4a\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#6f3500\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip64\\"> + <path d=\\" + M361.3333333333333, 129.0000000000002 + V158.0000000000002 + H638.6666666666666 + V100 + H361.3333333333333 + Z\\"></path> + </clipPath> + <path d=\\"M369.3333333333333,129L509.3333333333333,129L509.3333333333333,129.0000000000002L630.6666666666666,129.0000000000002\\" stroke=\\"url(#dag-grad54)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip64)\\"></path> + </g> + <g id=\\"dag-link45\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad55\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"116\\" x2=\\"622.6666666666666\\"> + <stop offset=\\"0%\\" stop-color=\\"#5772ff\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#6f3500\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip65\\"> + <path d=\\" + M100, 187.0000000000002 + V241.00000000000003 + H638.6666666666666 + V158.0000000000002 + H100 + Z\\"></path> + </clipPath> + <path d=\\"M108,212.00000000000003L306,212.00000000000003L306,187.0000000000002L630.6666666666666,187.0000000000002\\" stroke=\\"url(#dag-grad55)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip65)\\"></path> + </g> + <g id=\\"dag-link46\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad56\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"116\\" x2=\\"361.3333333333333\\"> + <stop offset=\\"0%\\" stop-color=\\"#b24800\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#006887\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip66\\"> + <path d=\\" + M100, 269.9999999999998 + V324 + H377.3333333333333 + V240.99999999999977 + H100 + Z\\"></path> + </clipPath> + <path d=\\"M108,295L338.93333333333334,295L338.93333333333334,269.9999999999998L369.3333333333333,269.9999999999998\\" stroke=\\"url(#dag-grad56)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip66)\\"></path> + </g> + <g id=\\"dag-link47\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad57\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"116\\" x2=\\"361.3333333333333\\"> + <stop offset=\\"0%\\" stop-color=\\"#25d2d2\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#487900\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip67\\"> + <path d=\\" + M100, 352.99999999999994 + V407.00000000000006 + H377.3333333333333 + V323.99999999999994 + H100 + Z\\"></path> + </clipPath> + <path d=\\"M108,378.00000000000006L144.66666666666669,378.00000000000006L144.66666666666669,352.99999999999994L369.3333333333333,352.99999999999994\\" stroke=\\"url(#dag-grad57)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip67)\\"></path> + </g> + <g id=\\"dag-link48\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad58\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"377.3333333333333\\" x2=\\"622.6666666666666\\"> + <stop offset=\\"0%\\" stop-color=\\"#006887\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#d84280\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip68\\"> + <path d=\\" + M361.3333333333333, 270.0000000000001 + V299.0000000000001 + H638.6666666666666 + V240.99999999999977 + H361.3333333333333 + Z\\"></path> + </clipPath> + <path d=\\"M369.3333333333333,269.9999999999998L464,269.9999999999998L464,270.0000000000001L630.6666666666666,270.0000000000001\\" stroke=\\"url(#dag-grad58)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip68)\\"></path> + </g> + <g id=\\"dag-link49\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad59\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"377.3333333333333\\" x2=\\"622.6666666666666\\"> + <stop offset=\\"0%\\" stop-color=\\"#487900\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#d84280\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip69\\"> + <path d=\\" + M361.3333333333333, 328.0000000000001 + V381.99999999999994 + H638.6666666666666 + V299.0000000000001 + H361.3333333333333 + Z\\"></path> + </clipPath> + <path d=\\"M369.3333333333333,352.99999999999994L522,352.99999999999994L522,328.0000000000001L630.6666666666666,328.0000000000001\\" stroke=\\"url(#dag-grad59)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip69)\\"></path> + </g> + <g id=\\"dag-link50\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad60\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"377.3333333333333\\" x2=\\"622.6666666666666\\"> + <stop offset=\\"0%\\" stop-color=\\"#487900\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#3547de\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip70\\"> + <path d=\\" + M361.3333333333333, 411 + V440 + H638.6666666666666 + V381.99999999999994 + H361.3333333333333 + Z\\"></path> + </clipPath> + <path d=\\"M369.3333333333333,410.99999999999994L580,410.99999999999994L580,411L630.6666666666666,411\\" stroke=\\"url(#dag-grad60)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip70)\\"></path> + </g> + <g id=\\"dag-link51\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad61\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"638.6666666666666\\" x2=\\"884\\"> + <stop offset=\\"0%\\" stop-color=\\"#d84280\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#006887\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip71\\"> + <path d=\\" + M622.6666666666666, 270.1890725105691 + V299.1890725105691 + H900 + V241.0000000000001 + H622.6666666666666 + Z\\"></path> + </clipPath> + <path d=\\"M630.6666666666666,270.0000000000001L861.6,270.0000000000001L861.6,270.1890725105691L892,270.1890725105691\\" stroke=\\"url(#dag-grad61)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip71)\\"></path> + </g> + <g id=\\"dag-link52\\" class=\\"dag-link gl-cursor-pointer\\"> + <linearGradient id=\\"dag-grad62\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"638.6666666666666\\" x2=\\"884\\"> + <stop offset=\\"0%\\" stop-color=\\"#3547de\\"></stop> + <stop offset=\\"100%\\" stop-color=\\"#275600\\"></stop> + </linearGradient> + <clipPath id=\\"dag-clip72\\"> + <path d=\\" + M622.6666666666666, 411 + V440 + H900 + V382 + H622.6666666666666 + Z\\"></path> + </clipPath> + <path d=\\"M630.6666666666666,411L679.9999999999999,411L679.9999999999999,411L892,411\\" stroke=\\"url(#dag-grad62)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip72)\\"></path> + </g> + </g> + <g> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node73\\" stroke=\\"#e17223\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"108\\" x2=\\"108\\" y1=\\"104\\" y2=\\"154.00000000000003\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node74\\" stroke=\\"#83ab4a\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"369\\" x2=\\"369\\" y1=\\"104\\" y2=\\"154\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node75\\" stroke=\\"#5772ff\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"108\\" x2=\\"108\\" y1=\\"187.00000000000003\\" y2=\\"237.00000000000003\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node76\\" stroke=\\"#b24800\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"108\\" x2=\\"108\\" y1=\\"270\\" y2=\\"320.00000000000006\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node77\\" stroke=\\"#25d2d2\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"108\\" x2=\\"108\\" y1=\\"353.00000000000006\\" y2=\\"403.0000000000001\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node78\\" stroke=\\"#6f3500\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"630\\" x2=\\"630\\" y1=\\"104.0000000000002\\" y2=\\"212.00000000000009\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node79\\" stroke=\\"#006887\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"369\\" x2=\\"369\\" y1=\\"244.99999999999977\\" y2=\\"294.99999999999994\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node80\\" stroke=\\"#487900\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"369\\" x2=\\"369\\" y1=\\"327.99999999999994\\" y2=\\"436\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node81\\" stroke=\\"#d84280\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"630\\" x2=\\"630\\" y1=\\"245.00000000000009\\" y2=\\"353\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node82\\" stroke=\\"#3547de\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"630\\" x2=\\"630\\" y1=\\"386\\" y2=\\"436\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node83\\" stroke=\\"#006887\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"892\\" x2=\\"892\\" y1=\\"245.18907251056908\\" y2=\\"295.1890725105691\\"></line> + <line class=\\"dag-node gl-cursor-pointer\\" id=\\"dag-node84\\" stroke=\\"#275600\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"892\\" x2=\\"892\\" y1=\\"386\\" y2=\\"436\\"></line> + </g> + <g class=\\"gl-font-sm\\"> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58.00000000000003px\\" width=\\"84\\" x=\\"8\\" y=\\"100\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58.00000000000003px; text-align: right;\\">build_a</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"369.3333333333333\\" y=\\"75\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: left;\\">test_a</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58px\\" width=\\"84\\" x=\\"8\\" y=\\"183.00000000000003\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58px; text-align: right;\\">test_b</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58.00000000000006px\\" width=\\"84\\" x=\\"8\\" y=\\"266\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58.00000000000006px; text-align: right;\\">post_test_a</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58.00000000000006px\\" width=\\"84\\" x=\\"8\\" y=\\"349.00000000000006\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58.00000000000006px; text-align: right;\\">post_test_b</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"630.6666666666666\\" y=\\"75.0000000000002\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: right;\\">post_test_c</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"369.3333333333333\\" y=\\"215.99999999999977\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: left;\\">staging_a</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"369.3333333333333\\" y=\\"298.99999999999994\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: left;\\">staging_b</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"630.6666666666666\\" y=\\"216.00000000000009\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: right;\\">canary_a</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"630.6666666666666\\" y=\\"357\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: right;\\">canary_c</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58px\\" width=\\"84\\" x=\\"908\\" y=\\"241.18907251056908\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58px; text-align: left;\\">production_a</div> + </foreignObject> + <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58px\\" width=\\"84\\" x=\\"908\\" y=\\"382\\" class=\\"gl-overflow-visible\\"> + <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58px; text-align: left;\\">production_d</div> + </foreignObject> + </g> +</svg>" +`; diff --git a/spec/frontend/pipelines/components/dag/dag_graph_spec.js b/spec/frontend/pipelines/components/dag/dag_graph_spec.js new file mode 100644 index 00000000000..bc576397967 --- /dev/null +++ b/spec/frontend/pipelines/components/dag/dag_graph_spec.js @@ -0,0 +1,96 @@ +import { mount } from '@vue/test-utils'; +import DagGraph from '~/pipelines/components/dag/dag_graph.vue'; +import { createSankey, removeOrphanNodes } from '~/pipelines/components/dag/utils'; +import { parsedData } from './mock_data'; + +describe('The DAG graph', () => { + let wrapper; + + const getGraph = () => wrapper.find('.dag-graph-container > svg'); + const getAllLinks = () => wrapper.findAll('.dag-link'); + const getAllNodes = () => wrapper.findAll('.dag-node'); + const getAllLabels = () => wrapper.findAll('foreignObject'); + + const createComponent = (propsData = {}) => { + if (wrapper?.destroy) { + wrapper.destroy(); + } + + wrapper = mount(DagGraph, { + attachToDocument: true, + propsData, + data() { + return { + color: () => {}, + width: 0, + height: 0, + }; + }, + }); + }; + + beforeEach(() => { + createComponent({ graphData: parsedData }); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('in the basic case', () => { + beforeEach(() => { + /* + The graph uses random to offset links. To keep the snapshot consistent, + we mock Math.random. Wheeeee! + */ + const randomNumber = jest.spyOn(global.Math, 'random'); + randomNumber.mockImplementation(() => 0.2); + createComponent({ graphData: parsedData }); + }); + + it('renders the graph svg', () => { + expect(getGraph().exists()).toBe(true); + expect(getGraph().html()).toMatchSnapshot(); + }); + }); + + describe('links', () => { + it('renders the expected number of links', () => { + expect(getAllLinks()).toHaveLength(parsedData.links.length); + }); + + it('renders the expected number of gradients', () => { + expect(wrapper.findAll('linearGradient')).toHaveLength(parsedData.links.length); + }); + + it('renders the expected number of clip paths', () => { + expect(wrapper.findAll('clipPath')).toHaveLength(parsedData.links.length); + }); + }); + + describe('nodes and labels', () => { + const sankeyNodes = createSankey()(parsedData).nodes; + const processedNodes = removeOrphanNodes(sankeyNodes); + + describe('nodes', () => { + it('renders the expected number of nodes', () => { + expect(getAllNodes()).toHaveLength(processedNodes.length); + }); + }); + + describe('labels', () => { + it('renders the expected number of labels as foreignObjects', () => { + expect(getAllLabels()).toHaveLength(processedNodes.length); + }); + + it('renders the title as text', () => { + expect( + getAllLabels() + .at(0) + .text(), + ).toBe(parsedData.nodes[0].name); + }); + }); + }); +}); diff --git a/spec/frontend/pipelines/components/dag/dag_spec.js b/spec/frontend/pipelines/components/dag/dag_spec.js index 31ee4e1a0a1..262682a89c5 100644 --- a/spec/frontend/pipelines/components/dag/dag_spec.js +++ b/spec/frontend/pipelines/components/dag/dag_spec.js @@ -1,26 +1,34 @@ -import { mount } from '@vue/test-utils'; +import { 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 } from '@gitlab/ui'; import Dag from '~/pipelines/components/dag/dag.vue'; +import DagGraph from '~/pipelines/components/dag/dag_graph.vue'; -describe('Pipeline DAG graph', () => { +import { + DEFAULT, + PARSE_FAILURE, + LOAD_FAILURE, + UNSUPPORTED_DATA, +} from '~/pipelines/components/dag//constants'; +import { mockBaseData, tooSmallGraph, unparseableGraph } from './mock_data'; + +describe('Pipeline DAG graph wrapper', () => { let wrapper; - let axiosMock; + let mock; const getAlert = () => wrapper.find(GlAlert); - const getGraph = () => wrapper.find('[data-testid="dag-graph-container"]'); - - const dataPath = 'root/test/pipelines/90/dag.json'; + const getGraph = () => wrapper.find(DagGraph); + const getErrorText = type => wrapper.vm.$options.errorTexts[type]; - const createComponent = (propsData = {}, method = mount) => { - axiosMock = new MockAdapter(axios); + const dataPath = '/root/test/pipelines/90/dag.json'; + const createComponent = (propsData = {}) => { if (wrapper?.destroy) { wrapper.destroy(); } - wrapper = method(Dag, { + wrapper = shallowMount(Dag, { propsData, data() { return { @@ -30,8 +38,12 @@ describe('Pipeline DAG graph', () => { }); }; + beforeEach(() => { + mock = new MockAdapter(axios); + }); + afterEach(() => { - axiosMock.restore(); + mock.restore(); wrapper.destroy(); wrapper = null; }); @@ -41,34 +53,80 @@ describe('Pipeline DAG graph', () => { createComponent({ graphUrl: undefined }); }); - it('shows the alert and not the graph', () => { + it('shows the DEFAULT alert and not the graph', () => { expect(getAlert().exists()).toBe(true); + expect(getAlert().text()).toBe(getErrorText(DEFAULT)); expect(getGraph().exists()).toBe(false); }); }); describe('when there is a dataUrl', () => { - beforeEach(() => { - createComponent({ graphUrl: dataPath }); + describe('but the data fetch fails', () => { + beforeEach(() => { + mock.onGet(dataPath).replyOnce(500); + createComponent({ graphUrl: dataPath }); + }); + + it('shows the LOAD_FAILURE alert and not the graph', () => { + return wrapper.vm + .$nextTick() + .then(waitForPromises) + .then(() => { + expect(getAlert().exists()).toBe(true); + expect(getAlert().text()).toBe(getErrorText(LOAD_FAILURE)); + expect(getGraph().exists()).toBe(false); + }); + }); }); - it('shows the graph and not the alert', () => { - expect(getAlert().exists()).toBe(false); - expect(getGraph().exists()).toBe(true); + describe('the data fetch succeeds but the parse fails', () => { + beforeEach(() => { + mock.onGet(dataPath).replyOnce(200, unparseableGraph); + createComponent({ graphUrl: dataPath }); + }); + + it('shows the PARSE_FAILURE alert and not the graph', () => { + return wrapper.vm + .$nextTick() + .then(waitForPromises) + .then(() => { + expect(getAlert().exists()).toBe(true); + expect(getAlert().text()).toBe(getErrorText(PARSE_FAILURE)); + expect(getGraph().exists()).toBe(false); + }); + }); }); - describe('but the data fetch fails', () => { + describe('and the data fetch and parse succeeds', () => { + beforeEach(() => { + mock.onGet(dataPath).replyOnce(200, mockBaseData); + createComponent({ graphUrl: dataPath }); + }); + + it('shows the graph and not the alert', () => { + return wrapper.vm + .$nextTick() + .then(waitForPromises) + .then(() => { + expect(getAlert().exists()).toBe(false); + expect(getGraph().exists()).toBe(true); + }); + }); + }); + + describe('the data fetch and parse succeeds, but the resulting graph is too small', () => { beforeEach(() => { - axiosMock.onGet(dataPath).replyOnce(500); + mock.onGet(dataPath).replyOnce(200, tooSmallGraph); createComponent({ graphUrl: dataPath }); }); - it('shows the alert and not the graph', () => { + it('shows the UNSUPPORTED_DATA alert and not the graph', () => { return wrapper.vm .$nextTick() .then(waitForPromises) .then(() => { expect(getAlert().exists()).toBe(true); + expect(getAlert().text()).toBe(getErrorText(UNSUPPORTED_DATA)); expect(getGraph().exists()).toBe(false); }); }); diff --git a/spec/frontend/pipelines/components/dag/mock_data.js b/spec/frontend/pipelines/components/dag/mock_data.js index 723cdd3f525..5de8697170a 100644 --- a/spec/frontend/pipelines/components/dag/mock_data.js +++ b/spec/frontend/pipelines/components/dag/mock_data.js @@ -3,7 +3,7 @@ as well as non-parallel jobs with spaces in the name to prevent us relying on spaces as an indicator. */ -export default { +export const mockBaseData = { stages: [ { name: 'test', @@ -42,3 +42,349 @@ export default { }, ], }; + +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 unparseableGraph = [ + { + 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: 'un-needed', + groups: [ + { + name: 'un-needed', + size: 1, + jobs: [{ name: 'un-needed' }], + }, + ], + }, +]; + +/* + This represents data that has been parsed by the wrapper +*/ +export const parsedData = { + nodes: [ + { + name: 'build_a', + size: 1, + jobs: [ + { + name: 'build_a', + }, + ], + category: 'build', + }, + { + name: 'build_b', + size: 1, + jobs: [ + { + name: 'build_b', + }, + ], + category: 'build', + }, + { + name: 'test_a', + size: 1, + jobs: [ + { + name: 'test_a', + needs: ['build_a'], + }, + ], + category: 'test', + }, + { + name: 'test_b', + size: 1, + jobs: [ + { + name: 'test_b', + }, + ], + category: 'test', + }, + { + name: 'test_c', + size: 1, + jobs: [ + { + name: 'test_c', + }, + ], + category: 'test', + }, + { + name: 'test_d', + size: 1, + jobs: [ + { + name: 'test_d', + }, + ], + category: 'test', + }, + { + name: 'post_test_a', + size: 1, + jobs: [ + { + name: 'post_test_a', + }, + ], + category: 'post-test', + }, + { + name: 'post_test_b', + size: 1, + jobs: [ + { + name: 'post_test_b', + }, + ], + category: 'post-test', + }, + { + name: 'post_test_c', + size: 1, + jobs: [ + { + name: 'post_test_c', + needs: ['test_a', 'test_b'], + }, + ], + category: 'post-test', + }, + { + name: 'staging_a', + size: 1, + jobs: [ + { + name: 'staging_a', + needs: ['post_test_a'], + }, + ], + category: 'staging', + }, + { + name: 'staging_b', + size: 1, + jobs: [ + { + name: 'staging_b', + needs: ['post_test_b'], + }, + ], + category: 'staging', + }, + { + name: 'staging_c', + size: 1, + jobs: [ + { + name: 'staging_c', + }, + ], + category: 'staging', + }, + { + name: 'staging_d', + size: 1, + jobs: [ + { + name: 'staging_d', + }, + ], + category: 'staging', + }, + { + name: 'staging_e', + size: 1, + jobs: [ + { + name: 'staging_e', + }, + ], + category: 'staging', + }, + { + name: 'canary_a', + size: 1, + jobs: [ + { + name: 'canary_a', + needs: ['staging_a', 'staging_b'], + }, + ], + category: 'canary', + }, + { + name: 'canary_b', + size: 1, + jobs: [ + { + name: 'canary_b', + }, + ], + category: 'canary', + }, + { + name: 'canary_c', + size: 1, + jobs: [ + { + name: 'canary_c', + needs: ['staging_b'], + }, + ], + category: 'canary', + }, + { + name: 'production_a', + size: 1, + jobs: [ + { + name: 'production_a', + needs: ['canary_a'], + }, + ], + category: 'production', + }, + { + name: 'production_b', + size: 1, + jobs: [ + { + name: 'production_b', + }, + ], + category: 'production', + }, + { + name: 'production_c', + size: 1, + jobs: [ + { + name: 'production_c', + }, + ], + category: 'production', + }, + { + name: 'production_d', + size: 1, + jobs: [ + { + name: 'production_d', + needs: ['canary_c'], + }, + ], + category: 'production', + }, + ], + links: [ + { + source: 'build_a', + target: 'test_a', + value: 10, + }, + { + source: 'test_a', + target: 'post_test_c', + value: 10, + }, + { + source: 'test_b', + target: 'post_test_c', + value: 10, + }, + { + source: 'post_test_a', + target: 'staging_a', + value: 10, + }, + { + source: 'post_test_b', + target: 'staging_b', + value: 10, + }, + { + source: 'staging_a', + target: 'canary_a', + value: 10, + }, + { + source: 'staging_b', + target: 'canary_a', + value: 10, + }, + { + source: 'staging_b', + target: 'canary_c', + value: 10, + }, + { + source: 'canary_a', + target: 'production_a', + value: 10, + }, + { + source: 'canary_c', + target: 'production_d', + value: 10, + }, + ], +}; diff --git a/spec/frontend/pipelines/components/dag/utils_spec.js b/spec/frontend/pipelines/components/dag/utils_spec.js index 41bb91b4800..be0e4f0ea8e 100644 --- a/spec/frontend/pipelines/components/dag/utils_spec.js +++ b/spec/frontend/pipelines/components/dag/utils_spec.js @@ -8,12 +8,12 @@ import { getMaxNodes, } from '~/pipelines/components/dag/utils'; -import mockGraphData from './mock_data'; +import { mockBaseData } from './mock_data'; describe('DAG visualization parsing utilities', () => { - const { nodes, nodeDict } = createNodesStructure(mockGraphData.stages); + const { nodes, nodeDict } = createNodesStructure(mockBaseData.stages); const unfilteredLinks = makeLinksFromNodes(nodes, nodeDict); - const parsed = parseData(mockGraphData.stages); + const parsed = parseData(mockBaseData.stages); const layoutSettings = { width: 200, @@ -30,10 +30,10 @@ describe('DAG visualization parsing utilities', () => { const parallelJobName = 'jest 1/2'; const singleJobName = 'frontend fixtures'; - const { name, jobs, size } = mockGraphData.stages[0].groups[0]; + const { name, jobs, size } = mockBaseData.stages[0].groups[0]; it('returns the expected node structure', () => { - expect(nodes[0]).toHaveProperty('category', mockGraphData.stages[0].name); + 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); |