100 lines
7.1 KiB
TypeScript
100 lines
7.1 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { mockAgentApi } from "./support/mock-agent-api";
|
|
import { mockWorkbenchContext } from "./support/mock-workbench-context";
|
|
import { investigationFixture, mockInvestigationPresentation } from "./support/mock-investigation-presentation";
|
|
import type { OperationalTaskNotification } from "../../src/features/workbench/api/operational-task-client";
|
|
|
|
for (const width of [1440, 375]) test(`task question keyboard submission and retry at ${width}px`, async ({ page }) => {
|
|
await page.setViewportSize({ width, height: 900 });
|
|
await mockWorkbenchContext(page);
|
|
await mockAgentApi(page);
|
|
await page.goto("/", { waitUntil: "domcontentloaded" });
|
|
await page.setContent('<!doctype html><html lang="zh-CN"><head><link rel="stylesheet" href="/src/styles.css"></head><body><main id="questions" style="max-width:680px;margin:auto;padding:16px"></main></body></html>');
|
|
await page.evaluate(async () => {
|
|
const entry = await (await fetch("/src/main.tsx")).text();
|
|
const reactUrl = entry.match(/from "([^"\n]*\/react\.js[^"\n]*)"/)?.[1];
|
|
const clientUrl = entry.match(/from "([^"\n]*\/react-dom_client\.js[^"\n]*)"/)?.[1];
|
|
if (!reactUrl || !clientUrl) throw new Error("Vite React paths unavailable");
|
|
const reactModule = await import(reactUrl);
|
|
const React = reactModule.default ?? reactModule;
|
|
const clientModule = await import(clientUrl);
|
|
const { createRoot } = clientModule.default ?? clientModule;
|
|
const { InvestigationQuestions } = await import("/src/features/workbench/components/investigation-questions.tsx");
|
|
const calls: unknown[][] = [];
|
|
Object.assign(window, { questionCalls: calls });
|
|
const question = { question_request_id: "q1", version: 1, execution_generation: 1, status: "pending", answers: [],
|
|
questions: [{ question_id: "flow", title: "是否有流量计记录", body: "已查询接入测点,需要补充事件时段的计量依据。",
|
|
options: [{ id: "unknown", label: "目前未知" }, { id: "yes", label: "有计量记录" }], mode: "single", allow_custom: true, required: true }] };
|
|
createRoot(document.getElementById("questions")).render(React.createElement(InvestigationQuestions, {
|
|
task: { questions: [question], execution_generation: 1, lifecycle_status: "waiting_human", active_run: null,
|
|
permissions: { can_answer_questions: true } },
|
|
onAnswer: async (...args: unknown[]) => {
|
|
calls.push(args);
|
|
if (calls.length === 1) throw new Error("网络暂时不可用,请重试");
|
|
}
|
|
}));
|
|
});
|
|
const submit = page.getByRole("button", { name: "提交回答并继续调查" });
|
|
await expect(submit).toBeDisabled();
|
|
await page.getByRole("radio", { name: "目前未知" }).focus();
|
|
await page.keyboard.press("Space");
|
|
await page.getByRole("textbox").fill("目前没有记录,请继续已有候选分析。");
|
|
await submit.focus(); await page.keyboard.press("Enter");
|
|
await expect(page.getByRole("alert")).toContainText("网络暂时不可用");
|
|
await expect(page.getByRole("textbox")).toHaveValue("目前没有记录,请继续已有候选分析。");
|
|
await submit.focus(); await page.keyboard.press("Enter");
|
|
await expect(page.getByText("回答已保存,调查已排队继续。")).toBeVisible();
|
|
const calls = await page.evaluate(() => (window as unknown as { questionCalls: unknown[][] }).questionCalls);
|
|
expect(calls).toHaveLength(2);
|
|
expect(calls[0]).toEqual(calls[1]);
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true);
|
|
});
|
|
|
|
test("task notification opens the question and submits through the scoped task API", async ({ page }) => {
|
|
const task = investigationFixture(11, "等待补充流量依据");
|
|
const run = task.active_run!;
|
|
task.active_run = null; task.latest_progress = null;
|
|
task.lifecycle_status = "waiting_human"; task.status = "waiting_human";
|
|
task.permissions.can_answer_questions = true;
|
|
task.questions = [{ question_request_id: "95000000-0000-4000-8000-000000000011", task_id: task.task_id,
|
|
run_id: run.run_id, source_session_id: "investigation-dev-test", execution_generation: 1, version: 1,
|
|
status: "pending", created_at: task.created_at, answered_at: null, answered_by: null, answers: [],
|
|
questions: [{ question_id: "flow", title: "是否有流量计记录", body: "需要补充事件时段的计量依据。",
|
|
options: [{ id: "unknown", label: "目前未知" }], mode: "single", allow_custom: true, required: true }] }];
|
|
const notification: OperationalTaskNotification = { notification_id: "96000000-0000-4000-8000-000000000011",
|
|
task_id: task.task_id, kind: "human_input_required", title: task.title, description: "是否有流量计记录",
|
|
lifecycle_status: "active", subject_type: "question", subject_id: task.questions[0].question_request_id,
|
|
resolved_at: null, resolution_reason: null, status: "unread", version: 1, required_permission: "operational_task.write",
|
|
created_at: task.created_at, read_at: null, read_by: null };
|
|
await mockInvestigationPresentation(page, [task], [], [notification]);
|
|
await page.route("**/operational-task-notifications/**/acknowledge", (route) => route.fulfill({ json: { ...notification,
|
|
status: "read", version: 2, read_at: task.created_at, read_by: "user" } }));
|
|
let submitted: unknown;
|
|
await page.route(`**/operational-tasks/${task.task_id}/questions/*/answer`, async (route) => {
|
|
submitted = route.request().postDataJSON();
|
|
task.questions![0] = { ...task.questions![0], status: "answered", version: 2, answered_by: "user",
|
|
answered_at: task.updated_at, answers: route.request().postDataJSON().answers };
|
|
task.execution_generation = 2; task.lifecycle_status = "open"; task.status = "queued"; task.revision += 1;
|
|
task.active_run = { ...run, generation: 2, status: "queued" };
|
|
await route.fulfill({ json: task });
|
|
});
|
|
await page.goto("/", { waitUntil: "domcontentloaded" });
|
|
await page.getByRole("button", { name: /查看待办与告警,当前 1 条/ }).first().click();
|
|
await page.getByText(task.title, { exact: true }).first().click();
|
|
const question = page.getByRole("region", { name: "调查提问" });
|
|
await expect(question).toBeVisible();
|
|
await expect(page.getByRole("region", { name: "工况任务", exact: true }).getByRole("region", { name: "调查提问" })).toBeVisible();
|
|
const chatWrites: string[] = [];
|
|
page.on("request", (request) => {
|
|
if (request.method() === "POST" && /127\.0\.0\.1:8787\/api\/v1\/(sessions|responses)/.test(request.url())) chatWrites.push(request.url());
|
|
});
|
|
await question.getByRole("radio", { name: "目前未知" }).check();
|
|
await question.getByRole("textbox").fill("尚无计量记录");
|
|
await question.getByRole("button", { name: "提交回答并继续调查" }).click();
|
|
await expect(question.getByText("目前未知;尚无计量记录")).toBeVisible();
|
|
expect(submitted).toMatchObject({ expected_version: 1, request_id: expect.any(String),
|
|
answers: [{ question_id: "flow", selected_option_ids: ["unknown"], custom_text: "尚无计量记录" }] });
|
|
await expect(question.getByRole("button")).toHaveCount(0);
|
|
expect(chatWrites).toEqual([]);
|
|
});
|