import { describe, it, expect } from 'vitest' import { buildFlowLayout } from '@/utils/flowLayout' const diamond = { nodes: [ { id: 'start', type: 'start' }, { id: 'A', type: 'approval', name: '审批A' }, { id: 'cond', type: 'condition', name: '条件' }, { id: 'B1', type: 'approval', name: '大额审批' }, { id: 'B2', type: 'approval', name: '默认审批' }, { id: 'C', type: 'approval', name: '审批C' }, { id: 'end', type: 'end' }, ], edges: [ { sourceNodeId: 'start', targetNodeId: 'A' }, { sourceNodeId: 'A', targetNodeId: 'cond' }, { sourceNodeId: 'cond', targetNodeId: 'B1', condition: { condition: 'amount>=1000', isDefault: false } }, { sourceNodeId: 'cond', targetNodeId: 'B2', condition: { condition: '', isDefault: true } }, { sourceNodeId: 'B1', targetNodeId: 'C' }, { sourceNodeId: 'B2', targetNodeId: 'C' }, { sourceNodeId: 'C', targetNodeId: 'end' }, ], } const allIds = (rows: any[]) => rows.flatMap((r) => { const main = (r.nodes || []).map((n: any) => n.id) const branch = (r.branches || []).flatMap((b: any) => b.nodes.map((n: any) => n.id)) return main.concat(branch).concat(r.kind === 'branch' ? [`${r.title}`] : []) }) describe('buildFlowLayout', () => { it('线性流程全部展示且不重复', () => { const linear = { nodes: [ { id: 'start', type: 'start' }, { id: 'A', type: 'approval', name: 'A' }, { id: 'B', type: 'approval', name: 'B' }, { id: 'end', type: 'end' }, ], edges: [ { sourceNodeId: 'start', targetNodeId: 'A' }, { sourceNodeId: 'A', targetNodeId: 'B' }, { sourceNodeId: 'B', targetNodeId: 'end' }, ], } const rows = buildFlowLayout(linear.nodes, linear.edges, [ { nodeId: 'A', status: 'completed' }, { nodeId: 'B', status: 'current' }, ], []) const ids = allIds(rows) expect(ids.filter((x) => x === 'A')).toHaveLength(1) expect(ids.filter((x) => x === 'B')).toHaveLength(1) expect(rows.filter((r) => r.kind === 'branch')).toHaveLength(0) }) it('菱形分支:两条分支都展示,后续节点也展示,无重复', () => { const rows = buildFlowLayout(diamond.nodes, diamond.edges, [ { nodeId: 'A', status: 'completed' }, { nodeId: 'B1', status: 'completed' }, { nodeId: 'C', status: 'current' }, ], [{ nodeId: 'B1' }], 'C') const branchRow = rows.find((r) => r.kind === 'branch') expect(branchRow).toBeTruthy() expect(branchRow.branches).toHaveLength(2) expect(branchRow.branches[0].nodes[0].id).toBe('B1') expect(branchRow.branches[1].nodes[0].id).toBe('B2') // 后续节点 C、end 在主线上 expect(rows.some((r) => r.kind === 'node' && r.nodes?.[0]?.id === 'C')).toBe(true) expect(rows.some((r) => r.kind === 'end')).toBe(true) // 无重复 const ids = allIds(rows) for (const id of ['A', 'B1', 'B2', 'C']) { expect(ids.filter((x) => x === id)).toHaveLength(1) } // 已选择分支标记 expect(branchRow.branches[0].isChosen).toBe(true) expect(branchRow.branches[1].isChosen).toBe(false) }) it('直连合并点:默认分支直连下一节点,后续仍展示', () => { const direct = { nodes: [ { id: 'start', type: 'start' }, { id: 'A', type: 'approval', name: 'A' }, { id: 'cond', type: 'condition', name: '条件' }, { id: 'B1', type: 'approval', name: '大额' }, { id: 'C', type: 'approval', name: 'C' }, { id: 'end', type: 'end' }, ], edges: [ { sourceNodeId: 'start', targetNodeId: 'A' }, { sourceNodeId: 'A', targetNodeId: 'cond' }, { sourceNodeId: 'cond', targetNodeId: 'B1', condition: { condition: 'x', isDefault: false } }, { sourceNodeId: 'cond', targetNodeId: 'C', condition: { condition: '', isDefault: true } }, { sourceNodeId: 'B1', targetNodeId: 'C' }, { sourceNodeId: 'C', targetNodeId: 'end' }, ], } const rows = buildFlowLayout(direct.nodes, direct.edges, [ { nodeId: 'A', status: 'completed' }, { nodeId: 'C', status: 'current' }, ], [], 'C') const branchRow = rows.find((r) => r.kind === 'branch') expect(branchRow).toBeTruthy() expect(branchRow.branches).toHaveLength(2) // C 在分支后主线上出现一次 expect(rows.filter((r) => r.nodes?.some((n: any) => n.id === 'C'))).toHaveLength(1) expect(rows.some((r) => r.kind === 'end')).toBe(true) }) it('导入型:前面主线节点标记为已走过(passed)', () => { const rows = buildFlowLayout(diamond.nodes, diamond.edges, [ { nodeId: 'C', status: 'current' }, ], [], 'C') const aRow = rows.find((r) => r.nodes?.[0]?.id === 'A') expect(aRow?.nodes?.[0]?.status).toBe('passed') }) it('分支内节点状态:未选择分支为 pending', () => { const rows = buildFlowLayout(diamond.nodes, diamond.edges, [ { nodeId: 'A', status: 'completed' }, { nodeId: 'B1', status: 'completed' }, { nodeId: 'C', status: 'current' }, ], [], 'C') const branchRow = rows.find((r) => r.kind === 'branch') expect(branchRow.branches[0].nodes[0].status).toBe('completed') expect(branchRow.branches[1].nodes[0].status).toBe('pending') }) })