Keep investigation graphs stable during updates, defer expensive chart rendering, and prevent stale results when switching tasks. Adopt reference annotations and consolidate frontend documentation.
82 lines
5.4 KiB
TypeScript
82 lines
5.4 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { investigationFixture, mockInvestigationPresentation, selectInvestigation, type SavedPresentationEvent } from "./support/mock-investigation-presentation";
|
|
|
|
const first = investigationFixture(71, "切换性能调查甲");
|
|
const second = investigationFixture(72, "切换性能调查乙");
|
|
const events: SavedPresentationEvent[] = [first, second].flatMap((task, taskIndex) =>
|
|
Array.from({ length: 4 }, (_, index) => ({
|
|
task_id: task.task_id, run_id: task.active_run!.run_id, execution_generation: 1,
|
|
event_seq: 11 + taskIndex * 4 + index, occurred_at: "2026-11-10T00:00:00Z",
|
|
command: { action: "open_chart", chart_id: `${taskIndex}-${index}`, evidence_refs: ["synthetic:reading"],
|
|
chart: { title: `${taskIndex ? "乙" : "甲"}任务图表${index}`, chart_type: "line",
|
|
x_data: ["07:30", "07:45", "08:00"], series: [{ name: taskIndex ? "乙任务序列" : "甲任务序列", data: [30, 29, 25] }] } },
|
|
})));
|
|
|
|
test("shows the selected report and skeleton while history waits, without rebuilding the previous task's charts", async ({ page }, testInfo) => {
|
|
await mockInvestigationPresentation(page, [first, second], [...events]);
|
|
await selectInvestigation(page, first.title);
|
|
const panel = page.locator('[data-presentation-scope="investigation"]');
|
|
await expect(panel.getByRole("img", { name: "甲任务图表0", exact: true })).toBeVisible();
|
|
await page.evaluate(async () => {
|
|
const source = await (await fetch("/src/features/agent/answer-ui/responsive-chart.tsx")).text();
|
|
const url = source.match(/from "([^"\n]*echarts-for-react[^"\n]*)"/)?.[1];
|
|
if (!url) throw new Error("Vite chart module unavailable");
|
|
const { default: Chart } = await import(url);
|
|
const calls: string[] = [];
|
|
Object.assign(window, { taskSwitchChartInitializations: calls });
|
|
let prototype = Chart.prototype;
|
|
while (prototype && !Object.hasOwn(prototype, "initEchartsInstance")) prototype = Object.getPrototypeOf(prototype);
|
|
const original = prototype.initEchartsInstance;
|
|
prototype.initEchartsInstance = function (...args: unknown[]) {
|
|
calls.push(this.props.option.series[0].name);
|
|
return original.apply(this, args);
|
|
};
|
|
});
|
|
let release!: () => void;
|
|
const waiting = new Promise<void>((resolve) => { release = resolve; });
|
|
await page.route(`**/operational-tasks/${second.task_id}/presentation-events**`, async (route) => {
|
|
await waiting;
|
|
await route.fallback();
|
|
});
|
|
await page.getByRole("region", { name: "工况任务", exact: true }).getByText(second.title, { exact: true }).first().click();
|
|
await expect(page.locator('article[aria-label="调查任务报告"] h2')).toHaveText(second.title);
|
|
await expect(panel.getByRole("status", { name: "正在加载调查展示", exact: true })).toBeVisible();
|
|
await expect(panel.getByRole("img", { name: "甲任务图表0", exact: true })).toHaveCount(0);
|
|
expect(await page.evaluate(() => (window as unknown as { taskSwitchChartInitializations: string[] })
|
|
.taskSwitchChartInitializations.filter((name) => name === "甲任务序列"))).toEqual([]);
|
|
await panel.screenshot({ path: testInfo.outputPath("task-switch-loading-desktop.png") });
|
|
release();
|
|
await expect(panel.getByRole("img", { name: "乙任务图表0", exact: true })).toBeVisible();
|
|
await expect(panel.getByRole("status", { name: "正在加载调查展示", exact: true })).toHaveCount(0);
|
|
await expect(page.getByRole("dialog", { name: "图表管理", exact: true })).toHaveCount(0);
|
|
expect(await page.evaluate(() => (window as unknown as { taskSwitchChartInitializations: string[] })
|
|
.taskSwitchChartInitializations.filter((name) => name === "甲任务序列"))).toEqual([]);
|
|
});
|
|
|
|
test("keeps loading feedback readable on a narrow viewport and discards a late task response", async ({ page }, testInfo) => {
|
|
await page.setViewportSize({ width: 375, height: 800 });
|
|
await mockInvestigationPresentation(page, [first, second], [...events]);
|
|
await selectInvestigation(page, first.title);
|
|
let release!: () => void;
|
|
const waiting = new Promise<void>((resolve) => { release = resolve; });
|
|
await page.route(`**/operational-tasks/${second.task_id}/presentation-events**`, async (route) => {
|
|
await waiting;
|
|
await route.fallback();
|
|
});
|
|
// The map task selector remains available independently of the report reader.
|
|
const taskPanel = page.getByRole("region", { name: "工况任务", exact: true }).filter({ visible: true });
|
|
await taskPanel.getByRole("button", { name: "收起工况任务", exact: true }).click();
|
|
await taskPanel.getByText(second.title, { exact: true }).first().click();
|
|
await expect(page.locator('article[aria-label="调查任务报告"] h2').filter({ visible: true })).toHaveText(second.title);
|
|
const loading = page.getByRole("status", { name: "正在加载调查展示", exact: true });
|
|
await expect(loading).toBeVisible();
|
|
await taskPanel.getByRole("button", { name: "关闭工况任务", exact: true }).click();
|
|
await expect(loading).toBeVisible();
|
|
await page.screenshot({ path: testInfo.outputPath("task-switch-loading-mobile.png") });
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(375);
|
|
await selectInvestigation(page, first.title);
|
|
release();
|
|
await expect(page.locator('article[aria-label="调查任务报告"] h2').filter({ visible: true })).toHaveText(first.title);
|
|
await expect(page.getByRole("img", { name: "乙任务图表0", exact: true })).toHaveCount(0);
|
|
});
|