UNPKG

@logicflow/core

Version:

LogicFlow, help you quickly create flowcharts

576 lines (525 loc) 14.6 kB
import { BaseNode, BaseNodeModel, Keyboard } from '../src' import LogicFlow from '../src/LogicFlow' // import Tool from '../src/tool' /** * @jest-environment jsdom */ describe('logicflow/initialize', () => { test('init', () => { const initContainerSpy = jest.spyOn( LogicFlow.prototype as any, 'initContainer' as any, ) const dom = document.createElement('div') dom.id = 'main-graph' document.body.appendChild(dom) const lf = new LogicFlow({ container: dom, }) expect(initContainerSpy).toBeCalled() expect(lf).toBeDefined() }) test('elements register', () => { const defaultRegister = jest.fn() jest .spyOn(LogicFlow.prototype as any, 'defaultRegister') .mockImplementation(defaultRegister) const dom = document.createElement('div') dom.id = 'main-graph' document.body.appendChild(dom) const lf = new LogicFlow({ container: dom, }) lf.register({ type: 'test', view: BaseNode, model: BaseNodeModel, }) lf.register('custom', ({ RectNode, RectNodeModel }) => { class CustomView extends RectNode {} class CustomModel extends RectNodeModel {} return { view: CustomView, model: CustomModel, } }) expect(defaultRegister).toBeCalled() expect(lf.getView('test')).toBeDefined() expect(lf.getView('custom')).toBeDefined() expect(lf.graphModel.getModel('test')).toBeDefined() expect(lf.graphModel.getModel('custom')).toBeDefined() }) test('register plugin by Logicflow.use', () => { class Plugin { static pluginName = 'test-use' lf: LogicFlow constructor(lf: LogicFlow) { this.lf = lf } init() {} } LogicFlow.use(Plugin) expect(LogicFlow.extensions.get('test-use')).toBeDefined() }) test('shortcut', () => { const initShortcuts = jest.fn() const on = jest.fn() Keyboard.prototype.initShortcuts = initShortcuts Keyboard.prototype.on = on const dom = document.createElement('div') dom.id = 'main-graph' document.body.appendChild(dom) // eslint-disable-next-line @typescript-eslint/no-unused-vars const lf = new LogicFlow({ container: dom, }) expect(initShortcuts).toBeCalled() expect(on).toBeCalledTimes(5) }) test('not silent mode', () => { const initShortcuts = jest.fn() Keyboard.prototype.initShortcuts = initShortcuts const dom = document.createElement('div') dom.id = 'main-graph' document.body.appendChild(dom) // eslint-disable-next-line @typescript-eslint/no-unused-vars const lf = new LogicFlow({ container: dom, isSilentMode: false, }) expect(initShortcuts).toBeCalledTimes(1) }) }) describe('logicflow/apis', () => { const rawData = { nodes: [ { id: 'node1', type: 'circle', x: 100, y: 100, text: 'node1', }, { id: 'node2', type: 'rect', x: 200, y: 200, text: 'node2', }, { id: 'node3', type: 'ellipse', x: 300, y: 300, rx: 10, ry: 5, text: 'node3', }, { id: 'node4', type: 'polygon', x: 400, y: 400, text: 'node4', }, ], edges: [ { id: 'edge1', type: 'line', sourceNodeId: 'node1', targetNodeId: 'node2', }, { id: 'edge2', type: 'polyline', sourceNodeId: 'node2', targetNodeId: 'node3', }, { id: 'edge3', type: 'bezier', sourceNodeId: 'node2', targetNodeId: 'node4', }, ], } describe('operations on node/edge model ', () => { const dom = document.createElement('div') dom.id = 'main-graph' document.body.appendChild(dom) const lf = new LogicFlow({ container: dom, width: 1000, height: 1000, keyboard: { enabled: true, }, allowRotation: true, metaKeyMultipleSelected: true, grid: { size: 10, type: 'dot', }, snapline: true, guards: { beforeClone: (data: any) => !['node1'].includes(data.id), beforeDelete: (data: any) => !['node1', 'edge1'].includes(data.id), }, }) test('render', () => { lf.render(rawData) expect(lf.graphModel.nodes.length).toBe(4) expect(lf.graphModel.edges.length).toBe(3) }) test('set default edge type', () => { lf.setDefaultEdgeType('line') expect(lf.graphModel.edgeType).toBe('line') }) test('delete elements with guards', () => { lf.render(rawData) expect(lf.deleteElement('node1')).toBeFalsy() expect(lf.deleteElement('node2')).toBeTruthy() expect(lf.deleteElement('node5')).toBeFalsy() expect(lf.graphModel.nodes.length).toBe(3) }) test('add elements', () => { lf.render(rawData) lf.addElements({ nodes: [ { id: 'node_1_1', type: 'rect', x: 100, y: 100, }, { id: 'node_2_1', type: 'rect', x: 200, y: 300, }, ], edges: [ { id: 'edge_3_1', type: 'polyline', sourceNodeId: 'node_1_1', targetNodeId: 'node_2_1', }, ], }) expect(lf.graphModel.nodes.length).toBe(6) expect(lf.graphModel.edges.length).toBe(4) }) test('add node', () => { lf.render(rawData) lf.addNode({ id: 'node5', type: 'text', x: 100, y: 100, text: 'node5', }) expect(lf.graphModel.nodes.length).toBe(5) lf.updateText('node5', 'node5_1') lf.updateText('edge1', 'edge1') expect(lf.getNodeModelById('node5').text.value).toBe('node5_1') expect(lf.getEdgeModelById('edge1').text.value).toBe('edge1') }) test('change node id', () => { lf.render(rawData) expect(lf.changeNodeId('node1', 'node1_1')).toBe('node1_1') expect(lf.changeNodeId('node1_1', 'node2')).toBeFalsy() expect(lf.changeNodeId('node1_1_1', 'node1_1_2')).toBeFalsy() }) test('clone node with guards', () => { lf.render(rawData) expect(lf.cloneNode('node1')).toBeFalsy() expect(lf.cloneNode('node2')).toBeTruthy() expect(lf.graphModel.nodes.length).toBe(5) }) test('get data by id', () => { lf.render(rawData) expect(lf.getDataById('node1')).toBeDefined() expect(lf.getDataById('edge1')).toBeDefined() }) test('get node data by id', () => { lf.render(rawData) expect(lf.getNodeDataById('node1')).toBeDefined() expect(lf.getNodeDataById('node6')).toBeUndefined() }) test('get edge data by id', () => { lf.render(rawData) expect(lf.getEdgeDataById('edge1')).toBeDefined() expect(lf.getEdgeDataById('edge4')).toBeUndefined() }) test('add edge', () => { lf.render(rawData) lf.addEdge({ id: 'edge4', type: 'polyline', sourceNodeId: 'node1', targetNodeId: 'node2', }) expect(lf.graphModel.edges.length).toBe(4) }) test('delete edge with guards', () => { lf.render(rawData) expect(lf.deleteEdge('edge1')).toBeFalsy() expect(lf.deleteEdge('edge2')).toBeTruthy() expect(lf.graphModel.edges.length).toBe(2) }) test('delete edge by nodeId', () => { lf.render({ nodes: [ { id: 'node1', type: 'rect', x: 100, y: 100, text: 'node1', }, { id: 'node2', type: 'rect', x: 200, y: 200, text: 'node2', }, { id: 'node3', type: 'rect', x: 300, y: 300, text: 'node3', }, { id: 'node4', type: 'diamond', x: 400, y: 400, text: 'node4', }, { id: 'node5', type: 'diamond', x: 500, y: 500, text: 'node5', }, ], edges: [ { id: 'edge1', type: 'polyline', sourceNodeId: 'node1', targetNodeId: 'node2', }, { id: 'edge2', type: 'polyline', sourceNodeId: 'node2', targetNodeId: 'node3', }, { id: 'edge3', type: 'polyline', sourceNodeId: 'node2', targetNodeId: 'node4', }, { id: 'edge4', type: 'polyline', sourceNodeId: 'node2', targetNodeId: 'node5', }, ], }) lf.deleteEdgeByNodeId({ targetNodeId: 'node3', }) expect(lf.graphModel.edges.length).toBe(3) lf.deleteEdgeByNodeId({ sourceNodeId: 'node1', targetNodeId: 'node2', }) expect(lf.graphModel.edges.length).toBe(2) lf.deleteEdgeByNodeId({ sourceNodeId: 'node2', }) expect(lf.graphModel.edges.length).toBe(0) }) test('change node type', () => { lf.render(rawData) lf.changeNodeType('node1', 'circle') expect(lf.getNodeModelById('node1').type).toBe('circle') }) test('change edge type', () => { lf.render(rawData) lf.changeEdgeType('edge1', 'line') expect(lf.getEdgeModelById('edge1').type).toBe('line') }) test('get incoming and outgoing edges of node', () => { lf.render(rawData) expect(lf.getNodeEdges('node2').length).toBe(3) }) test('get incoming edges', () => { lf.render(rawData) expect(lf.getNodeIncomingEdge('node2').length).toBe(1) }) test('get outgoing edges', () => { lf.renderRawData(rawData) expect(lf.getNodeOutgoingEdge('node2').length).toBe(2) }) test('get incoming node', () => { lf.renderRawData(rawData) expect(lf.getNodeIncomingNode('node2').length).toBe(1) }) test('get outgoing node', () => { lf.renderRawData(rawData) expect(lf.getNodeOutgoingNode('node2').length).toBe(2) }) test('get edge model by filter', () => { lf.render(rawData) expect( lf.getEdgeModels({ sourceNodeId: 'node2', }).length, ).toBe(2) expect( lf.getEdgeModels({ targetNodeId: 'node2', }).length, ).toBe(1) expect( lf.getEdgeModels({ sourceNodeId: 'node2', targetNodeId: 'node3', }).length, ).toBe(1) }) test('get elements in certain area', () => { lf.render(rawData) expect(lf.getAreaElement([0, 0], [1000, 1000]).length).toBe(7) }) test('set properties', () => { lf.renderRawData(rawData) lf.setProperties('node1', { a: { b: undefined, c: [], d: { e: 1, f: null, }, }, }) expect((lf.getProperties('node1') as any).a).toEqual({ b: undefined, c: [], d: { e: 1, f: null, }, }) }) test('delete properties', () => { lf.renderRawData(rawData) lf.deleteProperty('node1', 'a') expect(lf.getNodeModelById('node1').properties.a).toBeUndefined() }) test('select and to front in overlapMode 0', () => { lf.render(rawData) lf.selectElementById('node1') lf.selectElementById('node2', true) const selectElements = lf.getSelectElements() expect(selectElements.nodes.length).toBe(2) expect(selectElements.nodes[0].id).toBe('node1') expect(lf.getNodeModelById('node1').zIndex).toBe(9999) lf.clearSelectElements() expect(lf.getNodeModelById('node1').zIndex).toBe(1) }) test('to front in overlapMode 0', () => { lf.render(rawData) lf.toFront('node1') expect(lf.getNodeModelById('node1').zIndex).toBe(9999) }) test('get graph data', () => { lf.render(rawData) const graphData = lf.getGraphData() expect(lf.getGraphData()).toBeDefined() expect(graphData.nodes.length).toBe(4) expect(graphData.edges.length).toBe(3) }) test('clear graph data', () => { lf.render(rawData) lf.clearData() expect(lf.getGraphData()).toEqual({ nodes: [], edges: [], }) }) }) describe('transform', () => { const resize = jest.fn() const dom = document.createElement('div') dom.id = 'main-graph' document.body.appendChild(dom) const lf = new LogicFlow({ container: dom, stopScrollGraph: true, stopZoomGraph: true, metaKeyMultipleSelected: true, width: 1000, height: 1000, overlapMode: 1, }) lf.graphModel.resize = resize test('get transform information', () => { expect(lf.getTransform()).toEqual({ SCALE_X: 1, SCALE_Y: 1, TRANSLATE_X: 0, TRANSLATE_Y: 0, }) }) test('resize', () => { lf.resize(100, 100) expect(resize).toBeCalled() setTimeout(() => { expect(lf.graphModel.width).toBe(100) expect(lf.graphModel.height).toBe(100) }) }) test('zoom', () => { lf.zoom(0.5) expect(lf.graphModel.transformModel.SCALE_X).toBe(0.5) expect(lf.graphModel.transformModel.SCALE_Y).toBe(0.5) lf.resetZoom() expect(lf.graphModel.transformModel.SCALE_X).toBe(1) expect(lf.graphModel.transformModel.SCALE_Y).toBe(1) }) test('translate', () => { lf.translate(100, 100) expect(lf.graphModel.transformModel.TRANSLATE_X).toBe(100) expect(lf.graphModel.transformModel.TRANSLATE_Y).toBe(100) lf.resetTranslate() expect(lf.graphModel.transformModel.TRANSLATE_X).toBe(0) expect(lf.graphModel.transformModel.TRANSLATE_Y).toBe(0) }) test('select and to front in overlapMode 1', () => { lf.render(rawData) lf.selectElementById('node1') expect(lf.getNodeModelById('node1').zIndex).toBe(1008) lf.clearSelectElements() expect(lf.getNodeModelById('node1').zIndex).toBe(1008) }) test('to front in overlapMode 1', () => { lf.render(rawData) lf.toFront('node1') expect(lf.getNodeModelById('node1').zIndex).toBe(1016) }) }) })