import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, join, resolve } from "node:path"; const __dirname = dirname(fileURLToPath(import.meta.url)); const source = readFileSync(join(__dirname, "DashboardView.vue"), "utf8"); const mainCss = readFileSync(resolve(__dirname, "../styles/main.css"), "utf8"); describe("DashboardView material lot lifecycle DAG", () => { it("uses closed-loop material batch copy and stage labels", () => { assert.match(source, /材料库存批次闭环图/); assert.match(source, /生产台账/); assert.match(source, /库外闭环/); assert.match(source, /入库结果/); assert.doesNotMatch(source, /原材料生命周期 DAG/); }); it("knows all production ledger lifecycle node types", () => { [ "production_ledger", "production_issue_txn", "ledger_outside_balance", "production_ledger_settlement", "finished_inbound", "surplus_inbound", "scrap_inbound", "ledger_writeoff", "ledger_reopen", "operation_report", "delivery" ].forEach((nodeType) => { assert.match(source, new RegExp(nodeType)); }); }); it("frames operation reports as evidence instead of lifecycle control nodes", () => { assert.match(source, /报工证据/); assert.match(source, /报工仅作证据/); assert.doesNotMatch(source, /stage:\s*standardStageLabel\(node\)/); assert.match(source, /stageBandLabel/); }); it("uses parent-aware row placement before business priority", () => { assert.match(source, /buildParentByTarget/); assert.match(source, /buildParentRank/); assert.match(source, /parentRank/); assert.match(source, /compareDagNode\(left,\s*right,\s*parentRank/); }); it("styles the new lifecycle legend and node type treatments", () => { [ ".dag-node-ledger", ".dag-node-balance", ".dag-node-settlement", ".dag-node-evidence", ".dag-legend" ].forEach((selector) => { assert.match(mainCss, new RegExp(selector.replace(".", "\\."))); }); }); });