import { expect, test, type Locator } from "playwright/test"; test("agent header reveals the shell acrylic without nesting another filter", async ({ page }) => { await page.goto("/", { waitUntil: "domcontentloaded" }); await page.waitForTimeout(250); const topBar = page.locator("header.acrylic-navigation"); const agentPanel = page.locator('aside[aria-label="Agent 命令面板"]'); const agentHeader = agentPanel.locator(".agent-panel-header"); await expect(topBar).toBeVisible(); await expect(agentPanel).toBeVisible(); await expect(agentHeader).toBeVisible(); await expectAcrylicSurface(topBar); await expectAcrylicSurface(agentPanel); await expectTransparentAcrylicContext(agentHeader); await expectLightweightContextSurfaces(agentPanel.locator(".agent-panel-conversation")); await expectSolidInternalSurfaces(agentPanel.locator(".agent-panel-band")); }); async function expectAcrylicSurface(shell: Locator) { const composition = await shell.evaluate((element) => { const style = getComputedStyle(element); const filteredDescendants: string[] = []; for (const descendant of element.querySelectorAll("*")) { if (getComputedStyle(descendant).backdropFilter !== "none") { filteredDescendants.push(descendant.className); } } return { backdropFilter: style.backdropFilter, backgroundColor: style.backgroundColor, filteredDescendants, transform: style.transform, willChange: style.willChange }; }); expect(composition.backdropFilter).toContain("blur("); expect(getAlpha(composition.backgroundColor)).toBeLessThan(1); expect(composition.filteredDescendants).toEqual([]); expect(composition.transform).toBe("none"); expect(composition.willChange).toBe("auto"); } function getAlpha(color: string) { const match = color.match(/^rgba\([^,]+,[^,]+,[^,]+,\s*([\d.]+)\)$/); return match ? Number(match[1]) : 1; } async function expectTransparentAcrylicContext(header: Locator) { const style = await header.evaluate((element) => { const computedStyle = getComputedStyle(element); return { backdropFilter: computedStyle.backdropFilter, backgroundColor: computedStyle.backgroundColor, className: element.className, webkitBackdropFilter: computedStyle.getPropertyValue("-webkit-backdrop-filter") }; }); expect(style.backdropFilter).toBe("none"); expect(style.backgroundColor).toBe("rgba(0, 0, 0, 0)"); expect(["", "none"]).toContain(style.webkitBackdropFilter); expect(String(style.className)).not.toContain("acrylic-"); } async function expectLightweightContextSurfaces(surfaces: Locator) { const surfaceStyles = await surfaces.evaluateAll((elements) => elements.map((element) => { const style = getComputedStyle(element); return { backdropFilter: style.backdropFilter, backgroundColor: style.backgroundColor }; }) ); expect(surfaceStyles.length).toBeGreaterThan(0); for (const style of surfaceStyles) { expect(style.backdropFilter).toBe("none"); expect(getAlpha(style.backgroundColor)).toBeLessThanOrEqual(0.12); } } async function expectSolidInternalSurfaces(surfaces: Locator) { const surfaceStyles = await surfaces.evaluateAll((elements) => elements.map((element) => { const style = getComputedStyle(element); return { backdropFilter: style.backdropFilter, className: element.className, webkitBackdropFilter: style.getPropertyValue("-webkit-backdrop-filter") }; }) ); expect(surfaceStyles.length).toBeGreaterThan(0); for (const style of surfaceStyles) { expect(style.backdropFilter).toBe("none"); expect(["", "none"]).toContain(style.webkitBackdropFilter); expect(String(style.className)).not.toContain("acrylic-"); } }