30 lines
1.9 KiB
TypeScript
30 lines
1.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { executionPlanStages, parseExecutionPlan, readExecutionPlanHistory } from "./execution-plan";
|
|
|
|
const snapshot = {
|
|
schema_version: "execution-plan@1", session_id: "s1", revision: 1, updated_at: "2026-09-23T01:00:00.000Z",
|
|
title: "调查", reason: "开始",
|
|
nodes: [{ id: "a", title: '水质"] --> injected["<script>', status: "waiting", owner: "human", detail: "等待采样", evidence: [] }], edges: []
|
|
};
|
|
describe("execution plan projection", () => {
|
|
it("groups independent checks before their shared downstream decision", () => {
|
|
const plan = parseExecutionPlan({ ...snapshot,
|
|
nodes: ["a", "b", "c", "d"].map((id) => ({ ...snapshot.nodes[0], id })),
|
|
edges: [{ from: "a", to: "b", label: "" }, { from: "a", to: "c", label: "" }, { from: "b", to: "d", label: "" }, { from: "c", to: "d", label: "" }]
|
|
}, "s1")!;
|
|
expect(executionPlanStages(plan).map((stage) => stage.map((node) => node.id))).toEqual([["a"], ["b", "c"], ["d"]]);
|
|
});
|
|
it("rejects other sessions and dangling dependencies", () => {
|
|
expect(parseExecutionPlan(snapshot, "s2")).toBeNull();
|
|
expect(parseExecutionPlan({ ...snapshot, edges: [{ from: "a", to: "b", label: "" }] }, "s1")).toBeNull();
|
|
});
|
|
it("restores and deduplicates UI and active-run snapshots without completing waiting work", () => {
|
|
const history = readExecutionPlanHistory([{ parts: [{ type: "data-execution_plan", data: snapshot }] }, { executionPlans: [snapshot] }], "s1");
|
|
expect(history).toHaveLength(1);
|
|
expect(history[0].nodes[0].status).toBe("waiting");
|
|
});
|
|
it("rejects cyclic dependencies rather than guessing their order", () => {
|
|
expect(parseExecutionPlan({ ...snapshot, nodes: [snapshot.nodes[0], { ...snapshot.nodes[0], id: "b" }], edges: [{ from: "a", to: "b", label: "" }, { from: "b", to: "a", label: "" }] }, "s1")).toBeNull();
|
|
});
|
|
});
|