127 lines
5.3 KiB
JavaScript
127 lines
5.3 KiB
JavaScript
|
|
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();
|
||
|
|
}
|