import { expect, test } from "@playwright/test"; test("renders the migrated WebGIS workbench shell", async ({ page }) => { const riveRequests: string[] = []; page.on("request", (request) => { if (/\.riv(?:\?|$)/.test(request.url())) { riveRequests.push(request.url()); } }); await page.goto("/"); await expect(page.getByText("供水管网智能调度系统")).toBeVisible(); await expect(page.getByText("调度工作台")).toBeVisible(); await expect(page.getByLabel("推荐问题")).toBeVisible(); const runtimeConfig = await page.evaluate(() => globalThis.__TJWATER_CONFIG__); expect(runtimeConfig).toMatchObject({ TJWATER_MAP_URL: expect.any(String), TJWATER_GEOSERVER_WORKSPACE: expect.any(String), TJWATER_AGENT_API_BASE_URL: expect.any(String) }); expect(Object.keys(runtimeConfig as Record)).not.toContainEqual( expect.stringMatching(/^(NEXT_PUBLIC_|VITE_)/) ); expect(runtimeConfig).not.toHaveProperty("TJWATER_TTS_API_URL"); expect(runtimeConfig).not.toHaveProperty("EDGE_TTS_VOICE"); const mapAsset = await page.request.get("/map/valve.png"); expect(mapAsset.ok()).toBe(true); expect(mapAsset.headers()["content-type"]).toBe("image/png"); await expect(page.getByLabel("Agent 状态").first()).toBeVisible(); await expect.poll(() => riveRequests.length, { timeout: 25_000 }).toBe(1); }); test("animates the compact header menu without overflowing", async ({ page }) => { await page.emulateMedia({ reducedMotion: "no-preference" }); await page.setViewportSize({ width: 375, height: 812 }); await page.goto("/"); await page.locator('button[aria-label^="查看异常处置面板"]:visible').click(); const menu = page.locator('[role="menu"][data-state="open"]'); await expect(menu).toBeVisible(); const animation = await menu.evaluate((element) => { const style = window.getComputedStyle(element); return { duration: Number.parseFloat(style.animationDuration) * 1_000, name: style.animationName }; }); expect(animation.name).toContain("enter"); expect(animation.duration).toBeGreaterThan(0); const menuBounds = await menu.boundingBox(); expect(menuBounds).not.toBeNull(); expect(menuBounds!.x).toBeGreaterThanOrEqual(0); expect(menuBounds!.x + menuBounds!.width).toBeLessThanOrEqual(375); }); test("renders map notices through a single toaster", async ({ page }) => { await page.goto("/"); await expect(page.locator("[data-sonner-toaster]")).toHaveCount(1); await page.getByLabel("打开用户菜单").click(); await page.getByRole("menuitem", { name: /查看运行状态/ }).click(); await expect(page.locator("[data-sonner-toast]")).toHaveCount(1); }); test("preserves compact typography in header and agent controls", async ({ page }) => { await page.setViewportSize({ width: 1440, height: 900 }); await page.goto("/"); const headerControl = page.locator("header.acrylic-navigation button.font-semibold:visible").first(); const approvalControl = page.getByRole("button", { name: "权限批准模式" }); const suggestion = page.locator("[aria-label=推荐问题] button").first(); await expect(headerControl).toHaveCSS("font-weight", "600"); await expect(approvalControl).toHaveCSS("font-size", "12px"); await expect(approvalControl).toHaveCSS("line-height", "16px"); await expect(suggestion).toHaveCSS("font-size", "12px"); await expect(suggestion).toHaveCSS("font-weight", "500"); }); test("lets interactive utilities override surface materials", async ({ page }) => { await page.goto("/"); await page.addStyleTag({ content: "*,*::before,*::after{transition:none!important}" }); const suggestion = page.locator("[aria-label=推荐问题] button").first(); const restingBackground = await suggestion.evaluate( (element) => window.getComputedStyle(element).backgroundColor ); await suggestion.hover(); const hoverBackground = await suggestion.evaluate( (element) => window.getComputedStyle(element).backgroundColor ); expect(hoverBackground).not.toBe(restingBackground); }); test("preserves v3 menu and panel styling through Tailwind v4", async ({ page }) => { await page.setViewportSize({ width: 1440, height: 900 }); await page.goto("/"); await page.getByLabel("打开用户菜单").click(); const menu = page.locator('[role="menu"][data-state="open"]'); const menuTransformOrigin = await menu.evaluate( (element) => window.getComputedStyle(element).transformOrigin ); expect(menuTransformOrigin).not.toBe("50% 50%"); await page.keyboard.press("Escape"); const agentCommandControl = page.locator(".agent-panel-control.shadow-xs").first(); const commandShadow = await agentCommandControl.evaluate( (element) => window.getComputedStyle(element).boxShadow ); expect(commandShadow).toContain("rgba(0, 0, 0, 0.05) 0px 1px 2px 0px"); expect(commandShadow).not.toContain("0px 1px 3px 0px"); });