import { expect, test } from "@playwright/test"; import { readRenderedContrast } from "./support/theme-colors"; for (const width of [1280, 375, 320]) { test(`SCADA 调查通知切换状态时保持高度与下方布局 ${width}`, async ({ page }, testInfo) => { await page.setViewportSize({ width, height: 900 }); await page.route("**/scada-notice-preview", (route) => route.fulfill({ contentType: "text/html", body: '
' })); await page.goto("/scada-notice-preview"); await page.evaluate(async () => { const refresh = await import("/@react-refresh"); refresh.injectIntoGlobalHook(window); Object.assign(window, { $RefreshReg$: () => {}, $RefreshSig$: () => (type: unknown) => type }); 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 module paths unavailable"); const reactModule = await import(reactUrl); const React = reactModule.default ?? reactModule; const clientModule = await import(clientUrl); const { createRoot } = clientModule.default ?? clientModule; const { ScadaMonitoringNotice } = await import("/src/features/workbench/peripheral-sample/scada-monitoring-notice.tsx"); const { WorkbenchSection } = await import("/src/features/workbench/components/workbench-panel-ui.tsx"); const result = { monitoring_id: "monitoring-1", period_end: "2026-07-16T00:00:00Z", status: "attention", task_id: "task-1", incident: { action: "raised" } }; const states = [ { result: null, processing: false }, { result: null, processing: true }, { result: { ...result, status: "normal", task_id: null, incident: null }, processing: false }, { result, processing: false, animationId: "incident-1" }, { result: { ...result, status: "suspected_burst" }, processing: true, animationId: "incident-1" }, { result: { ...result, incident: { action: "ongoing" } }, processing: false, animationId: "incident-1" }, { result: { ...result, status: "normal", incident: { action: "resolved" } }, processing: false }, { result: { ...result, status: "insufficient_data", task_id: null, incident: null }, processing: false }, { result: null, processing: false } ]; const root = createRoot(document.getElementById("notice-reader")); const render = (index: number) => root.render(React.createElement(WorkbenchSection, { title: "SCADA 数据诊断", bodyClassName: "space-y-3" }, React.createElement(ScadaMonitoringNotice, { animationId: null, ...states[index], onOpenInvestigation: (taskId: string) => { document.body.dataset.openedTask = taskId; } }), React.createElement("div", { "data-testid": "following-controls" }, "演示开始时间 / 调频时间轴"))); Object.assign(window, { setNoticeState: render }); render(0); }); const notice = page.getByRole("status", { name: "最新监测结果" }); await expect(notice).toBeVisible(); await page.evaluate(() => document.fonts.ready); const initial = (await page.getByTestId("following-controls").boundingBox())!; const readSlots = () => notice.locator("[data-slot^=scada-notice-]").evaluateAll((elements) => elements.map((element) => { const { x, y, width, height } = element.getBoundingClientRect(); return { slot: element.getAttribute("data-slot"), x, y, width, height }; })); const initialSlots = await readSlots(); const messages = ["监测待机", "正在监测", "监测正常", "发现指标异常", "发现疑似爆管", "异常持续跟踪", "异常已恢复", "监测数据不足", "监测待机"]; const tones = ["neutral", "info", "success", "warning", "danger", "warning", "success", "neutral", "neutral"]; for (let index = 0; index < messages.length; index++) { await page.evaluate((state) => (window as unknown as { setNoticeState: (index: number) => void }).setNoticeState(state), index); await expect(notice).toContainText(messages[index]); await expect(notice).toHaveAttribute("data-status-tone", tones[index]); expect((await notice.boundingBox())!.height).toBe(160); expect((await page.getByTestId("following-controls").boundingBox())!.y).toBe(initial.y); expect(await readSlots()).toEqual(initialSlots); expect(await notice.evaluate((element) => element.scrollWidth <= element.clientWidth && element.scrollHeight <= element.clientHeight)).toBe(true); expect(await readRenderedContrast(notice.locator("[data-slot=scada-notice-summary] p").last())).toBeGreaterThanOrEqual(4.5); if (index < 3 || index === 5) { await expect(notice.getByRole("button", { name: "查看调查" })).toHaveCount(index === 5 ? 1 : 0); await testInfo.attach(`notice-${width}-${index}`, { body: await notice.screenshot({ path: testInfo.outputPath(`notice-${index}.png`) }), contentType: "image/png" }); } if (index === 3) { await expect(notice).toHaveAttribute("data-animation-state", "running"); await notice.getByRole("button", { name: "查看调查" }).click(); await expect(page.locator("body")).toHaveAttribute("data-opened-task", "task-1"); await testInfo.attach(`notice-${width}`, { body: await notice.screenshot({ path: testInfo.outputPath("notice.png") }), contentType: "image/png" }); await expect(notice).toHaveAttribute("data-animation-state", "idle"); expect((await notice.boundingBox())!.height).toBe(160); } } await page.emulateMedia({ reducedMotion: "reduce" }); await page.evaluate(() => (window as unknown as { setNoticeState: (index: number) => void }).setNoticeState(3)); await expect(notice).toContainText("发现指标异常"); await expect(notice).toHaveAttribute("data-animation-state", "idle"); expect((await notice.boundingBox())!.height).toBe(160); expect((await page.getByTestId("following-controls").boundingBox())!.y).toBe(initial.y); }); }