import { expect, test } from "@playwright/test"; import { mockWorkbenchContext } from "./support/mock-workbench-context"; import { createAnalysisRuntimeSnapshot, MOCK_SPATIAL_ANALYSIS } from "./support/mock-analysis-runtime"; test.beforeEach(async ({ page }) => { await page.emulateMedia({ reducedMotion: "reduce" }); await mockWorkbenchContext(page, createAnalysisRuntimeSnapshot(MOCK_SPATIAL_ANALYSIS)); }); test("docks the live task panel into analysis, enforces both minimum widths and restores the analysis", async ({ page }) => { await page.setViewportSize({ width: 1920, height: 1000 }); const errors: string[] = []; page.on("pageerror", (error) => errors.push(error.message)); await page.goto("/", { waitUntil: "domcontentloaded" }); await page.getByRole("button", { name: "打开最新后端分析成果" }).click(); await expect(page.locator("#artifact-workspace")).toBeVisible(); await page.getByRole("button", { name: "工况任务", exact: true }).click(); const panel = page.getByRole("region", { name: "工况任务", exact: true }); await expect(panel.getByRole("button", { name: /停靠工况任务/ })).toHaveCount(0); await expect(panel.locator("[data-condition-dock-toggle]")).toHaveCount(1); await expect(panel.getByRole("button", { name: "展开工况任务" }).locator(".lucide-maximize2")).toBeVisible(); await expect(panel.locator('button[data-condition-id][aria-pressed="true"]')).toHaveCount(0); await panel.getByRole("button", { name: "展开工况任务" }).click(); await expect(panel).toHaveAttribute("data-presentation", "workspace"); await expect(panel.getByRole("button", { name: "收起工况任务" }).locator(".lucide-minimize2")).toBeVisible(); await expect(panel.getByText("请选择工况任务", { exact: true })).toBeVisible(); const rows = panel.getByTestId("scheduled-condition-timeline").locator("button[aria-pressed]"); await rows.nth(1).click(); const selectedId = await rows.nth(1).getAttribute("data-condition-id"); await panel.evaluate((element) => Object.assign(window, { originalDockPanel: element })); await expect(page.locator("#condition-workspace").getByRole("region", { name: "工况任务", exact: true })).toBeVisible(); await expect(page.locator("#artifact-workspace")).toBeHidden(); await expect(panel).toHaveAttribute("data-presentation", "workspace"); await expect(panel.locator(`[data-condition-id="${selectedId}"]`)).toHaveAttribute("aria-pressed", "true"); await expect(panel).toHaveCSS("backdrop-filter", "none"); const separator = page.getByRole("separator", { name: "调整地图与报告宽度" }); await expect(separator).toBeVisible(); await separator.focus(); await page.keyboard.press("Home"); await expect.poll(async () => Math.round((await page.locator("#workspace-map").boundingBox())!.width)).toBe(600); await page.keyboard.press("End"); await expect.poll(async () => Math.round((await panel.boundingBox())!.width)).toBe(880); const bounds = await panel.boundingBox(); expect(bounds!.y).toBe(56); expect(Math.round(bounds!.height)).toBe(944); const detail = panel.getByTestId("scheduled-condition-detail-scroll"); expect(await detail.evaluate((element) => element.scrollWidth - element.clientWidth)).toBeLessThanOrEqual(1); const timeline = page.getByRole("region", { name: "运行时间轴", exact: true }); const timelineBox = (await timeline.boundingBox())!; expect(timelineBox.x + timelineBox.width).toBeLessThanOrEqual(bounds!.x); await page.screenshot({ path: "test-results/condition-dock-minimum-width.png" }); await page.setViewportSize({ width: 1480, height: 900 }); await expect(page.locator("#main-workspace")).toHaveAttribute("data-layout-mode", "focus"); await expect(panel).toHaveCSS("width", "1480px"); await page.setViewportSize({ width: 1481, height: 900 }); await expect(separator).toBeVisible(); await expect.poll(async () => Math.round((await page.locator("#workspace-map").boundingBox())!.width)).toBe(600); await expect(panel).toHaveCSS("width", "880px"); await panel.getByRole("button", { name: "收起工况任务" }).click(); await expect(panel).toHaveAttribute("data-presentation", "desktop-floating"); await expect(page.locator("#artifact-workspace")).toBeVisible(); expect(await panel.evaluate((element) => element === (window as unknown as { originalDockPanel: Element }).originalDockPanel)).toBe(true); await expect(panel.locator(`[data-condition-id="${selectedId}"]`)).toHaveAttribute("aria-pressed", "false"); await panel.getByRole("button", { name: "展开工况任务" }).click(); await expect(panel.locator(`[data-condition-id="${selectedId}"]`)).toHaveAttribute("aria-pressed", "true"); expect(errors).toEqual([]); }); test("opens and reopens without selecting a task, and selecting a row docks its detail", async ({ page }) => { await page.setViewportSize({ width: 1920, height: 1000 }); await page.goto("/", { waitUntil: "domcontentloaded" }); const toggle = page.getByRole("button", { name: "工况任务", exact: true }); const panel = page.getByRole("region", { name: "工况任务", exact: true }); await toggle.click(); await expect(panel.locator('button[data-condition-id][aria-pressed="true"]')).toHaveCount(0); await panel.getByTestId("scheduled-condition-timeline").locator("button[data-condition-id]").nth(1).click(); await expect(panel).toHaveAttribute("data-presentation", "workspace"); await expect(panel.locator('button[data-condition-id][aria-pressed="true"]')).toHaveCount(1); await expect(panel.getByTestId("scheduled-condition-detail-scroll")).toBeVisible(); await toggle.click(); await expect(panel).toBeHidden(); await toggle.click(); await expect(panel.locator('button[data-condition-id][aria-pressed="true"]')).toHaveCount(0); await panel.getByRole("button", { name: "展开工况任务" }).click(); await expect(panel.getByText("请选择工况任务", { exact: true })).toBeVisible(); await page.screenshot({ path: "test-results/condition-dock-no-selection.png" }); }); test("uses focus mode when space is limited and adapts through Agent and mobile layouts", async ({ page }) => { await page.setViewportSize({ width: 1440, height: 900 }); await page.goto("/", { waitUntil: "domcontentloaded" }); await page.getByRole("button", { name: /展开 Agent 助手面板/ }).click(); await page.getByRole("button", { name: "工况任务", exact: true }).click(); const panel = page.getByRole("region", { name: "工况任务", exact: true }); await panel.getByRole("button", { name: "展开工况任务", exact: true }).click(); await expect(page.locator("#main-workspace")).toHaveAttribute("data-layout-mode", "focus"); await expect.poll(async () => (await panel.boundingBox())!.width).toBeGreaterThanOrEqual(880); await page.setViewportSize({ width: 1024, height: 768 }); await expect(page.getByRole("complementary", { name: "Agent 命令面板" })).toBeHidden(); await expect(panel).toHaveCSS("width", "1024px"); await expect(page.getByRole("separator", { name: "调整地图与报告宽度" })).toBeHidden(); await page.getByRole("button", { name: "显示地图", exact: true }).click(); await expect(panel).toBeHidden(); await expect(page.locator("#workspace-map")).toBeVisible(); await page.getByRole("button", { name: "返回工况任务" }).click(); await expect(panel).toBeVisible(); const rail = (await page.getByRole("complementary", { name: "Agent 折叠栏" }).boundingBox())!; const title = (await panel.getByRole("heading", { name: "工况任务", exact: true }).boundingBox())!; expect(title.x).toBeGreaterThanOrEqual(rail.x + rail.width); await page.screenshot({ path: "test-results/condition-dock-narrow-desktop.png" }); await page.setViewportSize({ width: 390, height: 844 }); await expect(panel).toBeHidden(); await page.getByRole("button", { name: "打开工况任务", exact: true }).click(); await expect(panel).toHaveAttribute("data-presentation", "mobile-sheet"); await expect(panel.locator('button[data-condition-id][aria-pressed="true"]')).toHaveCount(0); await panel.getByTestId("scheduled-condition-timeline").locator("button[data-condition-id]").first().click(); await expect(panel.getByTestId("scheduled-condition-detail-scroll")).toBeVisible(); await expect(panel.getByRole("button", { name: "收起工况任务" })).toBeVisible(); await expect(panel.getByRole("button", { name: /停靠工况任务/ })).toHaveCount(0); await page.setViewportSize({ width: 1920, height: 1000 }); await expect(panel).toHaveAttribute("data-presentation", "workspace"); expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBe(1920); });