feat(workbench): integrate operational workflows and map state
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
fetchWorkbenchAnalysisRun,
|
||||
fetchWorkbenchRuntimeSnapshot
|
||||
parseWorkbenchRuntimeSnapshot
|
||||
} from "./workbench-runtime-client";
|
||||
|
||||
const projectPage = {
|
||||
@@ -89,16 +89,8 @@ const runtimeSnapshot = {
|
||||
describe("workbench runtime API client", () => {
|
||||
afterEach(() => vi.unstubAllGlobals());
|
||||
|
||||
it("resolves the project and maps a persisted scheduled condition", async () => {
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(projectPage), { status: 200 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(runtimeSnapshot), { status: 200 }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const snapshot = await fetchWorkbenchRuntimeSnapshot(
|
||||
vi.fn().mockResolvedValue("access-token")
|
||||
);
|
||||
it("maps a persisted scheduled condition", () => {
|
||||
const snapshot = parseWorkbenchRuntimeSnapshot(runtimeSnapshot);
|
||||
|
||||
expect(snapshot.source).toBe("scheduled_tasks");
|
||||
expect(snapshot.conditions).toEqual([
|
||||
@@ -140,17 +132,10 @@ describe("workbench runtime API client", () => {
|
||||
})
|
||||
]));
|
||||
expect(snapshot.simulationOverlay?.features).toHaveLength(1);
|
||||
const runtimeHeaders = new Headers(fetchMock.mock.calls[1]?.[1]?.headers);
|
||||
expect(runtimeHeaders.get("Authorization")).toBe("Bearer access-token");
|
||||
expect(runtimeHeaders.get("X-Project-Id")).toBe("project-1");
|
||||
expect(String(fetchMock.mock.calls[1]?.[0])).toContain("/api/v1/workbench/runtime");
|
||||
});
|
||||
|
||||
it("keeps legacy analysis conditions out of the operational task feed", async () => {
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(projectPage), { status: 200 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify({
|
||||
it("keeps legacy analysis conditions out of the operational task feed", () => {
|
||||
const snapshot = parseWorkbenchRuntimeSnapshot({
|
||||
...runtimeSnapshot,
|
||||
source: "analysis_runs",
|
||||
conditions: [{
|
||||
@@ -168,10 +153,7 @@ describe("workbench runtime API client", () => {
|
||||
evidence: ["运行 ID:analysis-1"],
|
||||
model_name: "TJWater analysis runtime"
|
||||
}]
|
||||
}), { status: 200 }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const snapshot = await fetchWorkbenchRuntimeSnapshot();
|
||||
});
|
||||
|
||||
expect(snapshot.source).toBe("none");
|
||||
expect(snapshot.conditions).toEqual([]);
|
||||
@@ -182,16 +164,8 @@ describe("workbench runtime API client", () => {
|
||||
expect(snapshot.scenarios).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("rejects an untyped runtime payload instead of treating it as real data", async () => {
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(projectPage), { status: 200 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify({ ...runtimeSnapshot, source: "production" }), {
|
||||
status: 200
|
||||
}));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(fetchWorkbenchRuntimeSnapshot()).rejects.toThrow();
|
||||
it("rejects an untyped runtime payload instead of treating it as real data", () => {
|
||||
expect(() => parseWorkbenchRuntimeSnapshot({ ...runtimeSnapshot, source: "production" })).toThrow();
|
||||
});
|
||||
|
||||
it("loads the requested analysis run instead of reusing the latest result", async () => {
|
||||
@@ -247,11 +221,8 @@ describe("workbench runtime API client", () => {
|
||||
expect(headers.get("X-Project-Id")).toBe("project-1");
|
||||
});
|
||||
|
||||
it("drops invalid backend map geometry without discarding other real sections", async () => {
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(projectPage), { status: 200 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify({
|
||||
it("drops invalid backend map geometry without discarding other real sections", () => {
|
||||
const snapshot = parseWorkbenchRuntimeSnapshot({
|
||||
...runtimeSnapshot,
|
||||
latest_analysis: {
|
||||
...runtimeSnapshot.latest_analysis,
|
||||
@@ -264,10 +235,7 @@ describe("workbench runtime API client", () => {
|
||||
}]
|
||||
}
|
||||
}
|
||||
}), { status: 200 }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const snapshot = await fetchWorkbenchRuntimeSnapshot();
|
||||
});
|
||||
|
||||
expect(snapshot.source).toBe("scheduled_tasks");
|
||||
expect(snapshot.scenarios).toHaveLength(1);
|
||||
@@ -276,7 +244,7 @@ describe("workbench runtime API client", () => {
|
||||
expect(snapshot.latestAnalysisArtifact).not.toHaveProperty("spatialOverlay");
|
||||
});
|
||||
|
||||
it("maps provisioned backend work orders without using the demo shape", async () => {
|
||||
it("maps provisioned backend work orders without using the demo shape", () => {
|
||||
const backendWorkOrder = {
|
||||
id: "wo-1",
|
||||
code: "WO-20260917-001",
|
||||
@@ -334,21 +302,15 @@ describe("workbench runtime API client", () => {
|
||||
reply_requirements: ["回传阀门开度"]
|
||||
}]
|
||||
};
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(projectPage), { status: 200 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify({
|
||||
const snapshot = parseWorkbenchRuntimeSnapshot({
|
||||
...runtimeSnapshot,
|
||||
work_order_availability: "ready",
|
||||
work_orders: [backendWorkOrder]
|
||||
}), { status: 200 }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const snapshot = await fetchWorkbenchRuntimeSnapshot();
|
||||
});
|
||||
|
||||
expect(snapshot.workOrderAvailability).toBe("ready");
|
||||
expect(snapshot.workOrders).toEqual([expect.objectContaining({
|
||||
id: "wo-1",
|
||||
id: "demo-work-order:wo-1",
|
||||
kind: "work_order",
|
||||
code: "WO-20260917-001",
|
||||
status: "completed",
|
||||
@@ -364,11 +326,8 @@ describe("workbench runtime API client", () => {
|
||||
})]);
|
||||
});
|
||||
|
||||
it("maps a provisioned backend alert without inventing a condition link", async () => {
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify(projectPage), { status: 200 }))
|
||||
.mockResolvedValueOnce(new Response(JSON.stringify({
|
||||
it("maps a provisioned backend alert without inventing a condition link", () => {
|
||||
const snapshot = parseWorkbenchRuntimeSnapshot({
|
||||
...runtimeSnapshot,
|
||||
alert_availability: "ready",
|
||||
alerts: [{
|
||||
@@ -384,10 +343,7 @@ describe("workbench runtime API client", () => {
|
||||
occurred_at: "2026-09-17T02:29:00Z",
|
||||
severity: "warning"
|
||||
}]
|
||||
}), { status: 200 }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const snapshot = await fetchWorkbenchRuntimeSnapshot();
|
||||
});
|
||||
|
||||
expect(snapshot.alertAvailability).toBe("ready");
|
||||
expect(snapshot.alerts).toEqual([expect.objectContaining({
|
||||
|
||||
Reference in New Issue
Block a user