import { expect, test, type Page } from "@playwright/test"; // P3 exit criterion (spec §17): every Computer-panel app is navigable and // deep-linkable, with per-agent theming, against real backend data. const OWNER_EMAIL = "owner@acme.test"; const OWNER_PASSWORD = "e2e-password"; async function signIn(page: Page) { await page.goto("/login"); await page.getByLabel("Email address").fill(OWNER_EMAIL); await page.getByLabel("Password").fill(OWNER_PASSWORD); await page.getByRole("button", { name: "Sign in" }).click(); await page.waitForURL((url) => !url.pathname.endsWith("/login"), { timeout: 15000 }); } async function openScout(page: Page) { await page.getByRole("link", { name: /Scout/ }).click(); await expect(page).toHaveURL(/\/claws\/.+\/chat\//); } async function sendMessage(page: Page, text: string) { const box = page.getByLabel("Message Scout"); await box.fill(text); await box.press("Enter"); } test("the computer opens to the themed home screen with grid and dock", async ({ page, }) => { await signIn(page); await openScout(page); await page.getByRole("button", { name: "Computer" }).click(); const panel = page.getByRole("complementary", { name: "Computer" }); await expect(panel.getByText(/Scout's Computer/)).toBeVisible(); await expect(panel.getByRole("button", { name: "Files" })).toBeVisible(); await expect(panel.getByRole("button", { name: "Settings" })).toBeVisible(); await expect(page).toHaveURL(/app=home/); // Per-agent theming: the wallpaper var derives from the agent accent. const themed = panel.getByTestId("device-panel-theme"); await expect(themed).toHaveAttribute("style", /--agent-accent/); // Size toggle flips ?device=. await page.getByRole("radio", { name: "Phone" }).click(); await expect(page).toHaveURL(/device=phone/); }); test("agent-written files appear in the Files app", async ({ page }) => { await signIn(page); await openScout(page); await sendMessage(page, "save the report [[scenario:save-report]]"); await expect(page.getByText(/Saved the report/)).toBeVisible(); await page.getByRole("button", { name: "Computer" }).click(); const panel = page.getByRole("complementary", { name: "Computer" }); await panel.getByRole("button", { name: "Files" }).click(); await panel.getByRole("button", { name: /My Documents/ }).click(); await expect(panel.getByText("reports/q2.md")).toBeVisible(); }); test("agent-scheduled routines appear in the Routines app", async ({ page, }) => { await signIn(page); await openScout(page); await sendMessage(page, "every morning [[scenario:schedule-digest]]"); await expect(page.getByText(/Scheduled the morning digest/)).toBeVisible(); await page.getByRole("button", { name: "Computer" }).click(); const panel = page.getByRole("complementary", { name: "Computer" }); await panel.getByRole("button", { name: "Routines" }).click(); await expect(panel.getByText("Morning digest")).toBeVisible(); await expect(panel.getByText(/0 9 \* \* \*/)).toBeVisible(); }); test("settings edits the system prompt and persists", async ({ page }) => { await signIn(page); await openScout(page); await page.getByRole("button", { name: "Computer" }).click(); const panel = page.getByRole("complementary", { name: "Computer" }); await panel.getByRole("button", { name: "Settings" }).click(); await expect(panel.getByText("Managed by")).toBeVisible(); await panel.getByRole("button", { name: /Edit profile/ }).click(); const description = panel.getByLabel(/Job description/); await description.fill("Research carefully and cite sources."); await panel.getByRole("button", { name: "Save profile" }).click(); await expect(panel.getByText("Managed by")).toBeVisible(); // Persisted: reopen settings cold (deep link) and check the textarea. await page.reload(); const reopened = page.getByRole("complementary", { name: "Computer" }); await reopened.getByRole("button", { name: /Edit profile/ }).click(); await expect(reopened.getByLabel(/Job description/)).toHaveValue( "Research carefully and cite sources.", ); }); test("every panel app is reachable and the deep link cold-loads", async ({ page, }) => { await signIn(page); await openScout(page); // Deep link with app + device cold-loads the open panel. const url = new URL(page.url()); url.searchParams.set("app", "settings"); url.searchParams.set("device", "full"); await page.goto(url.toString()); const panel = page.getByRole("complementary", { name: "Computer" }); await expect(panel.getByText("Managed by")).toBeVisible(); // Walk through the remaining apps via the home screen. const stops: [string, RegExp][] = [ ["Browser", /No active browsing session/], ["Slack", /Bring this claw into Slack/], ["Claw Chat", /No claw-to-claw conversations yet/], ["Add Apps", /Connect with an API key/], ["Skills", /Scout's Skills|Installed skills/], ]; for (const [tile, marker] of stops) { await panel.getByRole("button", { name: "Close" }).click(); await panel.getByRole("button", { name: tile, exact: true }).click(); await expect(panel.getByText(marker).first()).toBeVisible(); } // Inline keys connect from the directory (P4): Notion via API key. await panel.getByRole("button", { name: "Close" }).click(); await panel.getByRole("button", { name: "Add Apps", exact: true }).click(); await panel.getByRole("button", { name: "Connect Notion" }).click(); await panel.getByLabel("Notion API key").fill("secret_notion_key"); await panel.getByRole("button", { name: "Connect", exact: true }).click(); await expect(panel.getByText("✓ Connected")).toBeVisible(); }); test("the skill library page lists skills and installs onto a claw", async ({ page, }) => { await signIn(page); await page.getByRole("link", { name: "Skills", exact: true }).click(); await expect( page.getByRole("heading", { name: "Skill Library" }), ).toBeVisible(); await expect(page.getByText("Daily briefing")).toBeVisible(); // Install from the claw's Skills app. await page.getByRole("link", { name: /Scout/ }).click(); await page.getByRole("button", { name: "Computer" }).click(); const panel = page.getByRole("complementary", { name: "Computer" }); await panel.getByRole("button", { name: "Skills" }).click(); await panel.getByRole("button", { name: "Add Skill" }).click(); await panel.getByRole("button", { name: /Install Daily briefing/ }).click(); await expect(panel.getByText("Daily briefing")).toBeVisible(); });