join-status.check.js 3.03 KB
/**
 * 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: 全部通过');