@logicflow/core
Version:
LogicFlow, help you quickly create flowcharts
576 lines (525 loc) • 14.6 kB
text/typescript
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)
})
})
})