Files
paseo/packages/app/e2e/support/helpers/import-session.ts
T
Mohamed Boudra e939dd4c7a Streamline sidebar usage and stacked sheet interactions (#5805)
* feat(app): streamline sidebar usage and stacked sheets

* fix(app): restore compact sidebar navigation clicks

The close button container emitted box-none through Unistyles as invalid CSS and intercepted New workspace clicks. Let React Native apply click-through behavior at the view boundary. Keep the import journey on its existing New workspace screen and assert only the visible transcript.

* fix(app): cap menu sheets at eighty percent height

Keep long sidebar usage reports recognizably sheet-sized while allowing the content to scroll. Short menu sheets retain dynamic sizing.
2026-10-01 04:55:17 +01:00

163 lines
7.2 KiB
TypeScript

import { expect, type Page } from "@playwright/test";
import { buildHostWorkspaceRoute } from "@/utils/host-routes";
import { gotoAppShell } from "./app";
import { openCommandCenter } from "./command-center";
import { openGlobalNewWorkspaceComposer } from "./new-workspace";
import { getServerId } from "./server-id";
import { expectMobileAgentSidebarVisible, openMobileAgentSidebar } from "./sidebar";
const rowTestId = (id: string) => `import-session-session-claude-${id}`;
const rowFolderTestId = (id: string) => `import-session-row-folder-claude-${id}`;
export class ImportSessionFlow {
constructor(private readonly page: Page) {}
async openWorkspace(workspaceId: string, viewport: { width: number; height: number }) {
await this.page.setViewportSize(viewport);
await gotoAppShell(this.page);
await this.page.goto(buildHostWorkspaceRoute(getServerId(), workspaceId));
await expect(this.page.getByRole("button", { name: "Workspace actions" })).toBeVisible({
timeout: 30_000,
});
}
/** The new workspace screen's Import session button, reached from the sidebar. */
async revealNewWorkspaceEntryPoint() {
const compact = (this.page.viewportSize()?.width ?? 0) < 768;
if (compact) {
await openMobileAgentSidebar(this.page);
await expectMobileAgentSidebarVisible(this.page);
}
await openGlobalNewWorkspaceComposer(this.page);
const button = this.page.getByTestId("new-workspace-import-session");
await expect(button).toHaveAccessibleName("Import session");
await expect(button).toBeInViewport();
}
async openGlobally() {
await this.revealNewWorkspaceEntryPoint();
await this.openFromNewWorkspace();
}
async openFromNewWorkspace() {
await this.page.getByTestId("new-workspace-import-session").click();
await this.expectSheetReady();
}
async openFromWorkspaceHeader() {
await this.page.getByRole("button", { name: "Workspace actions" }).click();
await this.page.getByTestId("workspace-header-import-agent").click();
await this.expectScope("This workspace");
await expect(this.page.getByTestId("import-session-show-all")).toBeVisible();
await expect(this.page.getByText("Workspace actions", { exact: true })).not.toBeVisible();
}
async expectScope(text: string, exact = true) {
const scope = this.page.getByTestId("import-session-scope");
if (exact) await expect(scope).toHaveText(text);
else await expect(scope).toContainText(text);
await expect(scope).toBeVisible();
}
async expectRows(input: {
first?: string[];
before?: [string, string];
folders?: Array<[string, string]>;
}) {
for (const id of input.first ?? input.before ?? []) {
await expect(this.page.getByTestId(rowTestId(id))).toHaveCount(1);
}
const ids = await this.rowIds();
if (input.first) expect(ids.slice(0, input.first.length)).toEqual(input.first.map(rowTestId));
if (input.before) {
expect(ids.indexOf(rowTestId(input.before[0]))).toBeGreaterThanOrEqual(0);
expect(ids.indexOf(rowTestId(input.before[0]))).toBeLessThan(
ids.indexOf(rowTestId(input.before[1])),
);
}
for (const [id, folder] of input.folders ?? []) {
await expect(this.page.getByTestId(rowFolderTestId(id))).toHaveText(folder);
}
}
async expectProviderError(label: string) {
await expect(this.page.getByTestId("import-session-provider-errors")).toContainText(
`Could not load ${label} sessions`,
);
}
async expectProviderFilterFits(width: number) {
await expect(this.page.getByTestId("import-session-scope")).toBeInViewport();
const filter = this.page.getByRole("button", { name: "Filter: All" });
await expect(filter).toBeInViewport();
const bounds = await filter.boundingBox();
expect(bounds?.x ?? width).toBeGreaterThanOrEqual(0);
expect((bounds?.x ?? width) + (bounds?.width ?? 1)).toBeLessThanOrEqual(width);
}
async revealSession(id: string) {
await this.page.getByTestId(rowTestId(id)).scrollIntoViewIfNeeded();
}
async search(query: string) {
await this.page.getByTestId("import-session-search").fill(query);
await expect(this.page.getByText("Invoice migration plan", { exact: true })).toBeVisible();
await expect(this.page.getByText("Root session 01", { exact: true })).toHaveCount(0);
await expect(this.page.getByTestId("import-session-load-more")).toHaveCount(0);
}
async resetSearch() {
await this.page.getByTestId("import-session-search").fill("");
await expect(this.page.getByTestId("import-session-load-more")).toBeVisible();
}
async loadMore() {
await this.page.getByTestId("import-session-load-more").click();
await expect(this.page.getByText("Root session 20", { exact: true })).toBeVisible();
await expect(this.page.getByTestId("import-session-load-more")).toHaveCount(0);
}
async retryProvider(provider: string, label: string) {
await this.expectProviderError(label);
await this.page.getByTestId(`import-session-retry-${provider}`).click();
await expect(this.page.getByTestId(`import-session-retry-${provider}`)).toBeEnabled();
await this.expectProviderError(label);
await expect(this.page.getByRole("progressbar")).toHaveCount(0);
}
async importSession(id: string) {
await this.page.getByTestId(rowTestId(id)).click();
await expect(this.page.getByTestId("import-session-sheet")).toHaveCount(0, {
timeout: 30_000,
});
}
async expectTranscript(userText: string, assistantText: string) {
await expect(this.page.getByTestId("user-message").filter({ visible: true })).toContainText(
userText,
);
await expect(
this.page.getByTestId("assistant-message").filter({ visible: true }),
).toContainText(assistantText);
}
async showAll() {
await this.page.getByTestId("import-session-show-all").click();
await expect(this.page.getByTestId("import-session-scope")).toContainText("Sessions on");
}
async expectImportedIntoWorkspace(workspaceId: string, userText: string) {
await expect(this.page).toHaveURL(buildHostWorkspaceRoute(getServerId(), workspaceId), {
timeout: 30_000,
});
const workspace = this.page.getByTestId(`workspace-deck-entry-${getServerId()}:${workspaceId}`);
await expect(workspace.getByTestId("user-message").filter({ visible: true })).toContainText(
userText,
);
}
async close() {
await this.page.keyboard.press("Escape");
await expect(this.page.getByTestId("import-session-sheet")).toHaveCount(0);
}
async expectCommandCenterMatch() {
const panel = await openCommandCenter(this.page);
await panel.getByTestId("command-center-input").fill("import");
await expect(panel.getByText("Import session", { exact: true })).toBeVisible();
await expect(panel.getByText("Home", { exact: true })).toHaveCount(0);
}
private async expectSheetReady() {
const sheet = this.page.getByTestId("import-session-sheet");
await expect(sheet).toBeVisible({ timeout: 30_000 });
await expect(sheet.getByText("Loading sessions...", { exact: true })).toHaveCount(0, {
timeout: 30_000,
});
}
private async rowIds() {
return await this.page
.locator('[data-testid^="import-session-session-claude-"]')
.evaluateAll((nodes) => nodes.map((node) => node.getAttribute("data-testid")));
}
}