fix(browser): retain capacity refusal through terminal progress

This commit is contained in:
morluto
2026-10-24 04:03:46 +08:00
parent 6ff682505c
commit 88bbf9c006
2 changed files with 70 additions and 47 deletions
+2
View File
@@ -144,6 +144,8 @@ export const observeCdpSession = async (
message: "Browser observation window ended",
terminal: true,
});
// Terminal progress is awaited and may admit more protocol events.
capture.assertRequestOwnershipWithinLimit();
if (capture.scopeExcluded) endReason = "target_left_scope";
return {
browser: context.discovery.version,
@@ -1,4 +1,5 @@
import { expect, it, onTestFinished, vi } from "vitest";
import { CdpConnection } from "../../../src/browser/CdpConnection.js";
import { CdpBrowserProvider } from "../../../src/browser/CdpBrowserProvider.js";
import { observeWebSessionInputSchema } from "../../../src/domain/browserSession.js";
import { startFakeCdpBrowser } from "../../fixtures/fakeCdpBrowser.js";
@@ -17,53 +18,73 @@ vi.mock("../../../src/domain/webRuntime.js", async (importOriginal) => {
};
});
it("refuses active document identity retention before reporting a complete session", async () => {
const browser = await startFakeCdpBrowser({ commandEvents: () => [] });
const provider = new CdpBrowserProvider();
onTestFinished(async () => {
await provider.close();
await browser.close();
});
const result = await provider.observeSession(
observeWebSessionInputSchema.parse({
cdp_endpoint: browser.endpoint,
target_id: "allowed-page",
allowed_origins: [browser.allowedOrigin],
observation_ms: 1_000,
}),
{
signal: AbortSignal.timeout(2_000),
progress: {
report: async (update) => {
if (update.completed === 1)
browser.emitEvent({
method: "Network.requestWillBeSent",
sessionId: "session-1",
params: {
requestId: "r".repeat(128),
type: "Document",
frameId: "frame-main",
loaderId: "loader",
timestamp: 100,
request: {
url: `${browser.allowedOrigin}/page`,
method: "GET",
it.each([1, 2])(
"refuses active document identity retention at progress stage %s before reporting a complete session",
async (stage) => {
let received: () => void = () => {};
const delivered = new Promise<void>((resolve) => {
received = resolve;
});
const onEvent = CdpConnection.prototype.onEvent;
const delivery = vi
.spyOn(CdpConnection.prototype, "onEvent")
.mockImplementation(function (this: CdpConnection, listener) {
return onEvent.call(this, (event) => {
listener(event);
if (event.method === "Network.requestWillBeSent") received();
});
});
const browser = await startFakeCdpBrowser({ commandEvents: () => [] });
const provider = new CdpBrowserProvider();
onTestFinished(async () => {
delivery.mockRestore();
await provider.close();
await browser.close();
});
const result = await provider.observeSession(
observeWebSessionInputSchema.parse({
cdp_endpoint: browser.endpoint,
target_id: "allowed-page",
allowed_origins: [browser.allowedOrigin],
observation_ms: 5,
}),
{
signal: AbortSignal.timeout(2_000),
progress: {
report: async (update) => {
if (update.completed === stage) {
browser.emitEvent({
method: "Network.requestWillBeSent",
sessionId: "session-1",
params: {
requestId: "r".repeat(128),
type: "Document",
frameId: "frame-main",
loaderId: "loader",
timestamp: 100,
request: {
url: `${browser.allowedOrigin}/page`,
method: "GET",
},
},
},
});
});
// Observe actual parser/listener delivery before final progress resolves.
await delivered;
}
},
},
},
},
);
expect(result).toMatchObject({
ok: false,
error: {
_tag: "BrowserObservationError",
reason: "payload_limit",
detail: expect.stringContaining("Active document request identities"),
},
});
expect(browser.commands.map(({ method }) => method)).toContain(
"Target.detachFromTarget",
);
});
);
expect(result).toMatchObject({
ok: false,
error: {
_tag: "BrowserObservationError",
reason: "payload_limit",
detail: expect.stringContaining("Active document request identities"),
},
});
expect(browser.commands.map(({ method }) => method)).toContain(
"Target.detachFromTarget",
);
},
);