fix: restore investigation and appointment task loading
Server responses now include source.replay_context, including null for ordinary tasks. The strict frontend source schema rejected the new field and blocked the shared task snapshot and detail loading path. Validate replay metadata explicitly and cover investigation, appointment, and scheduled task contracts plus browser loading. Six acceptance regressions failed before the fix; all 877 unit tests and the focused browser loading test passed after it. Lint and type checking passed. The separate approval browser case remains blocked by its reconnect-toast assertion.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import type { OperationalTask, OperationalTaskSummary } from "../../src/features/workbench/api/operational-task-client";
|
||||
import { mockAgentApi } from "./support/mock-agent-api";
|
||||
import { mockWorkbenchContext } from "./support/mock-workbench-context";
|
||||
|
||||
test("调查和预约任务接收 Server 返回的空回放上下文并展示详情", async ({ page }, testInfo) => {
|
||||
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||
const now = new Date().toISOString();
|
||||
const id = "72000000-0000-4000-8000-000000000001";
|
||||
const appointmentId = "72000000-0000-4000-8000-000000000002";
|
||||
const summary: OperationalTaskSummary = {
|
||||
project_id: "324ff7ee-c2d4-5184-a84b-48fb14a2933e", task_id: id,
|
||||
task_type: "event_investigation", workflow: "burst_report",
|
||||
lifecycle_status: "waiting_human", active_run: null, status: "waiting_human",
|
||||
priority: "urgent", revision: 1, execution_generation: 1, execution_request_id: id,
|
||||
title: "凤阳爆管调查加载核验", summary: "核对调查任务详情",
|
||||
source: { kind: "external_system", external_id: id, external_revision: 1,
|
||||
event_kind: "burst_report", replay_context: null },
|
||||
trigger: { kind: "event", occurred_at: now, detail: "核对调查任务详情" },
|
||||
scheduled_for: null, agent_session_id: null, agent_lease_expires_at: null,
|
||||
current_plan_revision: null, current_report_revision: null, created_at: now, updated_at: now
|
||||
};
|
||||
const appointment: OperationalTaskSummary = {
|
||||
...summary, task_id: appointmentId, task_type: "external_work_order", workflow: "external-work-order",
|
||||
lifecycle_status: "open", status: "running", priority: "normal", execution_request_id: appointmentId,
|
||||
title: "凤阳预约维修加载核验", summary: "核对预约任务详情", scheduled_for: now,
|
||||
source: { ...summary.source, external_id: `peripheral_sample:${appointmentId}`, event_kind: "general" },
|
||||
trigger: { kind: "external_sync", occurred_at: now, detail: "核对预约任务详情" }
|
||||
};
|
||||
const summaries = [summary, appointment];
|
||||
const tasks: OperationalTask[] = summaries.map((item) => ({
|
||||
...item, latest_plan: null, latest_report: null, 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 },
|
||||
work_order_snapshot: item.task_type === "external_work_order" ? {
|
||||
work_order_id: appointmentId, revision: 1, title: item.title, summary: item.summary,
|
||||
status: "open", priority: "normal", assignee: "凤阳维修组", scheduled_at: now,
|
||||
work_order_type: "general", location: "凤阳核验点", scenario_code: null,
|
||||
origin: "system_data", updated_at: now
|
||||
} : null
|
||||
}));
|
||||
const runtime = {
|
||||
availability: "not_configured", source: "none", scenario_availability: "not_configured",
|
||||
artifact_availability: "not_configured", schedule_availability: "not_configured",
|
||||
work_order_availability: "not_configured", alert_availability: "not_configured",
|
||||
generated_at: now, conditions: [], alerts: [], scenarios: [], latest_analysis: null, work_orders: []
|
||||
};
|
||||
await mockWorkbenchContext(page, runtime);
|
||||
await mockAgentApi(page);
|
||||
await page.route("https://tjwater-api.invalid/api/v1/workbench/sync-snapshot", (route) => route.fulfill({ json: {
|
||||
schema: "workbench-sync-snapshot@1", event_cursor: 0, runtime,
|
||||
tasks: summaries, notifications: [], generated_at: now
|
||||
} }));
|
||||
await page.route("https://tjwater-api.invalid/api/v1/operational-tasks/*", (route) => {
|
||||
const taskId = new URL(route.request().url()).pathname.split("/").at(-1);
|
||||
const task = tasks.find((item) => item.task_id === taskId);
|
||||
return route.fulfill({ status: task ? 200 : 404, json: task ?? {} });
|
||||
});
|
||||
|
||||
await page.goto("/");
|
||||
await page.getByRole("button", { name: "工况任务", exact: true }).click();
|
||||
const panel = page.getByRole("region", { name: "工况任务", exact: true });
|
||||
await panel.getByRole("button", { name: "展开工况任务" }).click();
|
||||
await panel.getByRole("button", { name: /调查任务/ }).click();
|
||||
await panel.getByText(summary.title, { exact: true }).first().click();
|
||||
await expect(panel.getByTestId("scheduled-condition-detail-scroll")).toContainText(summary.summary);
|
||||
await testInfo.attach("investigation-loaded", { body: await panel.screenshot(), contentType: "image/png" });
|
||||
|
||||
await panel.getByRole("button", { name: /预约任务/ }).click();
|
||||
await panel.getByText(appointment.title, { exact: true }).first().click();
|
||||
const detail = panel.getByTestId("scheduled-condition-detail-scroll");
|
||||
await expect(detail).toContainText("核对预约任务详情");
|
||||
await expect(detail).toContainText("凤阳维修组");
|
||||
await expect(detail).toContainText("凤阳核验点");
|
||||
await testInfo.attach("appointment-loaded", { body: await panel.screenshot(), contentType: "image/png" });
|
||||
});
|
||||
Reference in New Issue
Block a user