import { createHash, randomUUID } from "node:crypto"; import { access } from "node:fs/promises"; import { expect, it } from "vitest"; import { createWebTextArtifact } from "../domain/webContentArtifact.js"; import type { IncludedScript } from "../domain/webBundleAnalyzerInspection.js"; import { AnalysisCancelledError, AnalysisOutputError, AnalysisResourceConstraintError, AnalysisTimeoutError, } from "../domain/analysisErrorCore.js"; import { resolvedAnalysisError, type AnalysisError, } from "../domain/analysisErrorBase.js"; import { cleanupOwnedProcessGroup } from "../process/ProcessOwnership.js"; import { spawnOwnedProviderProcess, type ProviderProcessHandle, } from "../process/ProviderProcess.js"; import { WebBundleAnalysisWorker } from "./WebBundleAnalysisWorker.js"; import { WEB_BUNDLE_WORKER_LIMITS } from "./WebBundleAnalysisWorkerProtocol.js"; const makeScript = (text: string): IncludedScript => ({ script_key: `scr_${createHash("sha256").update(text).digest("hex")}`, frame_id: "frame-1", url: "https://app.example.test/app.js", origin: "https://app.example.test", cdp_hash: null, length: Buffer.byteLength(text), is_module: false, language: "JavaScript", source_map_url: null, resource_reconciliation: { status: "unmatched", reason: "no_exact_sanitized_url", }, source: { included: true, artifact: createWebTextArtifact(text, "application/javascript"), }, }); const sourceWorkerProgram = ( hangMarker?: string, oomMarker?: string, stderrMarker?: string, ): string => ` const { serveWebBundleAnalysisWorker } = await import(${JSON.stringify(new URL("./WebBundleAnalysisWorkerServer.ts", import.meta.url).href)}); const { analyzeCapturedWebScript } = await import(${JSON.stringify(new URL("../domain/webBundleAnalyzer.ts", import.meta.url).href)}); const analyze = (script) => { if (${JSON.stringify(hangMarker)} !== undefined && script.source.artifact.text === ${JSON.stringify(hangMarker)}) { for (;;) {} } if (${JSON.stringify(oomMarker)} !== undefined && script.source.artifact.text === ${JSON.stringify(oomMarker)}) { const retained = []; for (;;) retained.push(new Array(50_000).fill({ marker: "bounded-child-oom" })); } if (${JSON.stringify(stderrMarker)} !== undefined) process.stderr.write(${JSON.stringify(stderrMarker)} + "\\n"); return analyzeCapturedWebScript(script); }; await serveWebBundleAnalysisWorker(analyze); `; type TestMode = | { readonly kind: "source"; readonly hangMarker?: string; readonly oomMarker?: string; readonly stderrMarker?: string; } | { readonly kind: "delayed-ready" } | { readonly kind: "exit-before-ready" } | { readonly kind: "protocol"; readonly failure: | "wrong-id" | "oversized-control" | "oversized-result" | "late-failure" | "exit-7" | "truncated-exit" | "abort-first-exit" | "tail-exit" | "malformed" | "wrong-job-failure" | "resource-failure" | "final-frame-held-pipe" | "zero-exit-held-pipe"; }; const protocolWorkerProgram = ( failure: | "wrong-id" | "oversized-control" | "oversized-result" | "late-failure" | "exit-7" | "truncated-exit" | "abort-first-exit" | "tail-exit" | "malformed" | "wrong-job-failure" | "resource-failure" | "final-frame-held-pipe" | "zero-exit-held-pipe", ): string => ` import { createInterface } from "node:readline"; import { spawn } from "node:child_process"; import { getHeapStatistics } from "node:v8"; const send = (value) => process.stdout.write(JSON.stringify(value) + "\\n"); send({ kind: "ready", heap_limit_bytes: getHeapStatistics().heap_size_limit }); ${failure === "abort-first-exit" ? `process.on("SIGTERM", () => {}); setTimeout(() => process.stderr.write("late natural exit 7\\n", () => process.exit(7)), 50);` : ""} const input = createInterface({ input: process.stdin, crlfDelay: Infinity }); input.once("line", (line) => { const request = JSON.parse(line); ${ failure === "zero-exit-held-pipe" ? `const program = "setTimeout(() => process.exit(0), 300);"; spawn(process.execPath, ["-e", program], { stdio: ["ignore", "inherit", "inherit"] }); process.exit(0);` : failure === "exit-7" ? `process.stderr.write("controlled exit 7\\n", () => process.exit(7));` : failure === "tail-exit" ? `const lateProgram = "setTimeout(() => { process.stderr.write('late tail marker'); setTimeout(() => process.exit(0), 500); }, 50);"; spawn(process.execPath, ["-e", lateProgram], { stdio: ["ignore", "ignore", "inherit"] }); process.stderr.write("early exit marker\\n", () => process.exit(7));` : failure === "truncated-exit" ? `process.stderr.write("x".repeat(300 * 1024), () => process.exit(7));` : failure === "abort-first-exit" ? `setInterval(() => {}, 1_000);` : failure === "malformed" ? `process.stdout.write("{not-json}\\n"); setInterval(() => {}, 1_000);` : failure === "wrong-job-failure" ? `send({ kind: "failure", id: ${JSON.stringify(randomUUID())}, reason: "output", message: "failure for another request" }); setInterval(() => {}, 1_000);` : failure === "resource-failure" ? `send({ kind: "failure", id: request.id, reason: "resource", message: "bounded result capacity" }); setInterval(() => {}, 1_000);` : failure === "final-frame-held-pipe" ? `const frame = JSON.stringify({ kind: "failure", id: request.id, reason: "output", message: "final frame from descendant" }); const program = "setTimeout(() => { process.stdout.write(" + JSON.stringify(frame + "\\n") + "); setInterval(() => {}, 1000); }, 100);"; spawn(process.execPath, ["-e", program], { stdio: ["ignore", "inherit", "inherit"] }); process.exit(7);` : failure === "late-failure" ? `process.stdout.write(JSON.stringify({ kind: "failure", id: request.id, reason: "output", message: "failure frame before abort" }) + "\\n"); setInterval(() => {}, 1_000);` : failure === "wrong-id" ? `send({ kind: "phase", id: ${JSON.stringify(randomUUID())}, phase: "analyze" });` : failure === "oversized-control" ? `process.stdout.write("x".repeat(70 * 1024) + "\\n");` : `send({ kind: "complete", id: request.id, result: { bytes: request.result_budget_bytes + 1, sha256: "${"0".repeat(64)}" } });` } }); `; const delayedReadyProgram = ` import { createInterface } from "node:readline"; import { getHeapStatistics } from "node:v8"; setTimeout(() => { process.stdout.write(JSON.stringify({ kind: "ready", heap_limit_bytes: getHeapStatistics().heap_size_limit }) + "\\n"); }, 1_500); createInterface({ input: process.stdin, crlfDelay: Infinity }); `; const exitBeforeReadyProgram = `process.exit(0);`; interface SpawnedTestProcess { readonly process: ProviderProcessHandle; readonly root: string | undefined; } const launcherFor = ( mode: TestMode, options: { readonly failCleanupOnce?: boolean; readonly onSpawn?: (spawned: SpawnedTestProcess) => void; } = {}, ): typeof spawnOwnedProviderProcess => { let failCleanup = options.failCleanupOnce ?? false; return async (request) => { const loader = import.meta.resolve("tsx"); const program = mode.kind === "source" ? sourceWorkerProgram( mode.hangMarker, mode.oomMarker, mode.stderrMarker, ) : mode.kind === "delayed-ready" ? delayedReadyProgram : mode.kind === "exit-before-ready" ? exitBeforeReadyProgram : protocolWorkerProgram(mode.failure); const spawned = await spawnOwnedProviderProcess({ ...request, arguments: [ ...request.arguments.slice(0, -1), "--import", loader, "--input-type=module", "-e", program, ], }); options.onSpawn?.({ process: spawned.process, root: request.cwd }); return { ...spawned, cleanup: async () => { if (failCleanup) { failCleanup = false; return { cleaned: false, reason: "controlled worker cleanup retry" }; } return spawned.cleanup === undefined ? cleanupOwnedProcessGroup(spawned.ownership) : spawned.cleanup(); }, }; }; }; const failureOf = ( result: Awaited>, ): AnalysisError => { if (result.ok) throw new Error("Expected web worker failure"); return result.error.error; }; const waitForExit = async (child: ProviderProcessHandle): Promise => { if (child.exitCode !== null || child.signalCode !== null) return; await new Promise((resolve, reject) => { let timer: NodeJS.Timeout | undefined; const finish = (): void => { if (timer !== undefined) clearTimeout(timer); child.off("exit", onExit); resolve(); }; const onExit = (): void => finish(); child.once("exit", onExit); timer = setTimeout(() => { child.off("exit", onExit); reject(new Error("Owned child did not exit")); }, 3_000); if (child.exitCode !== null || child.signalCode !== null) finish(); }); }; it("reuses one real owned worker for completed facts from consecutive scripts", async () => { const children: ProviderProcessHandle[] = []; const worker = new WebBundleAnalysisWorker( WEB_BUNDLE_WORKER_LIMITS.heapMb, launcherFor( { kind: "source" }, { onSpawn: ({ process: child }) => children.push(child) }, ), ); try { const first = await worker.analyze(makeScript("fetch('/users');"), 10_000); const second = await worker.analyze( makeScript("fetch('/orders');"), 10_000, ); expect(first.ok).toBe(true); expect(second.ok).toBe(true); if (!first.ok || !second.ok) throw new Error("Expected both captured scripts to complete"); expect(first.value).toMatchObject({ status: "analyzed", script_key: makeScript("fetch('/users');").script_key, }); expect(second.value).toMatchObject({ status: "analyzed", script_key: makeScript("fetch('/orders');").script_key, }); expect(children).toHaveLength(1); } finally { await worker.close(); } }); it("preserves an observed failure frame and the opaque later abort reason", async () => { const reason = { opaque: "caller cancellation reason" }; const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( WEB_BUNDLE_WORKER_LIMITS.heapMb, launcherFor( { kind: "protocol", failure: "late-failure" }, { onSpawn: ({ process: child }) => { child.stdout?.on("data", (chunk) => { if (String(chunk).includes("failure frame before abort")) queueMicrotask(() => controller.abort(reason)); }); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/late');"), 5_000, controller.signal, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisOutputError); expect(error.message).toContain("failure frame before abort"); expect(error.secondaryFailures).toHaveLength(1); expect(error.secondaryFailures[0]).toBeInstanceOf(AnalysisCancelledError); expect(error.secondaryFailures[0]?.cause).toBe(reason); } finally { await worker.close(); } }); it("retains exit-7 output when abort follows the observed exit", async () => { for (const abortAfterExit of [false, true]) { const reason = { opaque: "exit observed before abort" }; const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "protocol", failure: "exit-7" }, { onSpawn: ({ process: child }) => { if (abortAfterExit) child.once("exit", () => queueMicrotask(() => controller.abort(reason)), ); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/exit-7');"), 5_000, controller.signal, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisOutputError); expect(error.capturedOutput?.exit_code).toBe(7); expect(error.capturedOutput?.stderr).toContain("controlled exit 7"); if (abortAfterExit) { expect(error.secondaryFailures).toHaveLength(1); expect(error.secondaryFailures[0]).toBeInstanceOf( AnalysisCancelledError, ); expect(error.secondaryFailures[0]?.cause).toBe(reason); } else { expect(error.secondaryFailures).toHaveLength(0); } } finally { await worker.close(); } } }); it("keeps cancellation when abort is observed before a later child exit", async () => { const controller = new AbortController(); let childExit: Promise | undefined; const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "protocol", failure: "abort-first-exit" }, { onSpawn: ({ process: child }) => { childExit = new Promise((resolve) => child.once("exit", (code) => resolve(code)), ); child.stdout?.once("data", () => queueMicrotask(() => controller.abort(null)), ); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/abort-first');"), 5_000, controller.signal, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisCancelledError); expect(error.cause).toBeNull(); expect(error.capturedOutput).toBeUndefined(); expect(await childExit).toBe(7); } finally { await worker.close(); } }); it("keeps a code-0 exit pending while an inherited output pipe can still produce a frame", async () => { for (const abortAfterExit of [false, true]) { const reason = { opaque: "code-0 exit while inherited pipe is open" }; const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "protocol", failure: "zero-exit-held-pipe" }, { onSpawn: ({ process: child }) => { if (abortAfterExit) child.once("exit", () => queueMicrotask(() => controller.abort(reason)), ); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/zero-exit-held-pipe');"), 5_000, controller.signal, ); const error = failureOf(result); if (abortAfterExit) { expect(error).toBeInstanceOf(AnalysisCancelledError); expect(error.cause).toBe(reason); } else { expect(error).toBeInstanceOf(AnalysisOutputError); expect(error.capturedOutput?.exit_code).toBe(0); } } finally { await worker.close(); } } }); it("retains EOF without a terminal response when abort follows the close event", async () => { const reason = { opaque: "abort queued after owned output close" }; const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "protocol", failure: "zero-exit-held-pipe" }, { onSpawn: ({ process: child }) => { child.once("close", () => queueMicrotask(() => controller.abort(reason)), ); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/eof-before-abort');"), 5_000, controller.signal, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisOutputError); expect(error.message).toContain("output closed before completing"); expect(error.capturedOutput?.exit_code).toBe(0); expect(error.secondaryFailures).toHaveLength(1); expect(error.secondaryFailures[0]).toBeInstanceOf(AnalysisCancelledError); expect(error.secondaryFailures[0]?.cause).toBe(reason); } finally { await worker.close(); } }); it("retains startup EOF without a ready frame when abort follows the close event", async () => { for (const abortAfterClose of [false, true]) { const reason = { opaque: "abort queued after startup output close" }; const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "exit-before-ready" }, { onSpawn: ({ process: child }) => { if (abortAfterClose) child.once("close", () => queueMicrotask(() => controller.abort(reason)), ); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/startup-eof');"), 5_000, controller.signal, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisOutputError); expect(error.message).toContain("output closed before completing"); expect(error.capturedOutput?.exit_code).toBe(0); if (abortAfterClose) { expect(error.secondaryFailures).toHaveLength(1); expect(error.secondaryFailures[0]).toBeInstanceOf( AnalysisCancelledError, ); expect(error.secondaryFailures[0]?.cause).toBe(reason); } else { expect(error.secondaryFailures).toHaveLength(0); } } finally { await worker.close(); } } }); it("retains exit-time truncation when abort follows an oversized stderr exit", async () => { const reason = { opaque: "oversized stderr exit observed before abort" }; const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "protocol", failure: "truncated-exit" }, { onSpawn: ({ process: child }) => { child.once("exit", () => queueMicrotask(() => controller.abort(reason)), ); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/truncated-exit');"), 5_000, controller.signal, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisOutputError); expect(error.capturedOutput?.exit_code).toBe(7); expect(error.capturedOutput?.truncated).toBe(true); expect(Buffer.byteLength(error.capturedOutput?.stderr ?? "")).toBeLessThan( 300 * 1024, ); expect(error.secondaryFailures[0]?.cause).toBe(reason); } finally { await worker.close(); } }); it("keeps malformed protocol output primary when abort follows its observation", async () => { const reason = { opaque: "malformed frame observed before abort" }; for (const abortAfterFrame of [false, true]) { const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "protocol", failure: "malformed" }, { onSpawn: ({ process: child }) => { if (abortAfterFrame) child.stdout?.on("data", (chunk) => { if (String(chunk).includes("{not-json}")) queueMicrotask(() => controller.abort(reason)); }); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/malformed');"), 5_000, controller.signal, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisOutputError); expect(error.message).toContain("Invalid web analyzer control frame"); if (abortAfterFrame) { expect(error.secondaryFailures).toHaveLength(1); expect(error.secondaryFailures[0]?.cause).toBe(reason); } else { expect(error.secondaryFailures).toHaveLength(0); } } finally { await worker.close(); } } }); it("does not let a failure frame for another job replace cancellation", async () => { const reason = { opaque: "unrelated frame observed before abort" }; const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "protocol", failure: "wrong-job-failure" }, { onSpawn: ({ process: child }) => { child.stdout?.on("data", (chunk) => { if (String(chunk).includes("failure for another request")) queueMicrotask(() => controller.abort(reason)); }); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/wrong-job');"), 5_000, controller.signal, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisCancelledError); expect(error.cause).toBe(reason); expect(error.secondaryFailures).toHaveLength(0); } finally { await worker.close(); } }); it("keeps the resource budget on an observed worker resource frame", async () => { const reason = { opaque: "resource frame before abort" }; const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "protocol", failure: "resource-failure" }, { onSpawn: ({ process: child }) => { child.stdout?.on("data", (chunk) => { if (String(chunk).includes("bounded result capacity")) queueMicrotask(() => controller.abort(reason)); }); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/resource-failure');"), 5_000, controller.signal, ); const error = failureOf(result); if (!(error instanceof AnalysisResourceConstraintError)) throw new Error("Expected a worker resource constraint failure"); expect(error.reportedLimits?.result_budget_bytes).toBeGreaterThan(0); expect(error.secondaryFailures[0]?.cause).toBe(reason); } finally { await worker.close(); } }); it("consumes a final frame before an inherited descendant pipe closes", async () => { const worker = new WebBundleAnalysisWorker( 128, launcherFor({ kind: "protocol", failure: "final-frame-held-pipe" }), ); try { const result = await worker.analyze( makeScript("fetch('/descendant-frame');"), 5_000, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisOutputError); expect(error.message).toContain("final frame from descendant"); } finally { await worker.close(); } }); it("does not classify heap-marker stderr from a healthy worker as exhaustion", async () => { const worker = new WebBundleAnalysisWorker( 128, launcherFor({ kind: "source", stderrMarker: "FATAL ERROR: Allocation failed - JavaScript heap out of memory", }), ); try { const result = await worker.analyze( makeScript("fetch('/healthy');"), 5_000, ); expect(result.ok).toBe(true); if (result.ok) expect(result.value.status).toBe("analyzed"); } finally { await worker.close(); } }); it("projects late stderr tails with completeness from the actual selection point", async () => { for (const abortAfterExit of [false, true]) { const reason = { opaque: "abort after exit but after late stderr tail" }; const controller = new AbortController(); const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "protocol", failure: "tail-exit" }, { onSpawn: ({ process: child }) => { if (abortAfterExit) child.once("exit", () => setTimeout(() => controller.abort(reason), 150), ); }, }, ), ); try { const result = await worker.analyze( makeScript("fetch('/late-tail');"), 5_000, controller.signal, ); const error = failureOf(result); expect(error).toBeInstanceOf(AnalysisOutputError); expect(error.capturedOutput?.stderr).toContain("early exit marker"); expect(error.capturedOutput?.stderr).toContain("late tail marker"); expect(error.capturedOutput?.truncated).toBe(abortAfterExit); if (abortAfterExit) expect(error.secondaryFailures[0]?.cause).toBe(reason); else expect(error.secondaryFailures).toHaveLength(0); } finally { await worker.close(); } } }); it("kills a hung owned child at the deadline and starts a fresh worker for the next script", async () => { const children: ProviderProcessHandle[] = []; const worker = new WebBundleAnalysisWorker( WEB_BUNDLE_WORKER_LIMITS.heapMb, launcherFor( { kind: "source", hangMarker: "hang forever" }, { onSpawn: ({ process: child }) => children.push(child) }, ), ); try { const timedOut = await worker.analyze(makeScript("hang forever"), 500); expect(failureOf(timedOut)).toBeInstanceOf(AnalysisTimeoutError); await waitForExit(children[0]!); expect( children[0]?.exitCode !== null || children[0]?.signalCode !== null, ).toBe(true); const recovered = await worker.analyze( makeScript("fetch('/after-timeout');"), 10_000, ); expect(recovered.ok).toBe(true); expect(children).toHaveLength(2); } finally { await worker.close(); } }); it("contains child heap exhaustion and reuses the host for a later script", async () => { const children: ProviderProcessHandle[] = []; const roots: string[] = []; const worker = new WebBundleAnalysisWorker( 128, launcherFor( { kind: "source", oomMarker: "exhaust child heap" }, { onSpawn: ({ process: child, root }) => { children.push(child); if (root !== undefined) roots.push(root); }, }, ), ); try { const exhausted = await worker.analyze( makeScript("exhaust child heap"), 15_000, ); expect(failureOf(exhausted)).toBeInstanceOf( AnalysisResourceConstraintError, ); await waitForExit(children[0]!); expect( children[0]?.exitCode !== null || children[0]?.signalCode !== null, ).toBe(true); const recovered = await worker.analyze( makeScript("fetch('/after-oom');"), 10_000, ); expect(recovered.ok).toBe(true); expect(children).toHaveLength(2); expect(roots).toHaveLength(2); expect(roots[0]).toBe(roots[1]); await access(roots[0]!); await worker.close(); await expect(access(roots[0]!)).rejects.toThrow(); } finally { await worker.close(); } }); it("cancels during the late ready handshake and retains failed cleanup until exact retry", async () => { const children: SpawnedTestProcess[] = []; let announceSpawn: () => void = () => {}; const spawned = new Promise((resolve) => { announceSpawn = resolve; }); const worker = new WebBundleAnalysisWorker( WEB_BUNDLE_WORKER_LIMITS.heapMb, launcherFor( { kind: "delayed-ready" }, { failCleanupOnce: true, onSpawn: (child) => { children.push(child); announceSpawn(); }, }, ), ); const controller = new AbortController(); const reason = { source: "late-handshake-test" }; try { const analyzing = worker.analyze( makeScript("fetch('/cancelled');"), 10_000, controller.signal, ); await spawned; controller.abort(reason); const result = await analyzing; const error = failureOf(result); expect(error.cleanupIncomplete).toBe(true); expect(error.cleanupPrimary).toBeInstanceOf(AnalysisCancelledError); expect(error.cleanupPrimary?.cause).toBe(reason); expect(children[0]?.root).toBeDefined(); await access(children[0]?.root ?? ""); await worker.close(); expect(error.cleanupIncomplete).toBe(false); expect(resolvedAnalysisError(error).cause).toBe(reason); await expect(access(children[0]?.root ?? "")).rejects.toThrow(); await waitForExit(children[0]!.process); } finally { if ( children[0]?.process.exitCode === null && children[0]?.process.signalCode === null ) children[0]?.process.kill("SIGKILL"); await worker.close().catch(() => undefined); await WebBundleAnalysisWorker.retryPending().catch(() => undefined); } }); it.each([ ["wrong-id", AnalysisOutputError], ["oversized-control", AnalysisOutputError], ["oversized-result", AnalysisResourceConstraintError], ] as const)( "rejects %s before accepting unverified result bytes", async (failure, ErrorType) => { const worker = new WebBundleAnalysisWorker( WEB_BUNDLE_WORKER_LIMITS.heapMb, launcherFor({ kind: "protocol", failure }), ); try { const result = await worker.analyze( makeScript("fetch('/not-read');"), 10_000, ); expect(failureOf(result)).toBeInstanceOf(ErrorType); if (failure === "oversized-result") expect(failureOf(result).message).toContain( "exceed the host's remaining reserved result capacity", ); } finally { await worker.close(); } }, );