import { chromium } from "../tools/playwright/node_modules/playwright/index.mjs"; import assert from "node:assert/strict"; import { mkdirSync } from "node:fs"; const outDir = "/tmp/lazyboy2-settings-ui"; mkdirSync(outDir, { recursive: true }); const browser = await chromium.launch({ headless: true }); try { const context = await browser.newContext({ locale: "zh-TW", ignoreHTTPSErrors: true }); await context.grantPermissions(["clipboard-read", "clipboard-write"]); const page = await context.newPage(); page.setDefaultTimeout(8000); await page.addInitScript(() => { localStorage.setItem("lazyboy.locale", "zh-Hant"); localStorage.setItem("lazyboy.theme", "dark"); }); await page.emulateMedia({ colorScheme: "dark" }); page.on("pageerror", (e) => console.error(e.message)); await page.route("**/api/**", async (route) => { const path = new URL(route.request().url()).pathname; if (path === "/api/agents") { return route.fulfill({ json: { agents: [{ id: "owner", name: "測試", running: false }] } }); } if (path === "/api/agents/owner") { return route.fulfill({ json: { id: "owner", name: "測試", expertise: "", preview: "", transcript: [], running: false, activity: { state: "idle", running: false, queued: false, active_task_ids: [], observed_at_ms: Date.now() }, }, }); } if (path.endsWith("/activity")) { return route.fulfill({ json: { state: "idle", running: false, queued: false, active_task_ids: [], observed_at_ms: Date.now() }, }); } if (path.endsWith("/events")) { return route.fulfill({ contentType: "text/event-stream", body: "data: {\"events\":[]}\n\n" }); } if (path.endsWith("/computer")) { return route.fulfill({ json: { ready: true, state: "ready", viewer_url: "/fixture-viewer" } }); } return route.fulfill({ json: {} }); }); await page.goto(process.env.LAZYBOY_TEST_UI_URL || "http://127.0.0.1:5173"); await page.locator(".account").click(); await page.getByRole("menuitem", { name: "設定" }).waitFor(); await page.getByRole("menuitem", { name: "關於" }).waitFor(); await page.screenshot({ path: `${outDir}/menu.png` }); await page.getByRole("menuitem", { name: "設定" }).click(); const settings = page.locator(".lb-settings-dialog"); await settings.waitFor(); assert.equal(await page.locator(".lb-settings-nav__item").count(), 2); await page.getByRole("button", { name: "一般" }).waitFor(); await page.getByText("本機工作區", { exact: true }).first().waitFor(); await page.screenshot({ path: `${outDir}/settings-general.png` }); await page.getByLabel("主題").selectOption("light"); assert.equal(await page.locator("html").getAttribute("data-theme"), "light"); await page.screenshot({ path: `${outDir}/settings-general-light.png` }); await page.getByLabel("主題").selectOption("dark"); assert.equal(await page.locator("html").getAttribute("data-theme"), "dark"); await page.locator(".lb-settings-nav__item", { hasText: "更新" }).click(); await page.getByText("LazyBoy 0.1.0").waitFor(); await page.locator(".lb-settings-row").filter({ hasText: "更新電腦" }).getByRole("button", { name: "更新" }).waitFor(); await page.locator(".lb-settings-row").filter({ hasText: "重啟電腦" }).getByRole("button", { name: "重啟" }).waitFor(); assert.equal(await page.locator(".computer-part .computer-actions").count(), 0); await page.locator(".computer-caption .outline", { hasText: "放大" }).waitFor(); await page.screenshot({ path: `${outDir}/settings-updates.png` }); await page.locator(".lb-settings-close").click(); await settings.waitFor({ state: "hidden" }); await page.locator(".account").click(); await page.getByRole("menuitem", { name: "關於" }).click(); const about = page.locator(".lb-about-dialog"); await about.waitFor(); await about.getByRole("heading", { name: "LazyBoy" }).waitFor(); await about.getByText("版本 0.1.0").waitFor(); await about.getByText("Copyright © 2026 Daniel Wang").waitFor(); await page.waitForFunction(() => { const img = document.querySelector(".lb-about-icon img"); return img instanceof HTMLImageElement && img.complete && img.naturalWidth > 0; }); await page.screenshot({ path: `${outDir}/about.png` }); await about.getByRole("button", { name: "複製版本資訊" }).click(); await about.getByRole("button", { name: "已複製" }).waitFor(); const copied = await page.evaluate(() => navigator.clipboard.readText()); assert.match(copied, /Version: 0\.1\.0/); await page.locator(".lb-about-close").click(); await about.waitFor({ state: "hidden" }); await page.setViewportSize({ width: 390, height: 844 }); await page.locator(".mobile-menu").click(); await page.locator(".sidebar.open .account").click(); await page.getByRole("menuitem", { name: "設定" }).click(); await settings.waitFor(); await page.screenshot({ path: `${outDir}/settings-mobile.png` }); console.log("PASS settings and about overlays"); } finally { await browser.close(); }