mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-14 13:22:37 +00:00
* feat(app): modernize compact headers and sidebar affordances Use a shared island header with quick tab creation and keep sheet footers inside their visible layout. Opt sidebar rows into touch sizing without changing global appearance settings. * test(app): match darker light-theme workspace selection * test(app): align plugin journeys with compact header
204 lines
8.3 KiB
TypeScript
204 lines
8.3 KiB
TypeScript
import type { Locator, TestInfo } from "@playwright/test";
|
|
import { test, expect, type Page } from "@playwright/test";
|
|
import { copyPluginExample } from "./plugin-fixture";
|
|
import { gotoAppShell } from "./app";
|
|
import { buildAgentRoute } from "./mock-agent";
|
|
import { openCommandCenter } from "./command-center";
|
|
import { connectNewWorkspaceDaemonClient } from "./new-workspace";
|
|
import { seedWorkspace } from "./seed-client";
|
|
import { waitForSettledPosition } from "./sheet-layout";
|
|
|
|
const WIDE = { width: 1440, height: 900 };
|
|
const COMPACT = { width: 390, height: 844 };
|
|
|
|
function headerButtons(page: Page) {
|
|
return page.getByRole("toolbar", { name: "Workspace actions", exact: true }).getByRole("button");
|
|
}
|
|
|
|
async function exampleCommand(page: Page, name: string) {
|
|
await page.setViewportSize(WIDE);
|
|
const panel = await openCommandCenter(page);
|
|
const title = `Button examples: ${name}`;
|
|
await panel.getByTestId("command-center-input").fill(title);
|
|
await panel.getByRole("button", { name: title, exact: true }).click();
|
|
await expect(panel).not.toBeVisible();
|
|
}
|
|
|
|
async function capture(
|
|
page: Page,
|
|
info: TestInfo,
|
|
name: string,
|
|
subject: Locator = headerButtons(page),
|
|
) {
|
|
await expect(subject).toBeInViewport();
|
|
await waitForSettledPosition(subject);
|
|
const file = info.outputPath(`${name}.png`);
|
|
await page.screenshot({ path: file, animations: "disabled" });
|
|
await info.attach(name, { path: file, contentType: "image/png" });
|
|
}
|
|
|
|
async function closeDetails(page: Page) {
|
|
await page.getByRole("button", { name: "Close workspace details", exact: true }).click();
|
|
await expect(
|
|
page.getByRole("button", { name: "Close workspace details", exact: true }),
|
|
).toHaveCount(0);
|
|
}
|
|
|
|
export async function withButtonAuthorExample(
|
|
page: Page,
|
|
info: TestInfo,
|
|
run: (buttons: {
|
|
refreshFromHeaderAndComposer(): Promise<void>;
|
|
useMenusAndToggleButtons(): Promise<void>;
|
|
inspectLiveWorkspaceDetails(): Promise<void>;
|
|
}) => Promise<void>,
|
|
) {
|
|
const workspace = await seedWorkspace({
|
|
repoPrefix: "button-example-",
|
|
title: "Button examples",
|
|
});
|
|
const agent = await workspace.client.createAgent({
|
|
provider: "mock",
|
|
cwd: workspace.repoPath,
|
|
workspaceId: workspace.workspaceId,
|
|
title: "Example agent",
|
|
model: "ten-second-stream",
|
|
modeId: "load-test",
|
|
});
|
|
const client = await connectNewWorkspaceDaemonClient({ ownProjects: false });
|
|
const config = await client.getDaemonConfig();
|
|
const example = await copyPluginExample("buttons");
|
|
try {
|
|
await client.patchDaemonConfig({ pluginsEnabled: true });
|
|
await client.installDirectoryPlugin(example.directory);
|
|
await page.setViewportSize(WIDE);
|
|
await gotoAppShell(page);
|
|
await page.goto(buildAgentRoute(workspace.workspaceId, agent.id));
|
|
|
|
await run({
|
|
refreshFromHeaderAndComposer: () =>
|
|
test.step("icon-only header action and labeled composer action update in place", async () => {
|
|
await exampleCommand(page, "action");
|
|
await expect(headerButtons(page)).toHaveCount(1);
|
|
await headerButtons(page).click();
|
|
await expect(headerButtons(page)).toHaveAccessibleName("Refresh workspace (1)");
|
|
await page.getByRole("button", { name: "Refresh context", exact: true }).click();
|
|
await expect(
|
|
page.getByRole("button", { name: "Refresh context", exact: true }),
|
|
).toContainText("Refreshed · 2");
|
|
await capture(page, info, "01-actions");
|
|
await page.setViewportSize(COMPACT);
|
|
await expect(headerButtons(page)).toHaveCount(0);
|
|
await capture(
|
|
page,
|
|
info,
|
|
"02-compact-actions",
|
|
page.getByRole("button", { name: "Refresh context", exact: true }),
|
|
);
|
|
}),
|
|
useMenusAndToggleButtons: () =>
|
|
test.step("named menus include separators, nested actions, disabled items, and custom content", async () => {
|
|
await exampleCommand(page, "menu");
|
|
await headerButtons(page).click();
|
|
await expect(
|
|
page.getByRole("menuitem", { name: "Publish (unavailable in example)", exact: true }),
|
|
).toBeDisabled();
|
|
await capture(
|
|
page,
|
|
info,
|
|
"03-header-menu",
|
|
page.getByRole("menuitem", { name: "Refresh workspace", exact: true }),
|
|
);
|
|
await page.getByRole("menuitem", { name: "Workspace details", exact: true }).click();
|
|
await expect(page.getByText("Button examples", { exact: true }).last()).toBeVisible();
|
|
await closeDetails(page);
|
|
await page.getByRole("button", { name: "Composer tools", exact: true }).click();
|
|
await capture(
|
|
page,
|
|
info,
|
|
"04-composer-menu",
|
|
page.getByRole("menuitem", { name: "Refresh workspace", exact: true }),
|
|
);
|
|
await page.getByRole("menuitem", { name: "Display", exact: true }).click();
|
|
await page.getByRole("menuitem", { name: "Hide example buttons", exact: true }).click();
|
|
await expect(headerButtons(page)).toHaveCount(0);
|
|
await expect(
|
|
page.getByRole("button", { name: "Composer tools", exact: true }),
|
|
).toHaveCount(0);
|
|
await exampleCommand(page, "show");
|
|
await exampleCommand(page, "disable");
|
|
await expect(headerButtons(page)).toBeDisabled();
|
|
await expect(
|
|
page.getByRole("button", { name: "Composer tools", exact: true }),
|
|
).toBeDisabled();
|
|
await capture(page, info, "05-disabled");
|
|
await exampleCommand(page, "enable");
|
|
await page.setViewportSize(COMPACT);
|
|
await expect(headerButtons(page)).toHaveCount(0);
|
|
await page.getByRole("button", { name: "Composer tools", exact: true }).click();
|
|
await expect(
|
|
page.getByRole("menuitem", { name: "Refresh workspace", exact: true }),
|
|
).toBeInViewport();
|
|
await capture(
|
|
page,
|
|
info,
|
|
"06-compact-menu",
|
|
page.getByRole("menuitem", { name: "Refresh workspace", exact: true }),
|
|
);
|
|
await page.getByRole("menuitem", { name: "Refresh workspace", exact: true }).click();
|
|
}),
|
|
inspectLiveWorkspaceDetails: () =>
|
|
test.step("custom icons and content react to workspace changes and adapt to sheets", async () => {
|
|
await exampleCommand(page, "popover");
|
|
await expect(headerButtons(page)).toHaveCount(1);
|
|
await headerButtons(page).click();
|
|
await expect(
|
|
page.getByRole("button", { name: "Close workspace details", exact: true }),
|
|
).toBeVisible();
|
|
await capture(
|
|
page,
|
|
info,
|
|
"07-header-popover",
|
|
page.getByRole("button", { name: "Close workspace details", exact: true }),
|
|
);
|
|
await client.setWorkspaceTitle(workspace.workspaceId, "Renamed from the daemon");
|
|
await expect(
|
|
page.getByText("Renamed from the daemon", { exact: true }).last(),
|
|
).toBeVisible();
|
|
await closeDetails(page);
|
|
await page.getByRole("button", { name: "Context details", exact: true }).click();
|
|
await capture(
|
|
page,
|
|
info,
|
|
"08-composer-popover",
|
|
page.getByRole("button", { name: "Close workspace details", exact: true }),
|
|
);
|
|
await closeDetails(page);
|
|
await page.setViewportSize(COMPACT);
|
|
await page.getByRole("button", { name: "Context details", exact: true }).click();
|
|
await expect(
|
|
page.getByRole("button", { name: "Close workspace details", exact: true }),
|
|
).toBeInViewport();
|
|
await capture(
|
|
page,
|
|
info,
|
|
"09-compact-popover",
|
|
page.getByRole("button", { name: "Close workspace details", exact: true }),
|
|
);
|
|
await closeDetails(page);
|
|
await client.disablePlugin("button-examples");
|
|
await expect(headerButtons(page)).toHaveCount(0);
|
|
await expect(
|
|
page.getByRole("button", { name: "Context details", exact: true }),
|
|
).toHaveCount(0);
|
|
}),
|
|
});
|
|
} finally {
|
|
await client.removePlugin("button-examples");
|
|
await client.patchDaemonConfig({ pluginsEnabled: config.config.pluginsEnabled });
|
|
await client.close();
|
|
await example.cleanup();
|
|
await workspace.cleanup();
|
|
}
|
|
}
|