Files
next-tjwater-frontend/tests/browser/scada-comparison-chart.e2e.ts
T
jiang e0fe4a5a10
Generic Container CI/CD / test-build-publish (push) Successful in 1m12s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 1m11s
fix(charts): preserve comparison types and draggable window headings
Keep current lines and historical scatter points in a dedicated comparison chart type. Expose floating headings and use idempotent placement so StrictMode no longer masks production overlap.
2026-11-08 03:04:14 +08:00

124 lines
9.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test } from "@playwright/test";
import { mockAgentApi } from "./support/mock-agent-api";
import { mockWorkbenchContext } from "./support/mock-workbench-context";
import { responsesFixture } from "./support/responses-fixture";
test.use({ timezoneId: "UTC" });
const times = Array.from({ length: 13 }, (_, index) => `${String(9 + Math.floor(index / 4)).padStart(2, "0")}:${String(index % 4 * 15).padStart(2, "0")}`);
const block = {
version: "answer-ui@1", block_id: "scada-week", phase: "final", fallback_text: "合成 SCADA 七日对照",
spec: { root: "chart", elements: { chart: { type: "Chart", children: [], props: {
title: "压力与前七天同时刻对照(m)", chart_type: "time_comparison", y_axis_name: "压力(m)", x_axis_name: "时间",
x_data: times,
series: [{ name: "当日三小时", type: "line", data: [34, 34.2, 33.8, 34, 33.5, 33, 32.5, 32, 31, 30, 29, 27, 25],
sample_times: times.map((time) => new Date(`2026-06-14T${time}:00+08:00`).toISOString().replace(".000Z", "Z")) },
...Array.from({ length: 7 }, (_, index) => ({ name: `6月${13 - index}日`, type: "scatter",
data: [...Array(10).fill(null), 34 + index * 0.4, 34.3 + index * 0.4, 34.6 + index * 0.4],
sample_times: [...Array(10).fill(null), ...times.slice(10).map((time) => index % 2
? `2026-06-${String(13 - index).padStart(2, "0")}T${time}:00+08:00`
: new Date(`2026-06-${String(13 - index).padStart(2, "0")}T${time}:00+08:00`).toISOString().replace(".000Z", "Z"))] }))],
source: "浏览器合成样例,非现场监测数据"
} } } }
};
for (const width of [1440, 375, 320]) {
test(`SCADA comparison preserves seven daily point sets, timestamps and axis range at ${width}px`, async ({ page }, testInfo) => {
await page.setViewportSize({ width, height: 1000 });
await page.emulateMedia({ reducedMotion: "reduce" });
await mockWorkbenchContext(page, undefined, undefined, {}, [], { runtimeMode: "backend" });
await mockAgentApi(page);
await page.route("**/api/v1/responses", async (route) => {
if (route.request().method() === "OPTIONS") return route.fallback();
await route.fulfill({ headers: { "Access-Control-Allow-Origin": "*", "Content-Type": "text/event-stream" },
body: responsesFixture([
{ type: "start", messageId: "scada-week-answer" },
{ type: "data-answer_ui", id: block.block_id, data: block },
{ type: "data-final_answer", data: { content: "合成 SCADA 对照,待现场核验。", ui_block_ids: [block.block_id] } },
{ type: "finish", finishReason: "stop" }
]) });
});
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByRole("button", { name: width < 1024 ? "打开 Agent 面板" : /展开 Agent 助手面板/ }).click();
const panel = page.getByRole("complementary", { name: "Agent 命令面板" });
await panel.locator("textarea").fill("查看合成 SCADA 七日对照");
await panel.getByRole("button", { name: "发送 Agent 指令" }).click();
const ui = panel.locator(".answer-ui-chart");
await expect(ui).toBeVisible();
await expect(ui.locator("svg text").filter({ hasText: /^时间$/ })).toBeVisible();
await expect(ui.getByRole("tab", { name: "复合", exact: true })).toBeVisible();
await expect(ui.getByLabel("显示的数据序列").getByRole("button")).toHaveCount(8);
// Each historical day has exactly three unconnected SVG scatter symbols.
for (const color of ["#059669", "#d97706", "#7c3aed", "#0891b2", "#e11d48", "#475569", "#a16207"]) {
await expect(ui.locator(`svg path[fill="${color}"]`)).toHaveCount(3);
}
const axisValues = () => ui.locator("svg text").allTextContents().then((labels) => labels.filter((label) => /^-?\d+(\.\d+)?$/.test(label)).map(Number));
expect((await axisValues()).every((value) => value > 0)).toBe(true);
await page.evaluate(() => document.fonts.ready);
await testInfo.attach(`scada-week-${width}`, { body: await ui.screenshot({ path: testInfo.outputPath(`scada-week-${width}.png`) }), contentType: "image/png" });
await ui.locator('svg path[fill="#059669"]').last().hover({ position: { x: 4, y: 6 } });
await expect(ui).toContainText("采样时间 2026-06-13 12:00:00+08:00");
await page.evaluate(() => document.fonts.ready);
await testInfo.attach(`scada-week-tooltip-${width}`, { body: await ui.screenshot({ path: testInfo.outputPath(`scada-week-tooltip-${width}.png`) }), contentType: "image/png" });
const plot = ui.getByRole("group", { name: /按回车查看数据点/ });
await plot.focus();
await page.keyboard.press("End");
const details = ui.getByRole("region", { name: "数据点详情" });
await expect(details).toContainText("2026-06-14 12:00:00+08:00");
await expect(details).toContainText("2026-06-13 12:00:00+08:00");
await page.keyboard.press("Home");
await expect(details).toContainText("缺测");
await ui.getByRole("button", { name: "关闭数据点详情" }).click();
await ui.getByRole("tab", { name: "柱状", exact: true }).click();
expect(await axisValues()).toContain(0);
await ui.getByRole("tab", { name: "数据", exact: true }).click();
await expect(ui).toContainText("缺测");
await expect(ui).toContainText("2026-06-13 12:00:00+08:00");
expect(await ui.evaluate((element) => element.scrollWidth - element.clientWidth)).toBeLessThanOrEqual(1);
// Use the product buttons to inspect both the floating and maximized layouts.
await page.setViewportSize({ width, height: width < 640 ? 640 : 1000 });
const search = ui.getByRole("textbox", { name: /搜索压力与前七天/ });
await search.fill("2026-06-13");
const expand = ui.getByRole("button", { name: "放大查看 压力与前七天同时刻对照(m)", exact: true });
await expand.click();
const floating = page.getByRole("dialog", { name: "压力与前七天同时刻对照(m)", exact: true });
await expect(floating.getByRole("tab", { name: "数据", exact: true })).toHaveAttribute("aria-selected", "true");
await expect(floating.getByRole("textbox", { name: /搜索压力与前七天/ })).toHaveValue("2026-06-13");
await floating.getByRole("tab", { name: "复合", exact: true }).click();
const drawing = floating.getByRole("img", { name: "压力与前七天同时刻对照(m)", exact: true });
const instance = await drawing.locator(".echarts-for-react").getAttribute("_echarts_instance_");
const restored = (await floating.boundingBox())!;
await floating.getByRole("button", { name: "最大化窗口", exact: true }).click();
await expect.poll(async () => (await floating.boundingBox())!.width).toBe(width - 16);
await expect.poll(async () => (await floating.boundingBox())!.height).toBe((width < 640 ? 640 : 1000) - 16);
await expect.poll(async () => Math.abs(Number(await drawing.locator("svg").getAttribute("width")) - (await drawing.boundingBox())!.width)).toBeLessThan(1);
await expect.poll(async () => Math.abs(Number(await drawing.locator("svg").getAttribute("height")) - (await drawing.boundingBox())!.height)).toBeLessThan(1);
await expect(drawing.locator(".echarts-for-react")).toHaveAttribute("_echarts_instance_", instance!);
const content = floating.locator("[data-floating-window-content]");
expect(await content.evaluate((element) => element.scrollWidth - element.clientWidth)).toBeLessThanOrEqual(1);
const plotBox = (await drawing.boundingBox())!;
const sidebar = (await floating.locator("aside").boundingBox())!;
if (width < 640) expect(sidebar.y).toBeGreaterThanOrEqual(plotBox.y + plotBox.height);
else expect(sidebar.x).toBeGreaterThanOrEqual(plotBox.x + plotBox.width);
expect(plotBox.height).toBeGreaterThanOrEqual(220);
await floating.getByLabel("显示的数据序列").getByRole("button", { name: "6月12日", exact: true }).click();
await expect(ui.getByLabel("显示的数据序列").getByRole("button", { name: "6月12日", exact: true })).toHaveAttribute("aria-pressed", "false");
await floating.getByLabel("显示的数据序列").getByRole("button", { name: "6月12日", exact: true }).click();
await floating.locator('svg path[fill="#059669"]').last().hover({ position: { x: 4, y: 6 } });
await expect(floating).toContainText("采样时间 2026-06-13 12:00:00+08:00");
await floating.locator(".floating-window-heading").hover();
await page.evaluate(() => document.fonts.ready);
await testInfo.attach(`scada-week-fullscreen-${width}`, { body: await floating.screenshot({ path: testInfo.outputPath(`scada-week-fullscreen-${width}.png`) }), contentType: "image/png" });
await floating.getByRole("button", { name: "还原窗口", exact: true }).click();
await expect.poll(async () => (await floating.boundingBox())!.width).toBe(restored.width);
await expect.poll(async () => (await floating.boundingBox())!.height).toBe(restored.height);
await floating.getByRole("tab", { name: "数据", exact: true }).click();
await expect(floating.getByRole("textbox", { name: /搜索压力与前七天/ })).toHaveValue("2026-06-13");
await floating.getByRole("button", { name: "关闭窗口", exact: true }).click();
await expect(floating).toHaveCount(0);
await expect(expand).toBeFocused();
await expect(search).toHaveValue("2026-06-13");
});
}