feat: add adaptive agent workspace windows
This commit is contained in:
@@ -31,35 +31,32 @@ async function waitForAnimations(locator: Locator) {
|
||||
});
|
||||
}
|
||||
|
||||
test("desktop Agent layers floating controls inside one acrylic panel", async ({ page }) => {
|
||||
test("desktop Agent lives in the solid Main Frame navigation pane", async ({ page }) => {
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
|
||||
const topBar = page.locator("header.acrylic-navigation");
|
||||
const navigation = page.getByRole("complementary", { name: "工作台导航" });
|
||||
const agentPanel = page.locator('aside[aria-label="Agent 命令面板"]');
|
||||
const agentHeader = agentPanel.locator(".agent-panel-integrated-header");
|
||||
const agentConversation = agentPanel.locator(".agent-panel-conversation-canvas");
|
||||
const agentHeader = agentPanel.locator(".agent-panel-header");
|
||||
const agentConversation = agentPanel.getByRole("log");
|
||||
const agentConversationScroll = agentPanel.locator(".agent-conversation-scroll");
|
||||
const agentComposer = agentPanel.locator(".agent-panel-composer");
|
||||
const agentControls = agentPanel.locator(".agent-panel-band").last();
|
||||
|
||||
await expect(topBar).toBeVisible();
|
||||
await expect(navigation).toBeVisible();
|
||||
await expect(agentPanel).toBeVisible();
|
||||
await expect(agentHeader).toBeVisible();
|
||||
await expect(agentComposer).toBeVisible();
|
||||
await expect(agentControls).toBeVisible();
|
||||
await waitForAnimations(agentPanel);
|
||||
|
||||
await expectAcrylicSurface(topBar);
|
||||
await expectAcrylicSurface(agentPanel, ".agent-panel-composer");
|
||||
await expectIntegratedHeader(agentHeader);
|
||||
await expectContextualAcrylicSurface(agentComposer, {
|
||||
backdropFilter: "blur(",
|
||||
maximumAlpha: 0.9,
|
||||
minimumAlpha: 0.84
|
||||
});
|
||||
await expectLightweightMaterialContext(agentConversation);
|
||||
await expectUnfilteredInternalSurfaces(agentComposer.locator(".agent-panel-control"));
|
||||
await expect(agentComposer).toHaveCSS("background-color", "rgba(255, 255, 255, 0.86)");
|
||||
await expect(agentComposer).toHaveCSS("border-radius", "16px");
|
||||
await expect(agentComposer).toHaveCSS("border-top-width", "0px");
|
||||
await expect(navigation).toHaveCSS("background-color", "rgb(237, 241, 245)");
|
||||
await expect(navigation).toHaveCSS("backdrop-filter", "none");
|
||||
await expect(agentPanel).toHaveCSS("background-color", "rgb(247, 249, 251)");
|
||||
await expect(agentPanel).toHaveCSS("backdrop-filter", "none");
|
||||
await expect(agentPanel).toHaveCSS("border-radius", "0px");
|
||||
await expect(agentPanel).toHaveCSS("box-shadow", "none");
|
||||
await expect(agentControls).toHaveCSS("border-top-width", "1px");
|
||||
await expect(
|
||||
agentPanel.getByText("直接说出你想调查的问题,我会整理监测与空间证据,并将分析结果带回地图。")
|
||||
).toHaveCSS("color", "rgb(51, 65, 85)");
|
||||
@@ -69,66 +66,30 @@ test("desktop Agent layers floating controls inside one acrylic panel", async ({
|
||||
const panelBox = await agentPanel.boundingBox();
|
||||
const conversationBox = await agentConversation.boundingBox();
|
||||
const scrollBox = await agentConversationScroll.boundingBox();
|
||||
const composerBox = await agentComposer.boundingBox();
|
||||
expect(panelBox).not.toBeNull();
|
||||
expect(conversationBox).not.toBeNull();
|
||||
expect(scrollBox).not.toBeNull();
|
||||
expect(composerBox).not.toBeNull();
|
||||
expect(panelBox!.x).toBe(48);
|
||||
expect(panelBox!.width).toBe(319);
|
||||
expect(
|
||||
Math.abs(conversationBox!.y + conversationBox!.height - (panelBox!.y + panelBox!.height - 4))
|
||||
).toBeLessThanOrEqual(1);
|
||||
expect(
|
||||
Math.abs(scrollBox!.y + scrollBox!.height - (conversationBox!.y + conversationBox!.height))
|
||||
).toBeLessThanOrEqual(1);
|
||||
expect(composerBox!.y).toBeLessThan(conversationBox!.y + conversationBox!.height);
|
||||
expect(composerBox!.x - panelBox!.x).toBeGreaterThanOrEqual(21);
|
||||
expect(
|
||||
Math.abs(
|
||||
composerBox!.x -
|
||||
panelBox!.x -
|
||||
(panelBox!.x + panelBox!.width - composerBox!.x - composerBox!.width)
|
||||
)
|
||||
Math.abs(conversationBox!.x - panelBox!.x)
|
||||
).toBeLessThanOrEqual(1);
|
||||
await expect(agentConversationScroll).toHaveCSS("scrollbar-gutter", "stable both-edges");
|
||||
|
||||
const beforeFocus = await getFloatingSurfaceStyles(agentHeader, agentComposer);
|
||||
const beforeFocus = await getSurfacePresentation(agentPanel);
|
||||
await page.getByPlaceholder("输入调度问题,Agent 将通过后端会话流式响应").focus();
|
||||
await expect
|
||||
.poll(() => getFloatingSurfaceStyles(agentHeader, agentComposer))
|
||||
.poll(() => getSurfacePresentation(agentPanel))
|
||||
.toEqual(beforeFocus);
|
||||
});
|
||||
|
||||
async function expectIntegratedHeader(header: Locator) {
|
||||
const composition = await header.evaluate((element) => {
|
||||
const style = getComputedStyle(element);
|
||||
|
||||
return {
|
||||
backdropFilter: style.backdropFilter,
|
||||
backgroundColor: style.backgroundColor,
|
||||
borderTopWidth: style.borderTopWidth,
|
||||
borderRadius: style.borderRadius
|
||||
};
|
||||
});
|
||||
|
||||
expect(composition.backdropFilter).toBe("none");
|
||||
expect(getAlpha(composition.backgroundColor)).toBe(0);
|
||||
expect(composition.borderTopWidth).toBe("0px");
|
||||
expect(composition.borderRadius).toBe("0px");
|
||||
}
|
||||
|
||||
test("desktop Agent header expands into one attached acrylic history surface", async ({ page }) => {
|
||||
test("desktop Agent history remains usable inside the docked navigation pane", async ({ page }) => {
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
|
||||
const agentPanel = page.locator('aside[aria-label="Agent 命令面板"]');
|
||||
const agentHeader = agentPanel.locator(".agent-panel-integrated-header");
|
||||
const agentConversation = agentPanel.locator(".agent-panel-conversation-canvas");
|
||||
const historyButton = agentPanel.getByRole("button", {
|
||||
name: "打开 Agent 历史记录"
|
||||
});
|
||||
const headerBefore = await agentHeader.boundingBox();
|
||||
const conversationBefore = await agentConversation.boundingBox();
|
||||
const historyButtonPresentationBefore = await getSurfacePresentation(historyButton);
|
||||
const agentPanelFrameBefore = await expectAcrylicOutline(agentPanel);
|
||||
|
||||
await historyButton.click();
|
||||
|
||||
@@ -136,51 +97,7 @@ test("desktop Agent header expands into one attached acrylic history surface", a
|
||||
await expect(history).toBeVisible();
|
||||
await waitForAnimations(history);
|
||||
await expect(historyButton).toHaveAttribute("aria-expanded", "true");
|
||||
await page.mouse.move(720, 320);
|
||||
await expectAttachedHistoryExtension(history);
|
||||
await expectTransparentExpandedHeader(agentHeader, agentPanel);
|
||||
await expectUnifiedHistoryStructure(history);
|
||||
await expect.poll(() => getAcrylicFrame(agentPanel)).toEqual(agentPanelFrameBefore);
|
||||
await expect
|
||||
.poll(() => getSurfacePresentation(historyButton))
|
||||
.toEqual(historyButtonPresentationBefore);
|
||||
|
||||
const sessionTrigger = history.locator(".agent-history-session-trigger").first();
|
||||
const sessionTriggerBox = await sessionTrigger.boundingBox();
|
||||
const historyHeadingBox = await history.getByText("历史记录", { exact: true }).boundingBox();
|
||||
expect(sessionTriggerBox).not.toBeNull();
|
||||
expect(historyHeadingBox).not.toBeNull();
|
||||
await page.mouse.move(
|
||||
sessionTriggerBox!.x + sessionTriggerBox!.width / 2,
|
||||
sessionTriggerBox!.y + sessionTriggerBox!.height / 2
|
||||
);
|
||||
await page.mouse.down();
|
||||
await expect(sessionTrigger).toHaveCSS("outline-style", "none");
|
||||
await page.mouse.move(
|
||||
historyHeadingBox!.x + historyHeadingBox!.width / 2,
|
||||
historyHeadingBox!.y + historyHeadingBox!.height / 2
|
||||
);
|
||||
await page.mouse.up();
|
||||
|
||||
const headerBox = await agentHeader.boundingBox();
|
||||
const agentPanelBox = await agentPanel.boundingBox();
|
||||
const historyBox = await history.boundingBox();
|
||||
const conversationAfter = await agentConversation.boundingBox();
|
||||
expect(headerBefore).not.toBeNull();
|
||||
expect(headerBox).not.toBeNull();
|
||||
expect(agentPanelBox).not.toBeNull();
|
||||
expect(historyBox).not.toBeNull();
|
||||
expect(conversationBefore).not.toBeNull();
|
||||
expect(conversationAfter).not.toBeNull();
|
||||
expectRoundedValue(headerBox!.y, headerBefore!.y);
|
||||
expect(headerBox!.height).toBeGreaterThan(headerBefore!.height);
|
||||
expectRoundedValue(historyBox!.y, headerBefore!.y + headerBefore!.height);
|
||||
expectRoundedValue(headerBox!.x, agentPanelBox!.x + 1);
|
||||
expectRoundedValue(headerBox!.y, agentPanelBox!.y + 1);
|
||||
expectRoundedValue(headerBox!.width, agentPanelBox!.width - 2);
|
||||
expectRoundedValue(historyBox!.x, headerBox!.x);
|
||||
expectRoundedValue(historyBox!.width, headerBox!.width);
|
||||
expectRoundedBox(conversationAfter!, conversationBefore!);
|
||||
|
||||
await history.getByRole("button", { name: "重命名对话" }).first().click();
|
||||
const renameInput = history.locator("input").first();
|
||||
@@ -197,12 +114,6 @@ test("desktop Agent header expands into one attached acrylic history surface", a
|
||||
await expect(history).toBeHidden();
|
||||
await expect(historyButton).toBeFocused();
|
||||
await expect(historyButton).toHaveAttribute("aria-expanded", "false");
|
||||
await expect.poll(() => getAcrylicFrame(agentPanel)).toEqual(agentPanelFrameBefore);
|
||||
|
||||
await historyButton.click();
|
||||
await expect(history).toBeVisible();
|
||||
await page.mouse.click(720, 320);
|
||||
await expect(history).toBeHidden();
|
||||
});
|
||||
|
||||
test("mobile Agent mirrors the desktop floating history surface", async ({ page }) => {
|
||||
@@ -268,15 +179,16 @@ test("mobile Agent mirrors the desktop floating history surface", async ({ page
|
||||
await expect(historyButton).toBeFocused();
|
||||
});
|
||||
|
||||
test("Agent floating acrylic respects forced color mode", async ({ page }) => {
|
||||
test("Main Frame navigation respects forced color mode", async ({ page }) => {
|
||||
await page.emulateMedia({ forcedColors: "active" });
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
|
||||
const composer = page.locator(".agent-panel-composer");
|
||||
await expect(composer).toBeVisible();
|
||||
await expect(composer).toHaveCSS("backdrop-filter", "none");
|
||||
await expect(composer).toHaveCSS("background-image", "none");
|
||||
await expect(composer).toHaveCSS("box-shadow", "none");
|
||||
const navigation = page.getByRole("complementary", { name: "工作台导航" });
|
||||
const taskbar = page.getByRole("toolbar", { name: "工作区窗口任务栏" });
|
||||
await expect(navigation).toBeVisible();
|
||||
await expect(navigation).toHaveCSS("backdrop-filter", "none");
|
||||
await expect(navigation).toHaveCSS("box-shadow", "none");
|
||||
await expect(taskbar).toHaveCSS("box-shadow", "none");
|
||||
});
|
||||
|
||||
async function expectAcrylicSurface(shell: Locator, allowedFilteredDescendant?: string) {
|
||||
|
||||
Reference in New Issue
Block a user