Files
rea/scripts/lib/browser-runtime-termination-e2e.mjs
morluto 131b2d85f3 fix(verify): report every owned cleanup failure before success
Use one cleanup owner across browser, Frida and JEB verifiers. Attempt all independent cleanup tasks, retain primary failures, and emit successful reports only after cleanup. Remove the superseded browser helper and duplicate tests.

Validation: cleanup aggregation and runtime fixture tests, build and static checks passed. No real Frida or JEB run.
2026-10-14 13:40:53 +08:00

105 lines
3.1 KiB
JavaScript

import assert from "node:assert/strict";
import { CdpConnection } from "../../dist/browser/CdpConnection.js";
import { mcpTextValue } from "./mcp-verifier-results.mjs";
import { closeVerifierResources } from "./verifier-cleanup.mjs";
/** Close a separately owned fixture page after actual MCP arming and inspect native cleanup diagnostics. */
export async function verifyRuntimeTargetTermination(client, input, origin) {
const version = await (
await fetch(`${input.cdp_endpoint}/json/version`)
).json();
const root = await CdpConnection.connect(
version.webSocketDebuggerUrl,
"observe_web_execution",
);
let targetId;
let closed = false;
let primaryError;
try {
({ targetId } = await root.send("Target.createTarget", { url: origin }));
assert.equal(typeof targetId, "string");
await waitForTarget(input.cdp_endpoint, targetId, origin);
let closePromise;
const response = await client.callTool(
{
name: "observe_web_execution",
arguments: {
...input,
target_id: targetId,
observation_ms: 2_147_483_647,
},
},
{
timeout: 20_000,
onprogress: (notification) => {
if (
closePromise === undefined &&
notification.message?.includes(
"browser_execution: Browser execution observation armed",
)
) {
closePromise = root
.send("Target.closeTarget", { targetId })
.then((result) => {
assert.equal(result.success, true);
closed = true;
});
void closePromise.catch(() => undefined);
}
},
},
);
assert.ok(
closePromise,
"The separate page must be closed after actual arming",
);
await closePromise;
assert.equal(
response.isError,
true,
"Detached instrumentation cannot claim confirmed cleanup",
);
const failure = mcpTextValue(response);
assert.match(failure, /cleanup.*confirmed/u);
assert.ok(
failure.includes(targetId),
"Failure must retain the selected target identity",
);
assert.match(failure, /Profiler\.stopPreciseCoverage/u);
return {
target_id: targetId,
page_closed_after_arming: true,
failure_inline: true,
cleanup: "unconfirmed_reported",
};
} catch (cause) {
primaryError = cause;
throw cause;
} finally {
await closeVerifierResources(
[
() =>
targetId === undefined || closed
? undefined
: root.send("Target.closeTarget", { targetId }),
() => root.close(),
],
primaryError,
);
}
}
async function waitForTarget(endpoint, targetId, origin) {
for (let attempt = 0; attempt < 100; attempt += 1) {
const pages = await (await fetch(`${endpoint}/json/list`)).json();
if (
pages.some((page) => page.id === targetId && page.url.startsWith(origin))
)
return;
await new Promise((resolve) => setTimeout(resolve, 20));
}
throw new Error(
"Separate fixture target did not settle on its selected origin",
);
}