62 lines
3.1 KiB
JavaScript
62 lines
3.1 KiB
JavaScript
// Uses an isolated browser and mocked API; no model requests or existing profile.
|
|
import { chromium } from "../tools/playwright/node_modules/playwright/index.mjs";
|
|
import assert from "node:assert/strict";
|
|
|
|
const browser = await chromium.launch({ headless: true });
|
|
try {
|
|
const page = await browser.newPage();
|
|
page.setDefaultTimeout(8000);
|
|
await page.addInitScript(() => localStorage.setItem("lazyboy.locale", "zh-Hant"));
|
|
page.on("pageerror", (e) => console.error(e.message));
|
|
let state = "running";
|
|
let disconnected = false;
|
|
const activity = () => ({
|
|
state, running: state === "running", queued: state === "queued",
|
|
active_task_ids: state === "running" ? ["task"] : [],
|
|
observed_at_ms: Date.now(),
|
|
question: state === "waiting_input" ? { question: "請確認資料", options: ["完成"] } : null,
|
|
});
|
|
await page.route("**/api/**", async (route) => {
|
|
const path = new URL(route.request().url()).pathname;
|
|
if (path.endsWith("/activity")) {
|
|
if (disconnected) return route.abort("connectionfailed");
|
|
return route.fulfill({ json: activity() });
|
|
}
|
|
if (path.endsWith("/events")) {
|
|
// Stale "working" events must not override an authoritative idle snapshot.
|
|
return route.fulfill({ contentType: "text/event-stream",
|
|
body: 'data: {"events":[{"id":1,"kind":"runtime","payload":{"type":"waiting"}}]}\n\n' });
|
|
}
|
|
if (path === "/api/agents") return route.fulfill({ json: {
|
|
agents: [{ id: "owner", name: "測試", running: true }],
|
|
} });
|
|
if (path === "/api/agents/owner") return route.fulfill({ json: {
|
|
id: "owner", name: "測試", expertise: "", preview: "",
|
|
transcript: [], running: true, activity: activity(),
|
|
} });
|
|
return route.fulfill({ json: {} });
|
|
});
|
|
await page.goto(process.env.LAZYBOY_TEST_UI_URL || "http://127.0.0.1:5173");
|
|
await page.locator(".thinking-row .avatar.thinking").waitFor().catch(async (e) => { console.error(await page.locator("body").innerText()); throw e; });
|
|
state = "idle";
|
|
await page.waitForFunction(() => !document.querySelector(".thinking-row .avatar.thinking"), { timeout: 6000 });
|
|
assert.equal(await page.locator(".working-label").count(), 0);
|
|
state = "queued";
|
|
await page.locator(".working-label").waitFor();
|
|
assert.equal(await page.locator(".thinking-row .avatar.thinking").count(), 0);
|
|
state = "waiting_input";
|
|
await page.getByText("請確認資料", { exact: true }).waitFor();
|
|
assert.equal(await page.locator(".working-label").count(), 0);
|
|
state = "running";
|
|
await page.locator(".thinking-row .avatar.thinking").waitFor();
|
|
disconnected = true;
|
|
await page.waitForFunction(() => !document.querySelector(".thinking-row .avatar.thinking"), { timeout: 6000 });
|
|
await page.getByText("暫時無法確認工作狀態,正在重新連線。", { exact: true }).waitFor();
|
|
disconnected = false;
|
|
state = "idle";
|
|
await page.getByText("暫時無法確認工作狀態,正在重新連線。", { exact: true }).waitFor({ state: "hidden" });
|
|
console.log("PASS running/idle/queued/question/disconnect/reconnect; stale events and roster do not keep animation alive");
|
|
} finally {
|
|
await browser.close();
|
|
}
|