evOo-local/apps/web/e2e/artifact-preview.spec.ts
Claude 065b1322bb
feat: let the pane beside a conversation follow the bot's work
The live screen now opens wide beside the chat while the bot works on it,
a file the bot presents as its result opens next to the conversation, and a
question that scrolled away gets a "Needs you" pill back to it. Focus is
derived from signals clients already have (pointer events, takeover
requests, a new `present` flag on attach_file, pending asks) by shared core
rules, so web and mobile agree and the behaviour stays deterministic.

The pane only moves on focus edges, never replaces a pane the user opened,
and learns per bot whether the screen should open on its own. Pane widths
persist per device. Mobile shows a pill that opens the computer route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7VSRHHzyt2KwoCkUkZ2Gc
2026-10-03 18:30:39 +00:00

68 lines
2.9 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { captureScreenshot, completeOnboarding, signup } from "./helpers";
test.describe.configure({ mode: "serial" });
test("agent-attached files appear as downloadable cards", async ({ page }, testInfo) => {
const stamp = Date.now();
await signup(page, `artifact-card-${stamp}@rakazo.test`, "password12", "Artifact Card");
await completeOnboarding(page);
const composer = page.getByPlaceholder(/Message/);
await composer.fill("write notes/result.txt and attach it to the thread");
await page.keyboard.press("Enter");
// Scope to ArtifactFileCard text (name + mime); sidebar bot status can also
// include the prompt path notes/result.txt once status syncs immediately.
const fileCard = page.getByRole("button", { name: /result\.txt text\/plain/ });
await expect(fileCard).toBeVisible({ timeout: 30_000 });
await captureScreenshot(page, testInfo, "current-file-card");
const downloadPromise = page.waitForEvent("download");
await fileCard.click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe("result.txt");
});
test("agent-attached Markdown opens a rendered preview and can be downloaded", async ({
page,
}, testInfo) => {
// Narrow windows preview in a dialog; wide ones open the file beside the chat.
await page.setViewportSize({ width: 900, height: 800 });
const stamp = Date.now();
await signup(page, `markdown-preview-${stamp}@rakazo.test`, "password12", "Markdown Preview");
await completeOnboarding(page);
const composer = page.getByPlaceholder(/Message/);
await composer.fill(
"write path notes/preview.md and attach it to the thread says # Project preview",
);
await page.keyboard.press("Enter");
const previewButton = page.getByRole("button", { name: "Preview preview.md" });
await expect(previewButton).toBeVisible({ timeout: 30_000 });
await captureScreenshot(page, testInfo, "markdown-file-card");
await previewButton.click();
const dialog = page.getByRole("dialog", { name: "preview.md" });
await expect(dialog).toBeVisible();
await expect(dialog.getByRole("heading", { name: "Project preview" })).toBeVisible();
const closeButton = dialog.getByRole("button", { name: "Close preview" });
const downloadButton = dialog.getByRole("button", { name: "Download preview.md" });
await expect(closeButton).toBeFocused();
await page.keyboard.press("Tab");
await expect(downloadButton).toBeFocused();
await page.keyboard.press("Shift+Tab");
await expect(closeButton).toBeFocused();
await captureScreenshot(page, testInfo, "markdown-preview-open");
const downloadPromise = page.waitForEvent("download");
await downloadButton.click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe("preview.md");
await page.keyboard.press("Escape");
await expect(dialog).toHaveCount(0);
await expect(previewButton).toBeFocused();
});