@@ -1,250 +1,132 @@
import { expect , test , type Page } from "@playwright/test" ;
import { mockAgentApi } from "./support/mock-agent-api" ;
test ( "temporary Agent analysis windows float abov e the persistent map workspace " , async ( { page } ) = > {
test ( "the default workspace docks Agent besid e the persistent map" , async ( { page } ) = > {
await page . setViewportSize ( { width : 1600 , height : 900 } ) ;
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
const frame = page . getByTestId ( "workbench-main-fram e" ) ;
const mapWindow = page . locator ( "#workspace-map" ) ;
const testButton = page . getByRole ( "button" , { name : "测试打开 Agent 多图表窗口" } ) . first ( ) ;
const workspace = page . locator ( "#main-workspac e" ) ;
const map = page . locator ( "#workspace-map" ) ;
await expect ( frame ) . toBeVisible ( ) ;
await expect ( mapWindow ) . toBeVisible ( ) ;
await expect ( testButton ) . toBeVisible ( ) ;
await expect ( page . getByLabel ( "工作台导航" ) ) . toHaveCount ( 0 ) ;
await expect ( workspace ) . toHaveAttribute ( "data-layout-mode" , "default" ) ;
await expect ( map ) . toBeVisible ( ) ;
await expect ( page . getByLabel ( "Agent 命令面板" ) ) . toBeVisible ( ) ;
await expect ( mapWindow . getByRole ( "navigation" , { name : "地图工具" } ) ) . toBeVisible ( ) ;
await expect ( page . locator ( ".workspace-window-titlebar" ) ) . toHaveCount ( 0 ) ;
await testButton . click ( ) ;
await expect ( page . getByRole ( "heading" , { name : "北辰分区压力异常诊断" , exact : true } ) ) . toBeVisible ( ) ;
await expect ( mapWindow ) . toBeVisible ( ) ;
await testButton . click ( ) ;
await expect ( page . getByRole ( "heading" , { name : "供水服务分区平衡分析" , exact : true } ) ) . toBeVisible ( ) ;
await expect ( page . getByText ( "2 / 6 个临时分析窗" ) ) . toBeVisible ( ) ;
await openWindowOperationMenu ( page , "供水服务分区平衡分析" ) ;
await page . getByRole ( "menuitem" , { name : "最小化" } ) . click ( ) ;
await expect ( page . getByRole ( "button" , { name : "恢复供水服务分区平衡分析" } ) ) . toBeVisible ( ) ;
await page . getByRole ( "button" , { name : "恢复供水服务分区平衡分析" } ) . click ( ) ;
await expect ( page . getByRole ( "heading" , { name : "供水服务分区平衡分析" , exact : true } ) ) . toBeVisible ( ) ;
await openWindowOperationMenu ( page , "供水服务分区平衡分析" ) ;
await page . getByRole ( "menuitem" , { name : "关闭并销毁" } ) . click ( ) ;
await openWindowOperationMenu ( page , "北辰分区压力异常诊断" ) ;
await page . getByRole ( "menuitem" , { name : "关闭并销毁" } ) . click ( ) ;
await expect ( mapWindow ) . toBeVisible ( ) ;
await expect ( page . getByRole ( "heading" , { name : "北辰分区压力异常诊断" , exact : true } ) ) . toHaveCount ( 0 ) ;
await expect ( page . getByText ( "0 / 6 个临时分析窗" ) ) . toBeVisible ( ) ;
await expect ( map . getByRole ( "navigation" , { name : "地图工具" } ) ) . toBeVisible ( ) ;
await expect ( page . getByRole ( "region" , { name : "工况任务" , exact : true } ) ) . toHaveCount ( 0 ) ;
await expect ( page . getByRole ( "button" , { name : "任务视图" } ) ) . toHaveCount ( 0 ) ;
} ) ;
test ( "the map document floats and minimizes to its taskbar entry " , async ( { page } ) = > {
test ( "a generated Artifact stays in peek until explicitly opened " , async ( { page } ) = > {
await page . setViewportSize ( { width : 1600 , height : 900 } ) ;
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
await page . getByRole ( "button" , { name : "生成 Agent 模拟分析成果" } ) . click ( ) ;
const peek = page . getByRole ( "complementary" , { name : "Agent 成果预览" } ) ;
await expect ( peek ) . toBeVisible ( ) ;
await expect ( peek ) . toContainText ( "北辰分区压力异常诊断" ) ;
await expect ( page . locator ( "#main-workspace" ) ) . toHaveAttribute ( "data-layout-mode" , "default" ) ;
await expect ( page . getByRole ( "heading" , { name : "北辰分区压力异常诊断" } ) ) . toHaveCount ( 0 ) ;
await peek . getByRole ( "button" , { name : "打开成果" } ) . click ( ) ;
await expect ( page . locator ( "#main-workspace" ) ) . toHaveAttribute ( "data-layout-mode" , "map_split" ) ;
await expect ( page . locator ( "#workspace-map" ) ) . toBeVisible ( ) ;
await expect ( page . locator ( "#artifact-workspace" ) ) . toBeVisible ( ) ;
await expect ( page . getByRole ( "heading" , { name : "北辰分区压力异常诊断" } ) ) . toBeVisible ( ) ;
await expect ( page . getByLabel ( "Agent 折叠栏" ) ) . toBeVisible ( ) ;
} ) ;
test ( "Agent expands over an active Artifact without resizing the main workspace" , async ( { page } ) = > {
await page . setViewportSize ( { width : 1600 , height : 900 } ) ;
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
await openFirstArtifact ( page ) ;
const workspace = page . locator ( "#main-workspace" ) ;
const mapWindow = page . locator ( "#workspace-map" ) ;
const dockedBox = await workspace . boundingBox ( ) ;
expect ( dockedBox ) . not . toBeNull ( ) ;
await openWindowOperationMenu ( page , "供水管网地图" ) ;
await page . getByRole ( "menuitem" , { name : "恢复为浮动窗口" } ) . click ( ) ;
const floatingBox = await mapWindow . boundingBox ( ) ;
expect ( floatingBox ) . not . toBeNull ( ) ;
expect ( floatingBox ! . width ) . toBeLessThan ( dockedBox ! . width ) ;
expect ( floatingBox ! . height ) . toBeLessThan ( dockedBox ! . height ) ;
await expect ( mapWindow ) . toHaveCSS ( "border-radius" , "0px" ) ;
const floatingClassName = await mapWindow . getAttribute ( "class" ) ;
expect ( floatingClassName ) . not . toContain ( "ring-1" ) ;
expect ( await mapWindow . evaluate ( ( element ) = > getComputedStyle ( element ) . boxShadow ) ) . not . toBe ( "none" ) ;
await expect ( page . getByRole ( "button" , { name : "打开供水管网地图窗口操作" } ) ) . toBeAttached ( ) ;
await openWindowOperationMenu ( page , "供水管网地图" ) ;
await page . getByRole ( "menuitem" , { name : "最小化" } ) . click ( ) ;
await expect ( mapWindow ) . toBeHidden ( ) ;
const restoreTask = page . getByRole ( "button" , { name : "恢复供水管网地图" } ) ;
await expect ( restoreTask ) . toBeVisible ( ) ;
await restoreTask . click ( ) ;
await expect ( mapWindow ) . toBeVisible ( ) ;
await expect ( page . getByRole ( "button" , { name : "打开供水管网地图窗口操作" } ) ) . toBeAttached ( ) ;
} ) ;
test ( "the test control cycles through three trusted document profiles" , async ( { page } ) = > {
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
const testButton = page . getByRole ( "button" , { name : "测试打开 Agent 多图表窗口" } ) . first ( ) ;
await testButton . click ( ) ;
await testButton . click ( ) ;
await testButton . click ( ) ;
await expect ( page . getByRole ( "heading" , { name : "北辰分区压力异常诊断" , exact : true } ) ) . toBeAttached ( ) ;
await expect ( page . getByRole ( "heading" , { name : "供水服务分区平衡分析" , exact : true } ) ) . toBeAttached ( ) ;
await expect ( page . getByRole ( "heading" , { name : "低压事件调度处置流程" , exact : true } ) ) . toBeVisible ( ) ;
await expect ( page . getByText ( "3 / 6 个临时分析窗" ) ) . toBeVisible ( ) ;
} ) ;
test ( "task view shows every window and fills the workspace with the selected one" , async ( { page } ) = > {
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
const testButton = page . getByRole ( "button" , { name : "测试打开 Agent 多图表窗口" } ) . first ( ) ;
await testButton . click ( ) ;
await testButton . click ( ) ;
await openWindowOperationMenu ( page , "北辰分区压力异常诊断" ) ;
await page . getByRole ( "menuitem" , { name : "最小化" } ) . click ( ) ;
await page . getByRole ( "button" , { name : "任务视图" } ) . click ( ) ;
await expect ( page . getByRole ( "dialog" , { name : "任务视图" } ) ) . toBeVisible ( ) ;
await expect ( page . getByRole ( "button" , { name : /打开供水管网地图并铺满主视图/ } ) ) . toBeVisible ( ) ;
await expect ( page . getByRole ( "button" , { name : /打开北辰分区压力异常诊断并铺满主视图,当前已最小化/ } ) ) . toBeVisible ( ) ;
await expect ( page . getByRole ( "button" , { name : /打开供水服务分区平衡分析并铺满主视图/ } ) ) . toBeVisible ( ) ;
await page . getByRole ( "button" , { name : /打开供水服务分区平衡分析并铺满主视图/ } ) . click ( ) ;
await expect ( page . getByRole ( "dialog" , { name : "任务视图" } ) ) . toHaveCount ( 0 ) ;
const workspaceBox = await page . locator ( "#main-workspace" ) . boundingBox ( ) ;
const selectedBox = await page . locator ( "section[aria-label='供水服务分区平衡分析']" ) . boundingBox ( ) ;
expect ( workspaceBox ) . not . toBeNull ( ) ;
expect ( selectedBox ) . not . toBeNull ( ) ;
expect ( Math . abs ( selectedBox ! . width - workspaceBox ! . width ) ) . toBeLessThanOrEqual ( 2 ) ;
expect ( Math . abs ( selectedBox ! . height - workspaceBox ! . height ) ) . toBeLessThanOrEqual ( 2 ) ;
await page . getByRole ( "button" , { name : "任务视图" } ) . click ( ) ;
await page . keyboard . press ( "Escape" ) ;
await expect ( page . getByRole ( "dialog" , { name : "任务视图" } ) ) . toHaveCount ( 0 ) ;
await expect ( page . getByRole ( "button" , { name : "任务视图" } ) ) . toBeFocused ( ) ;
} ) ;
test ( "temporary documents survive a mobile breakpoint round trip" , async ( { page } ) = > {
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
await page . getByRole ( "button" , { name : "测试打开 Agent 多图表窗口" } ) . first ( ) . click ( ) ;
const analysisHeading = page . locator ( "h2" , { hasText : "北辰分区压力异常诊断" } ) ;
await expect ( analysisHeading ) . toBeVisible ( ) ;
await page . setViewportSize ( { width : 390 , height : 844 } ) ;
await expect ( page . locator ( "#workspace-map" ) ) . toBeVisible ( ) ;
await expect ( analysisHeading ) . toBeAttached ( ) ;
await expect ( analysisHeading ) . toBeHidden ( ) ;
await page . setViewportSize ( { width : 1440 , height : 900 } ) ;
await expect ( analysisHeading ) . toBeVisible ( ) ;
await expect ( page . locator ( "#workspace-map" ) ) . toBeVisible ( ) ;
} ) ;
test ( "layout presets arrange transient windows and keep the map visible" , async ( { page } ) = > {
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
const testButton = page . getByRole ( "button" , { name : "测试打开 Agent 多图表窗口" } ) . first ( ) ;
await testButton . click ( ) ;
await testButton . click ( ) ;
await testButton . click ( ) ;
await applyTaskViewLayout ( page , "主次" ) ;
const workspace = page . locator ( "#main-workspace" ) ;
await expect ( workspace ) . toHaveAttribute ( "data-layout-mode" , "primary" ) ;
await expect ( page . locator ( "#workspace-map" ) ) . toBeVisible ( ) ;
await expect ( page . locator ( "section[aria-label='低压事件调度处置流程']" ) ) . toBeVisible ( ) ;
await expect ( page . locator ( "section[aria-label='北辰分区压力异常诊断']" ) ) . toBeHidden ( ) ;
await expect ( page . locator ( "section[aria-label='低压事件调度处置流程']" ) ) . toHaveCSS ( "border-radius" , "0px" ) ;
const workspaceBox = await workspace . boundingBox ( ) ;
const primaryBox = await page . locator ( "section[aria-label='低压事件调度处置流程']" ) . boundingBox ( ) ;
expect ( workspaceBox ) . not . toBeNull ( ) ;
expect ( primaryBox ) . not . toBeNull ( ) ;
expect ( primaryBox ! . width ) . toBeGreaterThan ( workspaceBox ! . width * 0.6 ) ;
await testButton . click ( ) ;
await expect ( page . locator ( "section[aria-label='北辰分区压力异常诊断']" ) . last ( ) ) . toBeVisible ( ) ;
const newPrimaryBox = await page . locator ( "section[aria-label='北辰分区压力异常诊断']" ) . last ( ) . boundingBox ( ) ;
expect ( newPrimaryBox ) . not . toBeNull ( ) ;
expect ( newPrimaryBox ! . width ) . toBeGreaterThan ( workspaceBox ! . width * 0.6 ) ;
} ) ;
test ( "dragging a small window onto the primary window swaps their complete slots" , async ( { page } ) = > {
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
await page . getByRole ( "button" , { name : "测试打开 Agent 多图表窗口" } ) . first ( ) . click ( ) ;
await applyTaskViewLayout ( page , "主次" ) ;
const mapWindow = page . locator ( "#workspace-map" ) ;
const analysisWindow = page . locator ( "section[aria-label='北辰分区压力异常诊断']" ) ;
const mapBefore = await mapWindow . boundingBox ( ) ;
const analysisBefore = await analysisWindow . boundingBox ( ) ;
expect ( mapBefore ) . not . toBeNull ( ) ;
expect ( analysisBefore ) . not . toBeNull ( ) ;
expect ( mapBefore ! . width ) . toBeLessThan ( analysisBefore ! . width ) ;
await page . mouse . move ( mapBefore ! . x + 72 , mapBefore ! . y + 22 ) ;
await page . keyboard . down ( "Alt" ) ;
await page . mouse . down ( ) ;
await page . mouse . move (
analysisBefore ! . x + analysisBefore ! . width / 2 ,
analysisBefore ! . y + analysisBefore ! . height / 2 ,
{ steps : 10 }
) ;
await expect ( page . getByText ( "释放以交换" ) ) . toBeVisible ( ) ;
await page . mouse . up ( ) ;
await page . keyboard . up ( "Alt" ) ;
const mapAfter = await mapWindow . boundingBox ( ) ;
const analysisAfter = await analysisWindow . boundingBox ( ) ;
expect ( mapAfter ) . not . toBeNull ( ) ;
expect ( analysisAfter ) . not . toBeNull ( ) ;
expect ( mapAfter ! . width ) . toBeGreaterThan ( analysisAfter ! . width ) ;
expect ( Math . abs ( mapAfter ! . x - analysisBefore ! . x ) ) . toBeLessThanOrEqual ( 2 ) ;
expect ( Math . abs ( analysisAfter ! . x - mapBefore ! . x ) ) . toBeLessThanOrEqual ( 2 ) ;
await expect ( page . getByText ( "供水管网地图与北辰分区压力异常诊断已交换位置" ) ) . toBeAttached ( ) ;
} ) ;
test ( "dropping on blank workspace exits auto layout and Escape cancels a drag" , async ( { page } ) = > {
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
await page . getByRole ( "button" , { name : "测试打开 Agent 多图表窗口" } ) . first ( ) . click ( ) ;
await applyTaskViewLayout ( page , "双栏" ) ;
const workspace = page . locator ( "#main-workspace" ) ;
const analysisWindow = page . locator ( "section[aria-label='北辰分区压力异常诊断']" ) ;
const before = await analysisWindow . boundingBox ( ) ;
const workspaceBox = await workspace . boundingBox ( ) ;
const before = await workspace . boundingBox ( ) ;
expect ( before ) . not . toBeNull ( ) ;
expect ( workspaceBox ) . not . toBeNull ( ) ;
await page . mouse . move ( before ! . x + 80 , before ! . y + 22 ) ;
await page . keyboard . down ( "Alt" ) ;
await page . mouse . down ( ) ;
await page . mouse . move ( workspaceBox ! . x + 4 , workspaceBox ! . y + 4 , { steps : 8 } ) ;
await page . keyboard . press ( "Escape" ) ;
await page . keyboard . up ( "Alt" ) ;
await expect ( workspace ) . toHaveAttribute ( "data-layout-mode" , "split" ) ;
const afterCancel = await analysisWindow . boundingBox ( ) ;
expect ( Math . abs ( afterCancel ! . x - before ! . x ) ) . toBeLessThanOrEqual ( 2 ) ;
await page . getByLabel ( /展开 Agent 助手面板/ ) . click ( ) ;
await expect ( page . getByLabel ( "Agent 命令面板" ) ) . toBeVisible ( ) ;
const after = await workspace . boundingBox ( ) ;
await page . mouse . move ( before ! . x + 80 , before ! . y + 22 ) ;
await page . keyboard . down ( "Alt" ) ;
await page . mouse . down ( ) ;
await page . mouse . move ( workspaceBox ! . x + 4 , workspaceBox ! . y + 4 , { steps : 8 } ) ;
await page . mouse . up ( ) ;
await page . keyboard . up ( "Alt" ) ;
await expect ( workspace ) . toHaveAttribute ( "data-layout-mode" , "free" ) ;
await expect ( page . getByText ( "北辰分区压力异常诊断已转为自由排列" ) ) . toBeAttached ( ) ;
expect ( after ) . not . toBeNull ( ) ;
expect ( after ! . x ) . toBe ( before ! . x ) ;
expect ( after ! . width ) . toBe ( before ! . width ) ;
} ) ;
async function openWindowOperationMenu ( page : Page , title : string ) {
const window = page . locator ( ` section[aria-label=' ${ title } '] ` ) ;
await page . getByRole ( "button" , { name : ` 切换到 ${ title } ` } ) . click ( ) ;
await window . hover ( ) ;
await page . getByRole ( "button" , { name : ` 打开 ${ title } 窗口操作 ` } ) . click ( ) ;
}
test ( "spatial Artifacts switch between split, focus and peek" , async ( { page } ) = > {
await page . setViewportSize ( { width : 1600 , height : 900 } ) ;
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
await openFirstArtifact ( page ) ;
async function applyTaskViewLayout ( page : Page , layoutName : string ) {
await page . getByRole ( "button" , { name : "任务视图" } ) . click ( ) ;
await page . getByRole ( "button" , { name : new RegExp ( ` ^ ${ layoutName } : ` ) } ) . click ( ) ;
await page . getByRole ( "button" , { name : "专注分析" } ) . click ( ) ;
await expect ( page . locator ( "#main-workspace" ) ) . toHaveAttribute ( "data-layout-mode" , "focus" ) ;
await expect ( page . locator ( "#workspace-map" ) ) . toBeHidden ( ) ;
await page . getByRole ( "button" , { name : "显示地图" } ) . click ( ) ;
await expect ( page . locator ( "#main-workspace" ) ) . toHaveAttribute ( "data-layout-mode" , "map_split" ) ;
await expect ( page . locator ( "#workspace-map" ) ) . toBeVisible ( ) ;
await page . getByRole ( "button" , { name : "将成果收起为预览" } ) . click ( ) ;
await expect ( page . locator ( "#main-workspace" ) ) . toHaveAttribute ( "data-layout-mode" , "default" ) ;
await expect ( page . getByRole ( "complementary" , { name : "Agent 成果预览" } ) ) . toBeVisible ( ) ;
await expect ( page . getByLabel ( "Agent 命令面板" ) ) . toBeVisible ( ) ;
await page . getByRole ( "button" , { name : "销毁预览成果" } ) . click ( ) ;
await expect ( page . getByRole ( "complementary" , { name : "Agent 成果预览" } ) ) . toHaveCount ( 0 ) ;
await expect ( page . locator ( "#workspace-map" ) ) . toBeVisible ( ) ;
} ) ;
test ( "non-spatial Artifacts open directly in focus mode" , async ( { page } ) = > {
await page . setViewportSize ( { width : 1600 , height : 900 } ) ;
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
await page . getByRole ( "button" , { name : "生成 Agent 模拟分析成果" } ) . click ( ) ;
await page . getByRole ( "button" , { name : "销毁预览成果" } ) . click ( ) ;
await page . getByRole ( "button" , { name : "生成 Agent 模拟分析成果" } ) . click ( ) ;
await page . getByRole ( "button" , { name : "打开成果" } ) . click ( ) ;
await expect ( page . locator ( "#main-workspace" ) ) . toHaveAttribute ( "data-layout-mode" , "focus" ) ;
await expect ( page . getByRole ( "heading" , { name : "供水服务分区平衡分析" } ) ) . toBeVisible ( ) ;
await expect ( page . locator ( "#workspace-map" ) ) . toBeHidden ( ) ;
await expect ( page . getByRole ( "button" , { name : "显示地图" } ) ) . toHaveCount ( 0 ) ;
} ) ;
test ( "narrow workspaces switch between Artifact and map as pages" , async ( { page } ) = > {
await page . setViewportSize ( { width : 1180 , height : 820 } ) ;
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
await openFirstArtifact ( page ) ;
await expect ( page . locator ( "#main-workspace" ) ) . toHaveAttribute ( "data-layout-mode" , "focus" ) ;
await page . getByRole ( "button" , { name : "显示地图" } ) . click ( ) ;
await expect ( page . locator ( "#main-workspace" ) ) . toHaveAttribute ( "data-layout-mode" , "map_only" ) ;
await expect ( page . locator ( "#workspace-map" ) ) . toBeVisible ( ) ;
await expect ( page . locator ( "#artifact-workspace" ) ) . toBeHidden ( ) ;
await page . getByRole ( "button" , { name : "返回分析成果" } ) . click ( ) ;
await expect ( page . locator ( "#main-workspace" ) ) . toHaveAttribute ( "data-layout-mode" , "focus" ) ;
await expect ( page . locator ( "#artifact-workspace" ) ) . toBeVisible ( ) ;
} ) ;
test ( "the condition feed remains floating and starts closed" , async ( { page } ) = > {
await page . setViewportSize ( { width : 1600 , height : 900 } ) ;
await prepareMainFrame ( page ) ;
await page . goto ( "/" , { waitUntil : "domcontentloaded" } ) ;
await expect ( page . getByRole ( "region" , { name : "工况任务" , exact : true } ) ) . toHaveCount ( 0 ) ;
await page . getByRole ( "button" , { name : "工况任务" , exact : true } ) . click ( ) ;
await expect ( page . getByRole ( "region" , { name : "工况任务" , exact : true } ) ) . toBeVisible ( ) ;
} ) ;
async function openFirstArtifact ( page : Page ) {
await page . getByRole ( "button" , { name : "生成 Agent 模拟分析成果" } ) . click ( ) ;
await page . getByRole ( "button" , { name : "打开成果" } ) . click ( ) ;
}
async function prepareMainFrame ( page : Page ) {