import assert from "node:assert/strict"; import { EventEmitter } from "node:events"; import { test } from "node:test"; import { createBrowserTransport, type ChildProcessLike, type SpawnLike } from "./bridge.ts"; import { BrowserOperationError } from "./contracts.ts"; import type { BrowserOperation } from "./contracts.ts"; class TransportWorker extends EventEmitter implements ChildProcessLike { readonly requests: Record[] = []; readonly stdin = { write: (line: string): boolean => { const request = JSON.parse(line) as Record; this.requests.push(request); queueMicrotask(() => this.respond(request)); return true; }, end: (): void => undefined, once: (event: string, listener: (...args: any[]) => void): unknown => this.once(event, listener), }; readonly stdout = new EventEmitter() as EventEmitter & { setEncoding?: (encoding: string) => void }; readonly stderr = new EventEmitter(); killed = false; silent = false; respond(request: Record): void { if (this.silent) return; const operation = (request.operation as Record | undefined)?.op ?? request.op; const tab = { tabId: "tab-1", kind: "page", selected: true, owned: true, url: "http://fixture.test/form", origin: "http://fixture.test", title: "Fixture" }; let result: unknown; if (operation === "observe") result = { observationId: "obs-1", url: tab.url, title: tab.title, candidates: [] }; else if (operation === "read") result = { tab, documentId: "doc-1", url: tab.url, title: tab.title, visibleText: "Fixture complete", visibleTextTruncated: false }; else if (operation === "listTabs") result = [tab]; else if (operation === "narrowOriginPolicy") result = (request.operation as Record).request; else if (operation === "captureEvidence") result = { status: "complete", console: [{ level: "error", message: "fixture failed", count: 1, truncated: false }], failedRequests: [] }; else if (operation === "close") result = { closed: true }; else result = { status: "committed", mutationState: "verified", tab, documentId: "doc-2" }; this.stdout.emit("data", JSON.stringify({ id: request.id, ok: true, result: { op: operation, result } }) + "\n"); } kill(): boolean { this.killed = true; this.emit("close", null, "SIGTERM"); return true; } } function spawnFor(worker: TransportWorker): SpawnLike { return (_command, _args, _options) => worker; } const base = { cdpUrl: "http://127.0.0.1:9222", allowedOrigins: ["http://fixture.test"] as const }; const signal = () => new AbortController().signal; test("typed transport reuses one worker and carries scoped context without broadening", async () => { const worker = new TransportWorker(); const transport = createBrowserTransport({ ...base, spawn: spawnFor(worker) }); try { const narrowed = await transport.dispatch({ operation: { op: "narrowOriginPolicy", request: { allowedOrigins: ["http://fixture.test"] } } }, signal()); assert.deepEqual(narrowed, { op: "narrowOriginPolicy", result: { allowedOrigins: ["http://fixture.test"] } }); const read = await transport.dispatch({ operation: { op: "read", request: {} }, context: narrowed.result }, signal()); assert.equal(read.op, "read"); assert.equal(read.result.visibleText, "Fixture complete"); const tabs = await transport.dispatch({ operation: { op: "listTabs" } }, signal()); assert.equal(tabs.result[0]?.tabId, "tab-1"); assert.equal(worker.requests.length, 3); assert.deepEqual(worker.requests[0]?.operation, { op: "narrowOriginPolicy", request: { allowedOrigins: ["http://fixture.test"] } }); assert.deepEqual(worker.requests[1]?.operation, { op: "read", request: {} }); assert.deepEqual(worker.requests[1]?.context, { allowedOrigins: ["http://fixture.test"] }); await assert.rejects( transport.dispatch({ operation: { op: "read", request: {} }, context: { allowedOrigins: "*" } }, signal()), (error: unknown) => error instanceof BrowserOperationError && error.details.code === "invalid_request" && error.details.mutationState === "not_attempted", ); } finally { await transport.close(); } }); test("typed transport rejects malformed and oversized operation results safely", async () => { const worker = new TransportWorker(); worker.respond = (request) => { if ((request.operation as Record | undefined)?.op === "read") { worker.stdout.emit("data", JSON.stringify({ id: request.id, ok: true, result: { op: "read", result: { tab: {}, documentId: "d", url: "http://fixture.test/form", title: "x", visibleText: "x", visibleTextTruncated: false } } }) + "\n"); return; } worker.stdout.emit("data", `${JSON.stringify({ id: request.id, ok: true, result: { closed: true } })}\n`); }; const transport = createBrowserTransport({ ...base, spawn: spawnFor(worker) }); try { await assert.rejects(transport.dispatch({ operation: { op: "read", request: {} } }, signal()), (error: unknown) => { return error instanceof BrowserOperationError && error.details.code === "worker_failure"; }); assert.equal(worker.killed, true); } finally { await transport.close(); } const oversized = new TransportWorker(); oversized.respond = (request) => { oversized.stdout.emit("data", `${"x".repeat(128 * 1024 + 1)}\n`); }; const oversizedTransport = createBrowserTransport({ ...base, spawn: spawnFor(oversized) }); try { await assert.rejects(oversizedTransport.dispatch({ operation: { op: "observe" } }, signal()), (error: unknown) => error instanceof BrowserOperationError && error.details.code === "worker_failure"); assert.equal(oversized.killed, true); } finally { await oversizedTransport.close(); } }); test("transport preserves validated structured worker errors without raw exceptions", async () => { const worker = new TransportWorker(); let failed = true; worker.respond = (request) => { if (failed) { failed = false; worker.stdout.emit("data", JSON.stringify({ id: request.id, ok: false, error: "safe worker message", details: { code: "stale", operation: "act", phase: "verify", message: "browser target is stale", mutationState: "not_attempted", retry: "never", } }) + "\n"); return; } worker.stdout.emit("data", JSON.stringify({ id: request.id, ok: true, result: { op: "observe", result: { observationId: "obs-2", url: "http://fixture.test/form", title: "Fixture", candidates: [] } } }) + "\n"); }; const transport = createBrowserTransport({ ...base, spawn: spawnFor(worker) }); try { await assert.rejects(transport.dispatch({ operation: { op: "act", request: { observationId: "obs", candidateId: "c", action: "fill", text: "x" } } }, signal()), (error: unknown) => { return error instanceof BrowserOperationError && error.details.code === "stale" && error.details.mutationState === "not_attempted" && error.details.message === "browser target is stale"; }); assert.equal(worker.killed, false); const observation = await transport.dispatch({ operation: { op: "observe" } }, signal()); assert.equal(observation.result.observationId, "obs-2"); } finally { await transport.close(); } }); test("transport cancellation tears down the persistent worker without retry", async () => { const worker = new TransportWorker(); worker.silent = true; const transport = createBrowserTransport({ ...base, spawn: spawnFor(worker), requestTimeoutMs: 500 }); const controller = new AbortController(); const operation: BrowserOperation = { op: "navigate", request: { url: "http://fixture.test/form" } }; const pending = transport.dispatch({ operation }, controller.signal); await Promise.resolve(); controller.abort(); await assert.rejects(pending, (error: unknown) => error instanceof BrowserOperationError && error.details.code === "aborted" && error.details.mutationState === "unknown"); assert.equal(worker.requests.length, 1); assert.equal(worker.killed, true); await transport.close(); }); test("queued cancellation is safe and never writes a second request", async () => { const worker = new TransportWorker(); worker.silent = true; const transport = createBrowserTransport({ ...base, spawn: spawnFor(worker), requestTimeoutMs: 500 }); const first = transport.dispatch({ operation: { op: "observe" } }, new AbortController().signal); await Promise.resolve(); const queuedController = new AbortController(); const queued = transport.dispatch({ operation: { op: "navigate", request: { url: "http://fixture.test/form" } } }, queuedController.signal); queuedController.abort(); worker.silent = false; worker.respond(worker.requests[0]!); await first; await assert.rejects(queued, (error: unknown) => error instanceof BrowserOperationError && error.details.code === "aborted" && error.details.mutationState === "not_attempted" && error.details.retry === "never"); assert.equal(worker.requests.length, 1); await transport.close(); }); test("unknown runtime operations fail before any worker dispatch", async () => { const worker = new TransportWorker(); const transport = createBrowserTransport({ ...base, spawn: spawnFor(worker) }); try { await assert.rejects(transport.dispatch({ operation: { op: "notAnOperation" } as never }, signal()), (error: unknown) => error instanceof BrowserOperationError && error.details.code === "invalid_request" && error.details.mutationState === "not_attempted"); assert.equal(worker.requests.length, 0); } finally { await transport.close(); } }); test("parent cancellation tears down the worker even without a call signal abort", async () => { const worker = new TransportWorker(); worker.silent = true; const parent = new AbortController(); const transport = createBrowserTransport({ ...base, spawn: spawnFor(worker), requestTimeoutMs: 500 }, parent.signal); const pending = transport.dispatch({ operation: { op: "observe" } }, new AbortController().signal); await Promise.resolve(); parent.abort(); await assert.rejects(pending, (error: unknown) => error instanceof BrowserOperationError && error.details.code === "aborted"); assert.equal(worker.killed, true); await transport.close(); });