/** * join-status 的可运行检查(`node web/src/components/graph-console/join-status.check.js`)。 * 同款手法见 io-model.check.js 的头注——web/ 不在 vitest include 里,用 assert 自跑。 */ import assert from 'node:assert/strict'; import { resolveJoinWait, joinWaitLabel } from './join-status.js'; const nodes = [ { defNodeId: 'entry', name: 'entry', status: 'success' }, { defNodeId: 'a', name: 'a', status: 'success' }, { defNodeId: 'b', name: 'b', status: 'running' }, { defNodeId: 'c', name: 'c', status: 'fail' }, { defNodeId: 'join', name: 'join', status: 'pending' }, { defNodeId: 'chain2', name: 'chain2', status: 'pending' }, ]; const edges = [ { from: 'entry', to: 'a', condition: 'success', edgeKind: 'forward' }, { from: 'entry', to: 'b', condition: 'success', edgeKind: 'forward' }, { from: 'entry', to: 'c', condition: 'success', edgeKind: 'forward' }, { from: 'a', to: 'join', condition: 'success', edgeKind: 'forward' }, { from: 'b', to: 'join', condition: 'success', edgeKind: 'forward' }, { from: 'c', to: 'join', condition: 'success', edgeKind: 'forward' }, { from: 'a', to: 'chain2', condition: 'success', edgeKind: 'forward' }, // backward 边不参与等待判定,即使指向 join 也不该被数进 waiting { from: 'join', to: 'a', condition: 'fail', edgeKind: 'backward' }, ]; // ① 真正的 fan-in:join 在等 b(running)/c(fail),a 已经 success { const wait = resolveJoinWait(nodes.find((n) => n.defNodeId === 'join'), nodes, edges); assert.equal(wait.total, 3); assert.equal(wait.done, 1); assert.equal(wait.isFanIn, true); assert.equal(wait.satisfied, false); assert.deepEqual(wait.blockedBy.map((w) => w.defNodeId).sort(), ['b', 'c']); const label = joinWaitLabel(wait); assert.equal(label.text, '⏳1/3'); assert.match(label.title, /a\(success\)/); assert.match(label.title, /b\(running\)/); assert.match(label.title, /c\(fail\)/); } // ② 单一入边的普通顺序等待:不是 fan-in,不出徽标(避免给每一条链都加噪声) { const wait = resolveJoinWait(nodes.find((n) => n.defNodeId === 'chain2'), nodes, edges); assert.equal(wait.total, 1); assert.equal(wait.isFanIn, false); assert.equal(joinWaitLabel(wait), null); } // ③ 非 pending 节点:不适用(已经跑过或正在跑,没有「在等谁」这回事) { assert.equal(resolveJoinWait(nodes.find((n) => n.defNodeId === 'a'), nodes, edges), null); } // ④ 已满足(引擎下一拍就会点亮,这一刻不该显示「在等」) { const satisfiedNodes = nodes.map((n) => (n.defNodeId === 'b' || n.defNodeId === 'c' ? { ...n, status: 'success' } : n)); const wait = resolveJoinWait(satisfiedNodes.find((n) => n.defNodeId === 'join'), satisfiedNodes, edges); assert.equal(wait.satisfied, true); assert.equal(joinWaitLabel(wait), null); } // ⑤ 没有 forward success 入边(图的入口节点):不适用 { assert.equal(resolveJoinWait({ defNodeId: 'entry', status: 'pending' }, nodes, edges), null); } console.log('join-status.check.js: 全部通过');