fix(browser): preserve source-map cancellation results

This commit is contained in:
morluto
2026-10-14 01:56:05 +08:00
parent a742936108
commit bfcc9526a3
3 changed files with 102 additions and 1 deletions
+2
View File
@@ -167,6 +167,8 @@ export class CdpBrowserProvider implements BrowserObservationPort {
),
);
} catch (cause: unknown) {
if (options.signal?.aborted === true)
return err(new AnalysisCancelledError("analyze_web_bundle", { cause }));
return err(providerError(cause, "analyze_web_bundle"));
}
}
@@ -7,6 +7,8 @@ import {
} from "../../../src/domain/browserObservation.js";
import { analyzeWebBundleInputSchema } from "../../../src/domain/webBundleAnalysis.js";
import { observeWebSessionInputSchema } from "../../../src/domain/browserSession.js";
import { discoverWebMcpToolsInputSchema } from "../../../src/domain/webMcpDiscovery.js";
import { captureWebScreenshotInputSchema } from "../../../src/domain/webScreenshot.js";
import {
startFakeCdpBrowser,
type FakeCdpBrowser,
@@ -22,6 +24,68 @@ const waitFor = async (ready: () => boolean, description: string) => {
};
describe("CdpBrowserProvider: cancellation during cleanup", () => {
it.each([
{
name: "WebMCP discovery",
operation: "discover_webmcp_tools",
invoke: (
provider: CdpBrowserProvider,
browser: FakeCdpBrowser,
signal: AbortSignal,
) =>
provider.discoverWebMcpTools(
discoverWebMcpToolsInputSchema.parse({
cdp_endpoint: browser.endpoint,
allowed_origins: [browser.allowedOrigin],
target_id: "allowed-page",
observation_ms: 0,
}),
{ signal },
),
},
{
name: "screenshot capture",
operation: "capture_web_screenshot",
invoke: (
provider: CdpBrowserProvider,
browser: FakeCdpBrowser,
signal: AbortSignal,
) =>
provider.captureScreenshot(
captureWebScreenshotInputSchema.parse({
cdp_endpoint: browser.endpoint,
allowed_origins: [browser.allowedOrigin],
target_id: "allowed-page",
}),
{ signal },
),
},
])(
"reports cancellation during $name cleanup",
async ({ operation, invoke }) => {
const browser = await startFakeCdpBrowser({
hangOnMethod: "Page.disable",
webMcpTools: true,
});
trackBrowser(browser);
const controller = new AbortController();
const pending = invoke(
new CdpBrowserProvider(),
browser,
controller.signal,
);
await waitFor(
() => browser.commands.some(({ method }) => method === "Page.disable"),
"page cleanup did not start",
);
controller.abort();
await expect(pending).resolves.toMatchObject({
ok: false,
error: { _tag: "AnalysisCancelledError", operation },
});
},
);
it("reports cancellation when an interrupt arrives during page cleanup", async () => {
const browser = await startFakeCdpBrowser({
hangOnMethod: "Network.disable",
@@ -111,6 +175,35 @@ describe("CdpBrowserProvider: cancellation during cleanup", () => {
},
});
});
it("classifies custom source-map abort reasons as cancellation", async () => {
const browser = await startFakeCdpBrowser({ hangSourceMap: true });
trackBrowser(browser);
const controller = new AbortController();
const pending = new CdpBrowserProvider().analyzeBundle(
analyzeWebBundleInputSchema.parse({
cdp_endpoint: browser.endpoint,
allowed_origins: [browser.allowedOrigin],
target_id: "allowed-page",
observation_ms: 0,
fetch_source_maps: true,
}),
{ signal: controller.signal },
);
await waitFor(
() =>
browser.httpRequests.some(({ url }) => url.startsWith("/app.js.map")),
"source-map download did not start",
);
controller.abort(new Error("stopped"));
await expect(pending).resolves.toMatchObject({
ok: false,
error: {
_tag: "AnalysisCancelledError",
operation: "analyze_web_bundle",
},
});
});
});
describe("CdpBrowserProvider: cancellation and session events", () => {
@@ -73,7 +73,13 @@ it("releases cleanup when cancellation arrives after capture completes", async (
});
controller.abort();
const result = await pending;
expect(result.ok).toBe(true);
expect(result).toMatchObject({
ok: false,
error: {
_tag: "AnalysisCancelledError",
operation: "observe_web_session",
},
});
expect(browser.commands.map(({ method }) => method)).toContain(
"Target.detachFromTarget",
);