diff options
Diffstat (limited to 'spec/frontend/pipelines/components')
6 files changed, 348 insertions, 65 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 index 629efc6d3fa..cb5f6ff5307 100644 --- a/spec/frontend/pipelines/components/dag/__snapshots__/dag_graph_spec.js.snap +++ b/spec/frontend/pipelines/components/dag/__snapshots__/dag_graph_spec.js.snap @@ -3,7 +3,7 @@ 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\\"> + <g id=\\"dag-link43\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -20,7 +20,7 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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\\"> + <g id=\\"dag-link44\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -37,7 +37,7 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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\\"> + <g id=\\"dag-link45\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -54,7 +54,7 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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\\"> + <g id=\\"dag-link46\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -71,7 +71,7 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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\\"> + <g id=\\"dag-link47\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -88,7 +88,7 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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\\"> + <g id=\\"dag-link48\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -105,7 +105,7 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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\\"> + <g id=\\"dag-link49\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -122,7 +122,7 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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\\"> + <g id=\\"dag-link50\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -139,7 +139,7 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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\\"> + <g id=\\"dag-link51\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -156,7 +156,7 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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\\"> + <g id=\\"dag-link52\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\"> <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> @@ -175,18 +175,18 @@ exports[`The DAG graph in the basic case renders the graph svg 1`] = ` </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> + <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" 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\\"> diff --git a/spec/frontend/pipelines/components/dag/dag_annotations_spec.js b/spec/frontend/pipelines/components/dag/dag_annotations_spec.js new file mode 100644 index 00000000000..5747c91bee8 --- /dev/null +++ b/spec/frontend/pipelines/components/dag/dag_annotations_spec.js @@ -0,0 +1,112 @@ +import { shallowMount, mount } from '@vue/test-utils'; +import { GlButton } from '@gitlab/ui'; +import DagAnnotations from '~/pipelines/components/dag/dag_annotations.vue'; +import { singleNote, multiNote } from './mock_data'; + +describe('The DAG annotations', () => { + let wrapper; + + const getColorBlock = () => wrapper.find('[data-testid="dag-color-block"]'); + const getAllColorBlocks = () => wrapper.findAll('[data-testid="dag-color-block"]'); + const getTextBlock = () => wrapper.find('[data-testid="dag-note-text"]'); + const getAllTextBlocks = () => wrapper.findAll('[data-testid="dag-note-text"]'); + const getToggleButton = () => wrapper.find(GlButton); + + const createComponent = (propsData = {}, method = shallowMount) => { + if (wrapper?.destroy) { + wrapper.destroy(); + } + + wrapper = method(DagAnnotations, { + propsData, + data() { + return { + showList: true, + }; + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('when there is one annotation', () => { + const currentNote = singleNote['dag-link103']; + + beforeEach(() => { + createComponent({ annotations: singleNote }); + }); + + it('displays the color block', () => { + expect(getColorBlock().exists()).toBe(true); + }); + + it('displays the text block', () => { + expect(getTextBlock().exists()).toBe(true); + expect(getTextBlock().text()).toBe(`${currentNote.source.name} → ${currentNote.target.name}`); + }); + + it('does not display the list toggle link', () => { + expect(getToggleButton().exists()).toBe(false); + }); + }); + + describe('when there are multiple annoataions', () => { + beforeEach(() => { + createComponent({ annotations: multiNote }); + }); + + it('displays a color block for each link', () => { + expect(getAllColorBlocks().length).toBe(Object.keys(multiNote).length); + }); + + it('displays a text block for each link', () => { + 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}`); + }); + }); + + it('displays the list toggle link', () => { + expect(getToggleButton().exists()).toBe(true); + expect(getToggleButton().text()).toBe('Hide list'); + }); + }); + + describe('the list toggle', () => { + beforeEach(() => { + createComponent({ annotations: multiNote }, mount); + }); + + describe('clicking hide', () => { + it('hides listed items and changes text to show', () => { + expect(getAllTextBlocks().length).toBe(Object.keys(multiNote).length); + expect(getToggleButton().text()).toBe('Hide list'); + getToggleButton().trigger('click'); + return wrapper.vm.$nextTick().then(() => { + expect(getAllTextBlocks().length).toBe(0); + expect(getToggleButton().text()).toBe('Show list'); + }); + }); + }); + + describe('clicking show', () => { + it('shows listed items and changes text to hide', () => { + getToggleButton().trigger('click'); + getToggleButton().trigger('click'); + + return wrapper.vm.$nextTick().then(() => { + expect(getAllTextBlocks().length).toBe(Object.keys(multiNote).length); + expect(getToggleButton().text()).toBe('Hide list'); + }); + }); + }); + }); +}); diff --git a/spec/frontend/pipelines/components/dag/dag_graph_spec.js b/spec/frontend/pipelines/components/dag/dag_graph_spec.js index 017461dfb84..e312791b01f 100644 --- a/spec/frontend/pipelines/components/dag/dag_graph_spec.js +++ b/spec/frontend/pipelines/components/dag/dag_graph_spec.js @@ -1,4 +1,4 @@ -import { mount } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; import DagGraph from '~/pipelines/components/dag/dag_graph.vue'; import { IS_HIGHLIGHTED, LINK_SELECTOR, NODE_SELECTOR } from '~/pipelines/components/dag/constants'; import { highlightIn, highlightOut } from '~/pipelines/components/dag/interactions'; @@ -19,7 +19,7 @@ describe('The DAG graph', () => { wrapper.destroy(); } - wrapper = mount(DagGraph, { + wrapper = shallowMount(DagGraph, { attachToDocument: true, propsData, data() { diff --git a/spec/frontend/pipelines/components/dag/dag_spec.js b/spec/frontend/pipelines/components/dag/dag_spec.js index 666b4cfaa2f..7dea6d819b9 100644 --- a/spec/frontend/pipelines/components/dag/dag_spec.js +++ b/spec/frontend/pipelines/components/dag/dag_spec.js @@ -2,17 +2,28 @@ 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 } from '@gitlab/ui'; +import { GlAlert, GlEmptyState } from '@gitlab/ui'; import Dag from '~/pipelines/components/dag/dag.vue'; import DagGraph from '~/pipelines/components/dag/dag_graph.vue'; +import DagAnnotations from '~/pipelines/components/dag/dag_annotations.vue'; import { + ADD_NOTE, + REMOVE_NOTE, + REPLACE_NOTES, DEFAULT, PARSE_FAILURE, LOAD_FAILURE, UNSUPPORTED_DATA, } from '~/pipelines/components/dag//constants'; -import { mockBaseData, tooSmallGraph, unparseableGraph } from './mock_data'; +import { + mockBaseData, + tooSmallGraph, + unparseableGraph, + graphWithoutDependencies, + singleNote, + multiNote, +} from './mock_data'; describe('Pipeline DAG graph wrapper', () => { let wrapper; @@ -20,7 +31,9 @@ describe('Pipeline DAG graph wrapper', () => { const getAlert = () => wrapper.find(GlAlert); const getAllAlerts = () => wrapper.findAll(GlAlert); const getGraph = () => wrapper.find(DagGraph); + const getNotes = () => wrapper.find(DagAnnotations); const getErrorText = type => wrapper.vm.$options.errorTexts[type]; + const getEmptyState = () => wrapper.find(GlEmptyState); const dataPath = '/root/test/pipelines/90/dag.json'; @@ -30,7 +43,11 @@ describe('Pipeline DAG graph wrapper', () => { } wrapper = method(Dag, { - propsData, + propsData: { + emptySvgPath: '/my-svg', + dagDocPath: '/my-doc', + ...propsData, + }, data() { return { showFailureAlert: false, @@ -59,79 +76,153 @@ describe('Pipeline DAG graph wrapper', () => { expect(getAlert().text()).toBe(getErrorText(DEFAULT)); expect(getGraph().exists()).toBe(false); }); + + it('does not render the empty state', () => { + expect(getEmptyState().exists()).toBe(false); + }); }); describe('when there is a dataUrl', () => { describe('but the data fetch fails', () => { - beforeEach(() => { + 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', () => { - return wrapper.vm - .$nextTick() - .then(waitForPromises) - .then(() => { - expect(getAlert().exists()).toBe(true); - expect(getAlert().text()).toBe(getErrorText(LOAD_FAILURE)); - expect(getGraph().exists()).toBe(false); - }); + 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(() => { + beforeEach(async () => { mock.onGet(dataPath).replyOnce(200, unparseableGraph); createComponent({ graphUrl: dataPath }); + + await wrapper.vm.$nextTick(); + + return waitForPromises(); }); 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); - }); + expect(getAlert().exists()).toBe(true); + expect(getAlert().text()).toBe(getErrorText(PARSE_FAILURE)); + expect(getGraph().exists()).toBe(false); + }); + + it('does not render the empty state', () => { + expect(getEmptyState().exists()).toBe(false); }); }); describe('and the data fetch and parse succeeds', () => { - beforeEach(() => { + beforeEach(async () => { mock.onGet(dataPath).replyOnce(200, mockBaseData); createComponent({ graphUrl: dataPath }, mount); + + await wrapper.vm.$nextTick(); + + return waitForPromises(); }); - it('shows the graph and not the beta alert', () => { - return wrapper.vm - .$nextTick() - .then(waitForPromises) - .then(() => { - expect(getAllAlerts().length).toBe(1); - expect(getAlert().text()).toContain('This feature is currently in beta.'); - expect(getGraph().exists()).toBe(true); - }); + it('shows the graph and the beta alert', () => { + expect(getAllAlerts().length).toBe(1); + expect(getAlert().text()).toContain('This feature is currently in beta.'); + expect(getGraph().exists()).toBe(true); + }); + + it('does not render the empty state', () => { + expect(getEmptyState().exists()).toBe(false); }); }); describe('the data fetch and parse succeeds, but the resulting graph is too small', () => { - beforeEach(() => { + beforeEach(async () => { mock.onGet(dataPath).replyOnce(200, tooSmallGraph); createComponent({ graphUrl: dataPath }); + + await wrapper.vm.$nextTick(); + + return waitForPromises(); }); 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); - }); + expect(getAlert().exists()).toBe(true); + expect(getAlert().text()).toBe(getErrorText(UNSUPPORTED_DATA)); + expect(getGraph().exists()).toBe(false); + }); + + it('does not show the empty dag graph state', () => { + expect(getEmptyState().exists()).toBe(false); + }); + }); + + describe('the data fetch succeeds but the returned data is empty', () => { + beforeEach(async () => { + mock.onGet(dataPath).replyOnce(200, graphWithoutDependencies); + createComponent({ graphUrl: dataPath }, mount); + + await wrapper.vm.$nextTick(); + + return waitForPromises(); + }); + + 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(getGraph().exists()).toBe(false); }); + + it('shows the empty dag graph state', () => { + expect(getEmptyState().exists()).toBe(true); + }); + }); + }); + + describe('annotations', () => { + beforeEach(async () => { + mock.onGet(dataPath).replyOnce(200, mockBaseData); + createComponent({ graphUrl: dataPath }, mount); + + await wrapper.vm.$nextTick(); + + return waitForPromises(); + }); + + it('toggles on link mouseover and mouseout', async () => { + const currentNote = singleNote['dag-link103']; + + expect(getNotes().exists()).toBe(false); + + getGraph().vm.$emit('update-annotation', { type: ADD_NOTE, data: currentNote }); + await wrapper.vm.$nextTick(); + expect(getNotes().exists()).toBe(true); + + getGraph().vm.$emit('update-annotation', { type: REMOVE_NOTE, data: currentNote }); + await wrapper.vm.$nextTick(); + expect(getNotes().exists()).toBe(false); + }); + + it('toggles on node and link click', async () => { + expect(getNotes().exists()).toBe(false); + + getGraph().vm.$emit('update-annotation', { type: REPLACE_NOTES, data: multiNote }); + await wrapper.vm.$nextTick(); + expect(getNotes().exists()).toBe(true); + + getGraph().vm.$emit('update-annotation', { type: REPLACE_NOTES, data: {} }); + await wrapper.vm.$nextTick(); + expect(getNotes().exists()).toBe(false); }); }); }); diff --git a/spec/frontend/pipelines/components/dag/mock_data.js b/spec/frontend/pipelines/components/dag/mock_data.js index 5de8697170a..3b39b9cd21c 100644 --- a/spec/frontend/pipelines/components/dag/mock_data.js +++ b/spec/frontend/pipelines/components/dag/mock_data.js @@ -83,6 +83,46 @@ export const tooSmallGraph = { ], }; +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 unparseableGraph = [ { name: 'test', @@ -388,3 +428,43 @@ export const parsedData = { }, ], }; + +export const singleNote = { + 'dag-link103': { + uid: 'dag-link103', + source: { + name: 'canary_a', + color: '#b31756', + }, + target: { + name: 'production_a', + color: '#b24800', + }, + }, +}; + +export const multiNote = { + ...singleNote, + 'dag-link104': { + uid: 'dag-link104', + source: { + name: 'build_a', + color: '#e17223', + }, + target: { + name: 'test_c', + color: '#006887', + }, + }, + 'dag-link105': { + uid: 'dag-link105', + source: { + name: 'test_c', + color: '#006887', + }, + target: { + name: 'post_test_c', + color: '#3547de', + }, + }, +}; diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js index bdc807fcbfe..add7b56845e 100644 --- a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js +++ b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js @@ -2,7 +2,7 @@ import Api from '~/api'; import { mount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; -import PipelinesFilteredSearch from '~/pipelines/components/pipelines_filtered_search.vue'; +import PipelinesFilteredSearch from '~/pipelines/components/pipelines_list/pipelines_filtered_search.vue'; import { users, mockSearch, branches, tags } from '../mock_data'; import { GlFilteredSearch } from '@gitlab/ui'; |