import { expect, test, type Locator } from "playwright/test"; test("scheduled conditions keep acrylic blur outside transformed ancestors", async ({ page }) => { await page.goto("/", { waitUntil: "domcontentloaded" }); const panel = page.getByRole("region", { name: "工况任务", exact: true }); await expect(panel).toBeVisible(); await page.waitForTimeout(250); await expectAcrylicComposition(panel); await expect(panel).toHaveCSS("width", "432px"); const timeline = panel.getByTestId("scheduled-condition-timeline"); const collapsedPanelBox = await panel.boundingBox(); const collapsedTimelineBox = await timeline.boundingBox(); expect(collapsedPanelBox).not.toBeNull(); expect(collapsedTimelineBox).not.toBeNull(); await panel.getByRole("button", { name: "展开工况任务" }).click(); await page.waitForTimeout(250); await expectAcrylicComposition(panel); await expect(panel).toHaveCSS("width", "880px"); const expandedPanelBox = await panel.boundingBox(); const expandedTimelineBox = await timeline.boundingBox(); expect(expandedPanelBox).not.toBeNull(); expect(expandedTimelineBox).not.toBeNull(); expect(Math.round(expandedPanelBox!.x + expandedPanelBox!.width)).toBe( Math.round(collapsedPanelBox!.x + collapsedPanelBox!.width) ); expect(Math.round(expandedTimelineBox!.width)).toBe( Math.round(collapsedTimelineBox!.width) ); expect(Math.round(expandedTimelineBox!.x + expandedTimelineBox!.width)).toBe( Math.round(collapsedTimelineBox!.x + collapsedTimelineBox!.width) ); await panel.getByRole("button", { name: "收起工况任务" }).click(); await page.waitForTimeout(250); await expect(panel).toHaveCSS("width", "432px"); const restoredTimelineBox = await timeline.boundingBox(); expect(restoredTimelineBox).not.toBeNull(); expect(Math.round(restoredTimelineBox!.width)).toBe( Math.round(collapsedTimelineBox!.width) ); }); test("narrow desktop keeps Agent and expanded conditions from overlapping", async ({ page }) => { await page.setViewportSize({ width: 1024, height: 768 }); await page.goto("/", { waitUntil: "domcontentloaded" }); await page.getByRole("button", { name: "工况任务", exact: true }).click(); const panel = page.getByRole("region", { name: "工况任务", exact: true }); const agentPanel = page.locator('aside[aria-label="Agent 命令面板"]'); const resizeHandle = page.getByRole("separator", { name: "调整 Agent 面板宽度" }); await resizeHandle.focus(); await page.keyboard.press("End"); await expect(agentPanel).toHaveCSS("width", "484px"); const compactAgentBox = await agentPanel.boundingBox(); const compactConditionBox = await panel.boundingBox(); expect(compactAgentBox).not.toBeNull(); expect(compactConditionBox).not.toBeNull(); expect(compactConditionBox!.x - (compactAgentBox!.x + compactAgentBox!.width)).toBeGreaterThanOrEqual( 24 ); await panel.getByRole("button", { name: "展开工况任务" }).click(); await expect(page.locator('aside[aria-label="Agent 折叠栏"]')).toBeVisible(); await expect(panel).toHaveCSS("width", "852px"); const expandedConditionBox = await panel.boundingBox(); const collapsedAgentBox = await page .locator('aside[aria-label="Agent 折叠栏"]') .boundingBox(); expect(expandedConditionBox).not.toBeNull(); expect(collapsedAgentBox).not.toBeNull(); expect( expandedConditionBox!.x - (collapsedAgentBox!.x + collapsedAgentBox!.width) ).toBeGreaterThanOrEqual(24); await panel.getByRole("button", { name: "收起工况任务" }).click(); await expect(agentPanel).toBeVisible(); }); async function expectAcrylicComposition(panel: Locator) { const composition = await panel.evaluate((element) => { const rootStyle = getComputedStyle(element); const blockingAncestors: string[] = []; const filteredDescendants: string[] = []; let ancestor = element.parentElement; while (ancestor && ancestor.tagName !== "MAIN") { const style = getComputedStyle(ancestor); if ( style.transform !== "none" || style.filter !== "none" || style.opacity !== "1" || style.isolation !== "auto" || style.willChange.includes("transform") ) { blockingAncestors.push(ancestor.className); } ancestor = ancestor.parentElement; } for (const descendant of element.querySelectorAll("*")) { if (getComputedStyle(descendant).backdropFilter !== "none") { filteredDescendants.push(descendant.className); } } return { backdropFilter: rootStyle.backdropFilter, blockingAncestors, filteredDescendants, transform: rootStyle.transform, willChange: rootStyle.willChange }; }); expect(composition.backdropFilter).toContain("blur("); expect(composition.blockingAncestors).toEqual([]); expect(composition.filteredDescendants).toEqual([]); expect(composition.transform).toBe("none"); expect(composition.willChange).toBe("auto"); }