Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/pipelines/utils_spec.js')
-rw-r--r--spec/frontend/pipelines/utils_spec.js161
1 files changed, 161 insertions, 0 deletions
diff --git a/spec/frontend/pipelines/utils_spec.js b/spec/frontend/pipelines/utils_spec.js
new file mode 100644
index 00000000000..1c23a7e4fcf
--- /dev/null
+++ b/spec/frontend/pipelines/utils_spec.js
@@ -0,0 +1,161 @@
+import { createSankey } from '~/pipelines/components/dag/drawing_utils';
+import {
+ makeLinksFromNodes,
+ filterByAncestors,
+ generateColumnsFromLayersListBare,
+ listByLayers,
+ parseData,
+ removeOrphanNodes,
+ getMaxNodes,
+} from '~/pipelines/components/parsing_utils';
+import { createNodeDict } from '~/pipelines/utils';
+
+import { mockParsedGraphQLNodes, missingJob } from './components/dag/mock_data';
+import { generateResponse, mockPipelineResponse } from './graph/mock_data';
+
+describe('DAG visualization parsing utilities', () => {
+ 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', 'build_a');
+ expect(unfilteredLinks[0]).toHaveProperty('target', 'test_a');
+ expect(unfilteredLinks[0]).toHaveProperty('value', 10);
+ });
+
+ it('does not generate a link for non-existing jobs', () => {
+ const sources = unfilteredLinks.map(({ source }) => source);
+
+ expect(sources.includes(missingJob)).toBe(false);
+ });
+ });
+
+ describe('filterByAncestors', () => {
+ const allLinks = [
+ { source: 'job1', target: 'job4' },
+ { source: 'job1', target: 'job2' },
+ { source: 'job2', target: 'job4' },
+ ];
+
+ const dedupedLinks = [
+ { source: 'job1', target: 'job2' },
+ { source: 'job2', target: 'job4' },
+ ];
+
+ const nodeLookup = {
+ job1: {
+ name: 'job1',
+ },
+ job2: {
+ name: 'job2',
+ needs: ['job1'],
+ },
+ job4: {
+ name: 'job4',
+ needs: ['job1', 'job2'],
+ category: 'build',
+ },
+ };
+
+ it('dedupes links', () => {
+ expect(filterByAncestors(allLinks, nodeLookup)).toMatchObject(dedupedLinks);
+ });
+ });
+
+ describe('parseData parent function', () => {
+ it('returns an object containing a list of nodes and links', () => {
+ // an array of nodes exist and the values are defined
+ expect(parsed).toHaveProperty('nodes');
+ expect(Array.isArray(parsed.nodes)).toBe(true);
+ expect(parsed.nodes.filter(Boolean)).not.toHaveLength(0);
+
+ // an array of links exist and the values are defined
+ expect(parsed).toHaveProperty('links');
+ expect(Array.isArray(parsed.links)).toBe(true);
+ expect(parsed.links.filter(Boolean)).not.toHaveLength(0);
+ });
+ });
+
+ 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);
+ /*
+ These lengths are determined by the mock data.
+ If the data changes, the numbers may also change.
+ */
+ expect(parsed.nodes).toHaveLength(mockParsedGraphQLNodes.length);
+ expect(cleanedNodes).toHaveLength(12);
+ });
+ });
+
+ describe('getMaxNodes', () => {
+ it('returns the number of nodes in the most populous generation', () => {
+ const layerNodes = [
+ { layer: 0 },
+ { layer: 0 },
+ { layer: 1 },
+ { layer: 1 },
+ { layer: 0 },
+ { layer: 3 },
+ { layer: 2 },
+ { layer: 4 },
+ { layer: 1 },
+ { layer: 3 },
+ { layer: 4 },
+ ];
+ expect(getMaxNodes(layerNodes)).toBe(3);
+ });
+ });
+
+ describe('generateColumnsFromLayersList', () => {
+ const pipeline = generateResponse(mockPipelineResponse, 'root/fungi-xoxo');
+ const { pipelineLayers } = listByLayers(pipeline);
+ const columns = generateColumnsFromLayersListBare(pipeline, pipelineLayers);
+
+ it('returns stage-like objects with default name, id, and status', () => {
+ columns.forEach((col, idx) => {
+ expect(col).toMatchObject({
+ name: '',
+ status: { action: null },
+ id: `layer-${idx}`,
+ });
+ });
+ });
+
+ it('creates groups that match the list created in listByLayers', () => {
+ columns.forEach((col, idx) => {
+ const groupNames = col.groups.map(({ name }) => name);
+ expect(groupNames).toEqual(pipelineLayers[idx]);
+ });
+ });
+
+ it('looks up the correct group object', () => {
+ columns.forEach((col) => {
+ col.groups.forEach((group) => {
+ const groupStage = pipeline.stages.find((el) => el.name === group.stageName);
+ const groupObject = groupStage.groups.find((el) => el.name === group.name);
+ expect(group).toBe(groupObject);
+ });
+ });
+ });
+
+ /*
+ Just as a fallback in case multiple functions change, so tests pass
+ but the implementation moves away from case.
+ */
+ it('matches the snapshot', () => {
+ expect(columns).toMatchSnapshot();
+ });
+ });
+});