/** * Headed visual walkthrough — opens Chromium (headless: false) so you can watch. * * npm run test:visual */ import { chromium } from "playwright"; import { spawn } from "node:child_process"; import { setTimeout as sleep } from "node:timers/promises"; const PORT = 1420; const BASE = `http://127.0.0.1:${PORT}/visual.html`; async function portOpen(port) { try { const res = await fetch(`http://127.0.0.1:${port}/visual.html`); return res.status < 500; } catch { return false; } } async function ensureVite() { if (await portOpen(PORT)) return null; const child = spawn("npm", ["run", "dev", "--", "--host", "127.0.0.1"], { cwd: process.cwd(), stdio: "ignore", detached: true, }); for (let i = 0; i < 40; i++) { await sleep(250); if (await portOpen(PORT)) return child; } throw new Error("Vite did not start on :1420"); } async function main() { const vite = await ensureVite(); console.log("Opening headed Chromium — watch the window…\n"); const browser = await chromium.launch({ headless: false, slowMo: 400, }); const page = await browser.newPage({ viewport: { width: 480, height: 640 } }); await page.goto(BASE, { waitUntil: "networkidle" }); // 1) Show banner await page.waitForSelector('[data-testid="banner"]'); await sleep(800); // 2) Type in search const input = page.getByPlaceholder("Search…"); await input.click(); await input.fill("Meeting"); await sleep(900); await input.fill(""); await sleep(500); // 3) Hover / focus list rows await page.getByText("Meeting notes").hover(); await sleep(600); // 4) Open context menu + Paste plain await page.getByTestId("open-menu").click(); await sleep(700); await page.getByText("Paste plain").click(); await sleep(1000); // 5) Click redacted password row (pastes full secret into banner) await page.getByText("(password)").click({ modifiers: [] }); await sleep(1200); // 6) Alt-click card row for plain await page.getByText("(card)").click({ modifiers: ["Alt"] }); await sleep(1200); // 7) Show transform menu → Pretty JSON not relevant; show uppercase on meeting await page.getByText("Meeting notes").click({ button: "right" }); await sleep(600); await page.getByText("UPPERCASE").click(); await sleep(1500); const banner = await page.getByTestId("banner").innerText(); console.log("Final banner:", banner); console.log("\nLeaving the window open for 5s so you can look…"); await sleep(5000); await browser.close(); if (vite) { try { process.kill(-vite.pid); } catch { /* ignore */ } } console.log("Visual walkthrough finished."); } main().catch((err) => { console.error(err); process.exit(1); });