From 69c41b9b91c66f7200272cfce9fa5415a94af694 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 21 Jul 2020 13:49:37 +0200 Subject: [PATCH] test(graph-utils): add tests --- cypress/integration/flow/graph-utils.spec.js | 130 +++++++++++++++++++ src/utils/graph.ts | 9 +- 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 cypress/integration/flow/graph-utils.spec.js diff --git a/cypress/integration/flow/graph-utils.spec.js b/cypress/integration/flow/graph-utils.spec.js new file mode 100644 index 00000000..128f3e6d --- /dev/null +++ b/cypress/integration/flow/graph-utils.spec.js @@ -0,0 +1,130 @@ +import { isNode, isEdge, getOutgoers, removeElements, addEdge } from '../../../src/utils/graph.ts'; + +const nodes = [ + { id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } }, + { id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } }, + { id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } }, + { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } }, +]; + +const edges = [ + { id: 'e1-2', source: '1', target: '2', animated: true }, + { id: 'e1-3', source: '1', target: '3' }, +]; + +const elements = [...nodes, ...edges]; + +describe('Graph Utils Testing', () => { + it('tests isNode function', () => { + expect(isNode(nodes[0])).to.be.true; + expect(isNode(edges[0])).to.be.false; + }); + + it('tests isEdge function', () => { + expect(isEdge(edges[0])).to.be.true; + expect(isEdge(nodes[0])).to.be.false; + }); + + it('tests getOutgoers function', () => { + const outgoers = getOutgoers(nodes[0], elements); + expect(outgoers.length).to.be.equal(2); + + const noOutgoers = getOutgoers(nodes[1], elements); + expect(noOutgoers.length).to.be.equal(0); + }); + + describe('tests addEdge function', () => { + it('adds edge', () => { + const newEdge = { source: '2', target: '3' }; + const nextElements = addEdge(newEdge, elements); + + expect(nextElements.length).to.be.equal(elements.length + 1); + }); + + it('tries to add invalid edge', () => { + const newEdge = { nosource: '1', notarget: '3' }; + + try { + addEdge(newEdge, elements); + } catch (e) { + console.log(e.message); + + expect(e.message).to.be.equal("Can't create edge. An edge needs a source and a target."); + } + }); + + it('tries to add edge with id that does not exist', () => { + const notExistingId = 'does-not-exist'; + const newEdge = { source: notExistingId, target: '3' }; + + try { + addEdge(newEdge, elements); + } catch (e) { + console.log(e.message); + expect(e.message).to.be.equal(`Can't create edge. Node with id=${notExistingId} does not exist.`); + } + }); + }); + + describe('tests removeElements function', () => { + it('removes a node', () => { + const nextElements = removeElements([nodes[0]], elements); + + const nextNodes = nextElements.filter((e) => isNode(e)); + const nextEdges = nextElements.filter((e) => isEdge(e)); + + expect(nextNodes.length).to.be.equal(nodes.length - 1); + expect(nextEdges.length).to.be.equal(edges.length - 2); + }); + + it('removes multiple nodes', () => { + const elementsToRemove = [nodes[0], nodes[1]]; + const nextElements = removeElements(elementsToRemove, elements); + const nextNodes = nextElements.filter((e) => isNode(e)); + const nextEdges = nextElements.filter((e) => isEdge(e)); + + expect(nextNodes.length).to.be.equal(nodes.length - 2); + expect(nextEdges.length).to.be.equal(0); + }); + + it('removes no node', () => { + const nextElementsNoRemove = removeElements([], elements); + expect(nextElementsNoRemove.length).to.be.equal(elements.length); + }); + + it('tries to removes node that does not exist', () => { + const nextElementsNoRemove = removeElements([{ id: 'id-that-does-not-exist' }], elements); + expect(nextElementsNoRemove.length).to.be.equal(elements.length); + }); + + it('removes an edge', () => { + const nextElements = removeElements([edges[0]], elements); + + const nextNodes = nextElements.filter((e) => isNode(e)); + const nextEdges = nextElements.filter((e) => isEdge(e)); + + expect(nextNodes.length).to.be.equal(nodes.length); + expect(nextEdges.length).to.be.equal(edges.length - 1); + }); + + it('removes multiple edges', () => { + const nextElements = removeElements([edges[0], edges[1]], elements); + + const nextNodes = nextElements.filter((e) => isNode(e)); + const nextEdges = nextElements.filter((e) => isEdge(e)); + + expect(nextNodes.length).to.be.equal(nodes.length); + expect(nextEdges.length).to.be.equal(edges.length - 2); + }); + + it('removes node and edge', () => { + const nextElements = removeElements([nodes[0], edges[0]], elements); + + const nextNodes = nextElements.filter((e) => isNode(e)); + const nextEdges = nextElements.filter((e) => isEdge(e)); + + expect(nextNodes.length).to.be.equal(nodes.length - 1); + expect(nextEdges.length).to.be.equal(edges.length - 2); + }); + }); +}); diff --git a/src/utils/graph.ts b/src/utils/graph.ts index 8b899913..79ebfc04 100644 --- a/src/utils/graph.ts +++ b/src/utils/graph.ts @@ -33,9 +33,16 @@ const getEdgeId = ({ source, target }: Connection): ElementId => `reactflow__edg export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elements => { if (!edgeParams.source || !edgeParams.target) { - throw new Error('Can not create edge. An edge needs a source and a target'); + throw new Error("Can't create edge. An edge needs a source and a target."); } + // make sure that there is node with the target and one with the source id + [edgeParams.source, edgeParams.target].forEach((id) => { + if (!elements.find((e) => isNode(e) && e.id === id)) { + throw new Error(`Can't create edge. Node with id=${id} does not exist.`); + } + }); + if (isEdge(edgeParams)) { return elements.concat({ ...edgeParams }); }