import { expect, test } from "@playwright/test"; import { investigationFixture, mockInvestigationPresentation, selectInvestigation, showInvestigationMap, showInvestigationTasks } from "./support/mock-investigation-presentation"; import { responsesFixture } from "./support/responses-fixture"; test.use({ reducedMotion: "reduce" }); const chart = (id: string) => ({ action: "open_chart", chart_id: id, evidence_refs: ["synthetic:pressure"], chart: { title: `停靠监测 ${id}`, chart_type: "line", x_data: ["07:45", "08:00"], series: [{ name: "压力(m)", data: [32, 28] }] } }); test("chart manager occupies the right workspace and preserves charts when switching to tasks", async ({ page }, testInfo) => { await page.setViewportSize({ width: 1920, height: 1000 }); const task = investigationFixture(1, "右侧图表工作区验收"); const mock = await mockInvestigationPresentation(page, [task]); await selectInvestigation(page, task.title); await page.getByRole("button", { name: /展开 Agent 助手面板/ }).click(); const presentation = page.getByLabel("调查实时展示", { exact: true }); await expect(presentation).toContainText("实时跟随"); await mock.emit(task, chart("P1")); const manager = page.getByRole("dialog", { name: "图表管理", exact: true }); await expect(manager).toBeVisible(); await expect(manager).toHaveAttribute("data-window-presentation", "docked"); await expect(page.getByRole("button", { name: /窗口管理,当前/ })).toHaveCount(0); await expect(manager.getByRole("button", { name: /最大化窗口|还原窗口/ })).toHaveCount(0); await expect(manager.locator("[data-window-resize-handle]")).toHaveCount(0); await expect(page.getByRole("region", { name: "工况任务", exact: true })).toBeHidden(); const box = (await manager.boundingBox())!; const map = (await page.locator("#workspace-map").boundingBox())!; expect(box.y).toBe(56); expect(box.x).toBeGreaterThanOrEqual(map.x + map.width); expect(Math.round(box.x + box.width)).toBe(1920); await expect(manager.getByRole("img", { name: "停靠监测 P1", exact: true })).toBeVisible(); const separator = page.getByRole("separator", { name: "调整地图与报告宽度" }); await separator.focus(); await page.keyboard.press("End"); await expect.poll(async () => Math.round((await manager.boundingBox())!.width)).toBe(600); await page.screenshot({ path: testInfo.outputPath("chart-workspace-minimum.png") }); const instance = await manager.locator(".echarts-for-react").getAttribute("_echarts_instance_"); await page.getByRole("button", { name: "工况任务", exact: true }).click(); await expect(manager).toBeHidden(); await expect(page.getByRole("region", { name: "工况任务", exact: true })).toBeVisible(); await showInvestigationMap(page); await presentation.getByRole("button", { name: "打开图表管理", exact: true }).press("Enter"); await expect(manager).toBeVisible(); await expect(manager.getByLabel("图表管理标题栏", { exact: true })).toBeFocused(); await expect(manager.locator(".echarts-for-react")).toHaveAttribute("_echarts_instance_", instance!); for (const width of [1200, 1024, 390, 320]) { await page.setViewportSize({ width, height: 800 }); await expect(page.locator("#main-workspace")).toHaveAttribute("data-layout-mode", "focus"); const bounds = (await manager.boundingBox())!; expect(bounds.x + bounds.width).toBeLessThanOrEqual(width); expect(await manager.evaluate((node) => node.scrollWidth - node.clientWidth)).toBeLessThanOrEqual(1); await page.screenshot({ path: testInfo.outputPath(`chart-workspace-${width}.png`) }); } await page.setViewportSize({ width: 1920, height: 1000 }); await manager.getByRole("button", { name: "关闭窗口", exact: true }).click(); await expect(manager).toHaveCount(0); await expect(page.locator("#workspace-map")).toBeVisible(); await showInvestigationTasks(page); await expect(page.getByRole("region", { name: "工况任务", exact: true })).toBeVisible(); expect(mock.mutations).toEqual([]); }); test("multiple chart sources share the visible dock without resetting their charts", async ({ page }) => { await page.setViewportSize({ width: 1920, height: 1000 }); const task = investigationFixture(1, "多来源停靠验收"); const mock = await mockInvestigationPresentation(page, [task]); await selectInvestigation(page, task.title); await mock.emit(task, chart("P1")); const first = page.getByRole("dialog", { name: "图表管理", exact: true }).filter({ hasText: task.title }); await expect(first).toBeVisible(); await expect(first.locator(".echarts-for-react svg")).toBeVisible(); const instance = await first.locator(".echarts-for-react").getAttribute("_echarts_instance_"); await page.getByRole("button", { name: "切换地图 Dev Panel" }).click(); const tools = page.getByTestId("investigation-dev-tools"); await tools.getByLabel("调查展示 JSONL", { exact: true }).fill(JSON.stringify({ record_type: "presentation", command: chart("preview") })); await expect(tools.getByRole("combobox", { name: "JSONL 测试案例", exact: true })).toBeEnabled(); await tools.getByRole("button", { name: "执行本地预览", exact: true }).click(); await expect(tools.getByRole("status")).toContainText("本地预览完成"); await page.getByRole("button", { name: "切换地图 Dev Panel" }).click(); await page.getByLabel("本地预览展示", { exact: true }).getByRole("button", { name: "打开图表管理", exact: true }).press("Enter"); const second = page.getByRole("dialog", { name: "图表管理", exact: true }).filter({ hasText: "本地预览展示" }); await expect(second).toBeVisible(); expect((await second.boundingBox())!.y).toBe(56); await expect(first).toBeHidden(); await page.getByLabel("调查实时展示", { exact: true }).getByRole("button", { name: "打开图表管理", exact: true }).press("Enter"); await expect(first).toBeVisible(); expect((await first.boundingBox())!.y).toBe(56); await expect(second).toBeHidden(); await expect(first.locator(".echarts-for-react")).toHaveAttribute("_echarts_instance_", instance!); await expect(page.getByRole("button", { name: /窗口管理,当前/ })).toHaveCount(0); }); test("Agent map location reveals the map while the chart workspace is focused", async ({ page }) => { await page.setViewportSize({ width: 1200, height: 900 }); const task = investigationFixture(1, "图表专注地图定位验收"); const mock = await mockInvestigationPresentation(page, [task]); const block = { version: "answer-ui@1", block_id: "dock-location", fallback_text: "合成地图定位", spec: { root: "location", elements: { location: { type: "MapLocation", props: { label: "定位合成监测点", layer: "junctions", feature_ids: ["P1"], source: "浏览器验收" }, children: [] } } } }; await page.route("**/api/v1/responses", (route) => route.request().method() === "OPTIONS" ? route.fallback() : route.fulfill({ headers: { "Access-Control-Allow-Origin": "*", "Content-Type": "text/event-stream" }, body: responsesFixture([ { type: "start", messageId: "dock-location-answer" }, { type: "data-answer_ui", id: block.block_id, data: block }, { type: "data-final_answer", data: { content: "合成地图定位", ui_block_ids: [block.block_id] } }, { type: "finish", finishReason: "stop" } ]) })); await selectInvestigation(page, task.title); await mock.emit(task, chart("P1")); await expect(page.getByRole("dialog", { name: "图表管理", exact: true })).toBeVisible(); await page.getByRole("button", { name: /展开 Agent 助手面板/ }).click(); const agent = page.getByRole("complementary", { name: "Agent 命令面板" }); await agent.locator(".agent-panel-prompt-textarea").fill("定位合成监测点"); await agent.getByRole("button", { name: "发送 Agent 指令", exact: true }).click(); await expect(page.locator("#workspace-map")).toBeHidden(); await agent.getByRole("button", { name: "定位合成监测点", exact: true }).click(); await expect(page.locator("#workspace-map")).toBeVisible(); await expect(page.locator("#main-workspace")).toHaveAttribute("data-layout-mode", "map_only"); await expect(page.getByRole("button", { name: "返回图表管理", exact: true })).toBeVisible(); });