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-agent-profile-ui"; mkdirSync(outDir, { recursive: true }); const owner = { id: "owner", name: "測試", title: "市場研究員", description: "用白話講研究結果", tags: ["研究"], avatar_color: "#08A99D", avatar_shape: "round", expertise: "市場研究員 — 研究 — 用白話講研究結果", preview: "任務結束了", running: false, }; const agents = [owner]; let patched = null; let created = null; const browser = await chromium.launch({ headless: true }); try { const context = await browser.newContext({ locale: "zh-TW" }); 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 req = route.request(); const path = new URL(req.url()).pathname; if (path === "/api/agents" && req.method() === "GET") { return route.fulfill({ json: { agents } }); } if (path === "/api/agents" && req.method() === "POST") { created = JSON.parse(req.postData() || "{}"); const row = { id: "newbie", preview: "新對話", running: false, ...created }; agents.unshift(row); return route.fulfill({ json: row }); } const agentMatch = path.match(/^\/api\/agents\/([^/]+)$/); if (agentMatch && req.method() === "PATCH") { patched = JSON.parse(req.postData() || "{}"); const current = agents.find((row) => row.id === agentMatch[1]) || owner; Object.assign(current, patched); return route.fulfill({ json: current }); } if (agentMatch && req.method() === "GET") { const current = agents.find((row) => row.id === agentMatch[1]) || owner; return route.fulfill({ json: { ...current, transcript: current.id === "owner" ? [ { role: "user", content: "幫我查一下", at: new Date().toISOString() }, { role: "assistant", content: "任務結束了", at: new Date().toISOString() }, ] : [], 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" }); } return route.fulfill({ json: {} }); }); await page.goto(process.env.LAZYBOY_TEST_UI_URL || "http://127.0.0.1:5173"); const row = page.locator(".bot-row").filter({ hasText: "測試" }); await row.waitFor(); assert.match(await row.locator("small").innerText(), /任務結束了/); assert.equal(await row.locator(".bot-tag").innerText(), "研究"); await page.screenshot({ path: `${outDir}/sidebar.png` }); await row.click({ button: "right" }); await page.getByRole("menuitem", { name: "Agent 設定" }).click(); const dialog = page.locator(".settings-dialog"); await dialog.waitFor(); await dialog.getByLabel("名稱").waitFor(); assert.equal(await dialog.locator(".shape-grid button").count(), 0); await dialog.locator(".avatar-hit").click(); assert.equal(await dialog.locator(".shape-grid button").count(), 8); await dialog.getByRole("tab", { name: "上傳" }).waitFor(); await dialog.locator(".dialog-title").click(); await dialog.getByLabel("名稱").waitFor(); assert.equal(await dialog.locator(".shape-grid button").count(), 0); await dialog.locator("textarea").fill("用更短的句子回答"); await dialog.getByRole("button", { name: "儲存" }).click(); await dialog.waitFor({ state: "hidden" }); assert.equal(patched?.description, "用更短的句子回答"); assert.equal(patched?.name, "測試"); await page.screenshot({ path: `${outDir}/saved.png` }); await page.locator(".create-menu-wrap .icon-button").click(); await page.getByRole("menuitem", { name: "新增 Agent" }).click(); const create = page.locator(".settings-dialog"); const createBtn = create.getByRole("button", { name: "建立" }); assert.equal(await createBtn.isDisabled(), true); await create.getByLabel("名稱").fill("小研"); assert.equal(await createBtn.isDisabled(), true); await create.getByLabel("描述").fill("用白話講研究結果"); await create.getByLabel("標題").fill("市場研究員"); await create.getByLabel("標籤(選填)").fill("研究"); await createBtn.click(); await create.waitFor({ state: "hidden" }); assert.equal(created?.name, "小研"); assert.equal(created?.description, "用白話講研究結果"); assert.equal(created?.title, "市場研究員"); assert.deepEqual(created?.tags, ["研究"]); await page.locator(".bot-row").filter({ hasText: "小研" }).waitFor(); await page.screenshot({ path: `${outDir}/created.png` }); console.log("agent_profile_ui ok"); } finally { await browser.close(); }