| 1 | import assert from "node:assert/strict"; |
| 2 | import path from "node:path"; |
| 3 | import { fileURLToPath } from "node:url"; |
| 4 | import { createServer } from "vite"; |
| 5 | import { newSessionButton } from "./app-page-actions.mjs"; |
| 6 | |
| 7 | const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); |
| 8 | const { chromium } = await import("playwright"); |
| 9 | const server = await createServer({ root, logLevel: "error", server: { host: "127.0.0.1", port: 0 } }); |
| 10 | await server.listen(); |
| 11 | const browser = await chromium.launch({ headless: true }); |
| 12 | try { |
| 13 | const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } }); |
| 14 | const errors = []; |
| 15 | page.on("pageerror", error => errors.push(error.message)); |
| 16 | await page.goto(`http://127.0.0.1:${server.httpServer.address().port}/?mock=bench&bench=1`); |
| 17 | const composer = page.locator("textarea.composer__input:not([aria-hidden=true])"); |
| 18 | await composer.waitFor(); |
| 19 | const original = await page.evaluate(async () => (await (await import("/src/lib/bridge.ts")).app.GetWorkspaceSnapshot()).workspaces.flatMap(workspace => workspace.sessionIds)); |
| 20 | // Exercise actual clicks; every accepted click must survive navigation coalescing. |
| 21 | for (let index = 0; index < 3; index++) await newSessionButton(page).click(); |
| 22 | await page.waitForFunction(async before => { |
| 23 | const { app } = await import("/src/lib/bridge.ts"); |
| 24 | return (await app.GetWorkspaceSnapshot()).workspaces.flatMap(workspace => workspace.sessionIds).filter(id => !before.includes(id)).length === 3; |
| 25 | }, original); |
| 26 | const created = await page.evaluate(async before => (await (await import("/src/lib/bridge.ts")).app.GetWorkspaceSnapshot()).workspaces.flatMap(workspace => workspace.sessionIds).filter(id => !before.includes(id)), original); |
| 27 | assert.equal(new Set(created).size, 3); |
| 28 | await page.waitForFunction(() => document.querySelector("textarea.composer__input:not([aria-hidden=true])")?.disabled === false); |
| 29 | await composer.fill("formal session unsent input"); |
| 30 | await page.waitForFunction(async () => { |
| 31 | const { app } = await import("/src/lib/bridge.ts"); |
| 32 | const active = (await app.ListTabs()).find(tab => tab.active); |
| 33 | return active && (await app.GetSessionComposerState({hostId:"local",sessionId:active.sessionId})).contentJson.includes("formal session unsent input"); |
| 34 | }); |
| 35 | assert.deepEqual(await page.evaluate(async () => (await import("/src/lib/bridge.ts")).app.ListSessionDraftSummaries()), []); |
| 36 | assert.deepEqual(errors, []); |
| 37 | console.log("PASS real UI: three New actions create distinct formal sessions; input persists; no legacy draft is created"); |
| 38 | } finally { await browser.close(); await server.close(); } |
| 39 |