The live screen opens wide beside the chat while the bot works on it or asks for a takeover, 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. Shared core rules derive the focus from signals clients already have (pointer events, takeover requests, a new `present` flag on attach_file, pending asks), move the pane only on focus edges, never replace a pane the user opened, and learn per bot whether the screen opens on its own. Pane widths persist per device; mobile shows a pill that opens the computer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C7VSRHHzyt2KwoCkUkZ2Gc
68 lines
2.9 KiB
TypeScript
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();
|
|
});
|