import { connectionToEdge, addEdgeToGraph, removeNodesFromGraph, removeEdgesFromGraph, } from '../graph-ops'; import type { WorkflowGraph } from '../types'; const graph: WorkflowGraph = { nodes: [ { id: 'a', name: 'A', type: 'trigger.event' }, { id: 'b', name: 'B', type: 'transform.set' }, { id: 'c', name: 'C', type: 'action.email' }, ], edges: [ { source: 'a', target: 'b' }, { source: 'b', target: 'c', sourceOutput: 1 }, ], }; describe('connectionToEdge', () => { it('maps handle id strings to numeric output/input indexes', () => { expect( connectionToEdge({ source: 'b', target: 'c', sourceHandle: '1', targetHandle: '0', }) ).toEqual({ source: 'b', target: 'c', sourceOutput: 1, targetInput: 0, type: 'main', }); }); it('defaults missing/null handles to index 0', () => { expect( connectionToEdge({ source: 'a', target: 'b', sourceHandle: null }) ).toEqual({ source: 'a', target: 'b', sourceOutput: 0, targetInput: 0, type: 'main', }); }); }); describe('addEdgeToGraph', () => { it('appends a new edge', () => { const next = addEdgeToGraph(graph, { source: 'a', target: 'c', sourceOutput: 0, targetInput: 0, }); expect(next.edges).toHaveLength(3); expect(next.edges).toContainEqual( expect.objectContaining({ source: 'a', target: 'c' }) ); // does not mutate the input expect(graph.edges).toHaveLength(2); }); it('is a no-op for a duplicate edge (same source/output/target/input)', () => { const next = addEdgeToGraph(graph, { source: 'a', target: 'b', sourceOutput: 0, targetInput: 0, }); expect(next.edges).toHaveLength(2); }); }); describe('removeNodesFromGraph', () => { it('removes the node AND every incident edge (as source or target)', () => { const next = removeNodesFromGraph(graph, ['b']); expect(next.nodes.map((n) => n.id)).toEqual(['a', 'c']); // a->b and b->c both reference b, so both go expect(next.edges).toHaveLength(0); }); it('keeps edges between surviving nodes', () => { const next = removeNodesFromGraph(graph, ['c']); expect(next.nodes.map((n) => n.id)).toEqual(['a', 'b']); expect(next.edges).toEqual([{ source: 'a', target: 'b' }]); }); }); describe('removeEdgesFromGraph', () => { it('removes only the matching edge (by source/target/output/input)', () => { const next = removeEdgesFromGraph(graph, [ { source: 'b', target: 'c', sourceOutput: 1, targetInput: 0 }, ]); expect(next.edges).toEqual([{ source: 'a', target: 'b' }]); }); });