Files
next-tjwater-frontend/src/features/workbench/api/operational-task-client.test.ts
T

60 lines
3.5 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import { parseOperationalTask } from "./operational-task-client";
vi.mock("./project-client", () => ({
findOwnedWorkbenchProject: vi.fn(async () => ({ project: { project_id: "project" }, accessToken: "test" })),
createWorkbenchHeaders: vi.fn(() => ({})),
getServerError: vi.fn(() => "请求失败")
}));
const id = "324ff7ee-c2d4-5184-a84b-48fb14a2933e";
const time = "2026-09-23T01:00:00Z";
function task(generation: number | null | undefined = 2) {
const snapshot = { revision: 1, source_session_id: "session", published_at: time, published_by: "agent",
...(generation === undefined ? {} : { execution_generation: generation }) };
return {
project_id: id, task_id: id, task_type: "event_investigation", workflow: "water_quality_complaint",
lifecycle_status: "waiting_human", active_run: null,
status: "waiting_human", priority: "normal", revision: 1, execution_generation: 2,
execution_request_id: id, title: "水质投诉", summary: "调查中",
source: { kind: "external_system", external_id: null, external_revision: null, event_kind: null },
trigger: { kind: "event", occurred_at: time, detail: "投诉上报" },
scheduled_for: null, agent_session_id: "session", agent_lease_expires_at: null,
current_plan_revision: 1, current_report_revision: 1, created_at: time, updated_at: time,
latest_plan: { ...snapshot, plan: { schema: "execution-plan@1", title: "调查", reason: "投诉",
nodes: [{ id: "check", title: "核查", owner: "agent", status: "completed", detail: "已核查", evidence_refs: [], action_refs: [] }], edges: [] } },
latest_report: { ...snapshot, report: { title: "调查报告", current_conclusion: "待采样",
conclusion_boundary: "尚无现场证据", evidence_refs: [], recommendations: [], pending_items: ["采样"] } },
evidence: [], actions: [], permissions: { can_publish_artifacts: false, can_propose_actions: false,
can_sync_external_feedback: false, can_decide_work_orders: false, can_execute_work_orders: false,
can_decide_commands: false, can_execute_commands: false }
};
}
afterEach(() => vi.unstubAllGlobals());
describe("operational task contract", () => {
it("accepts execution generation on both plan and report", () => {
const parsed = parseOperationalTask(task());
expect(parsed.latest_plan).toHaveProperty("execution_generation", 2);
expect(parsed.latest_report).toHaveProperty("execution_generation", 2);
});
it("accepts legacy null or missing snapshot generation", () => {
expect(() => parseOperationalTask(task(null))).not.toThrow();
const legacy = task();
Reflect.deleteProperty(legacy.latest_plan, "execution_generation");
Reflect.deleteProperty(legacy.latest_report, "execution_generation");
expect(() => parseOperationalTask(legacy)).not.toThrow();
});
it("accepts a task without any plan or report", () => {
expect(parseOperationalTask({ ...task(), latest_plan: null, latest_report: null }).latest_report).toBeNull();
});
it("keeps unknown fields and invalid generations rejected", () => {
expect(() => parseOperationalTask(task(0))).toThrow();
const value = task();
expect(() => parseOperationalTask({ ...value, latest_plan: { ...value.latest_plan, unexpected: true } })).toThrow();
expect(() => parseOperationalTask({ ...value, latest_report: { ...value.latest_report, unexpected: true } })).toThrow();
expect(() => parseOperationalTask({ ...value, latest_report: { ...value.latest_report, execution_generation: -1 } })).toThrow();
});
});