import { expect, test } from "@playwright/test"; import { expandSimulationConsole, prepareApp, resultSnapshot, wideProject } from "./fixtures"; test.beforeEach(async ({ page }) => { await page.route("**/api/simulation/runtime-check", route => route.fulfill({ json: { checkId: "test-runtime", status: "completed", stage: "complete", message: "仿真环境自检通过", durationMs: 1, error: null, failure: null, } })); }); for (const diagnosticsMode of ["native", "legacy-native", "python"] as const) { test(`completed ${diagnosticsMode} results can be published and restored`, async ({ page }) => { await prepareApp(page); const diagnostics = diagnosticsMode === "python" ? resultSnapshot.result.diagnostics : { backend: "native-c", stateCount: 1, ...(diagnosticsMode === "native" ? { sampleCount: 3 } : {}) }; await page.route("**/api/system-xml/simulate-stream", route => route.fulfill({ contentType: "application/x-ndjson", body: JSON.stringify({ event: "result", progress: 100, phase: "completed", result: { ...resultSnapshot.result, diagnostics } }) + "\n", })); await page.goto("/"); await page.locator('input[type="file"]').setInputFiles({ name: "native-result.json", mimeType: "application/json", buffer: Buffer.from(JSON.stringify({ ...wideProject, edges: [...wideProject.edges, { id: "close-test-loop", source: "generic_sensor_4", target: "generic_sensor_1", sourceHandle: "port_b", targetHandle: "port_a", data: { isContactEdge: false }, }] })), }); await expect(page.getByRole("textbox", { name: "工程", exact: true })).toHaveValue("native-result"); await page.getByRole("button", { name: "运行仿真", exact: true }).click(); await expandSimulationConsole(page); const consolePanel = page.getByRole("complementary", { name: "仿真控制台", exact: true }); await expect(consolePanel).toContainText("仿真完成,已生成新的结果,共 3 个采样点"); await expect(consolePanel).not.toContainText("仿真失败"); if (diagnosticsMode === "python") { await expect(consolePanel).toContainText("最大方程残差 0"); } else { await expect(consolePanel).not.toContainText("最大方程残差"); } await expect.poll(() => page.evaluate(() => JSON.parse(sessionStorage.getItem("system-simulation-flow:latest-result") ?? "null")?.storage)).toBe("indexeddb"); const saved = await page.evaluate(async () => { // @ts-expect-error Vite serves the persistence module in the test browser. const { loadStoredResultSnapshot } = await import("/src/resultPersistence.ts"); return loadStoredResultSnapshot(); }); expect(saved.result.diagnostics.sampleCount).toBe(3); expect(saved.result.series).toEqual(resultSnapshot.result.series); await page.reload(); await page.getByRole("tab", { name: "结果", exact: true }).click(); await expect(page.getByText("3 个采样点", { exact: false }).first()).toBeVisible(); }); } for (const live of [true, false]) { test(`property temperature warning is shown once with live delivery ${live}`, async ({ page }) => { await prepareApp(page); const message = "氦气物性有效温度越界:状态方程及热力性质的真实气体修正项,t = 0.001 s,T = 1600 K > Tmax = 1500 K。仿真继续计算,超范围物性不保证有效性。"; const warning = { code: "helium-equation-of-state-high", message }; const events = [ ...(live ? [0, 1].map(() => ({ event: "progress", progress: 1, phase: "property-warning", message, simulatedTime: .001, totalTime: 1 })) : []), { event: "result", progress: 100, phase: "completed", result: { ...resultSnapshot.result, diagnostics: { backend: "native-c", stateCount: 1, sampleCount: 3, propertyWarnings: [warning] }, } }, ]; await page.route("**/api/system-xml/simulate-stream", route => route.fulfill({ contentType: "application/x-ndjson", body: events.map(e => JSON.stringify(e)).join("\n") + "\n", })); await page.goto("/"); await page.locator('input[type="file"]').setInputFiles({ name: "property-warning.json", mimeType: "application/json", buffer: Buffer.from(JSON.stringify({ ...wideProject, edges: [...wideProject.edges, { id: "close-test-loop", source: "generic_sensor_4", target: "generic_sensor_1", sourceHandle: "port_b", targetHandle: "port_a", data: { isContactEdge: false }, }] })), }); await expect(page.getByRole("textbox", { name: "工程", exact: true })).toHaveValue("property-warning"); await page.getByRole("button", { name: "运行仿真", exact: true }).click(); await expandSimulationConsole(page); const panel = page.getByRole("complementary", { name: "仿真控制台", exact: true }); await expect(panel.getByText(message, { exact: true })).toHaveCount(1); await expect(panel).toContainText("仿真完成,已生成新的结果,共 3 个采样点"); await expect(panel).not.toContainText("仿真失败"); await expect.poll(() => page.evaluate(async () => { // @ts-expect-error Vite serves the persistence module in the test browser. const { loadStoredResultSnapshot } = await import("/src/resultPersistence.ts"); return (await loadStoredResultSnapshot())?.result.diagnostics.propertyWarnings; })).toEqual([warning]); }); }