fix(verifiers): own browser fixture setup and cleanup in one scope

This commit is contained in:
morluto 2026-10-14 09:55:09 +08:00
parent 278d7fb284
commit fd8a2e98ff
8 changed files with 184 additions and 125 deletions

View File

@ -14,36 +14,42 @@ import { webModuleTraceResultSchema } from "../../dist/domain/webModuleTrace.js"
import { NativeModuleResolver } from "../../dist/browser/modules/NativeModuleResolver.js";
import { startBrowserModuleSite } from "../fixtures/browser-module-site.mjs";
import { mcpTextValue } from "./mcp-verifier-results.mjs";
import { closeRuntimeFixtureResources } from "./browser-runtime-fixture-lifecycle.mjs";
/** Check native URL resolution against an independently loaded module graph through CLI/MCP. */
export async function verifyBrowserModules(
executable,
entrypoint = fileURLToPath(new URL("../rea.mjs", import.meta.url)),
) {
const site = await startBrowserModuleSite();
const root = await mkdtemp(join(tmpdir(), "rea-browser-modules-"));
const env = {
...process.env,
REA_LOG_LEVEL: "silent",
REA_BROWSER_EXECUTABLE: executable,
HOPPER_LAUNCHER_PATH: "/rea-unconfigured-provider/hopper",
};
const cli = async (...args) => {
const { stdout } = await promisify(execFile)(
process.execPath,
[entrypoint, ...args, "--json"],
{ env, timeout: 45000, maxBuffer: 16 * 1024 * 1024 },
);
return parseEvidence(JSON.parse(stdout));
};
const transport = new StdioClientTransport({
command: process.execPath,
args: [entrypoint, "mcp"],
env,
stderr: "pipe",
});
const client = new Client({ name: "module-real-e2e", version: "1" });
let site;
let root;
let transport;
let client;
let primaryError;
try {
site = await startBrowserModuleSite();
root = await mkdtemp(join(tmpdir(), "rea-browser-modules-"));
const env = {
...process.env,
REA_LOG_LEVEL: "silent",
REA_BROWSER_EXECUTABLE: executable,
HOPPER_LAUNCHER_PATH: "/rea-unconfigured-provider/hopper",
};
const cli = async (...args) => {
const { stdout } = await promisify(execFile)(
process.execPath,
[entrypoint, ...args, "--json"],
{ env, timeout: 45000, maxBuffer: 16 * 1024 * 1024 },
);
return parseEvidence(JSON.parse(stdout));
};
transport = new StdioClientTransport({
command: process.execPath,
args: [entrypoint, "mcp"],
env,
stderr: "pipe",
});
client = new Client({ name: "module-real-e2e", version: "1" });
const oracle = await loadingOracle(executable, site);
const scenario = {
browser: { mode: "launch", executable_path: executable },
@ -298,11 +304,17 @@ export async function verifyBrowserModules(
map_identity_verified: true,
implicit_refetches: 0,
};
} catch (cause) {
primaryError = cause;
throw cause;
} finally {
await client.close();
await transport.close();
await site.close();
await rm(root, { recursive: true, force: true });
const cleanup = [];
if (client !== undefined) cleanup.push(() => client.close());
if (transport !== undefined) cleanup.push(() => transport.close());
if (site !== undefined) cleanup.push(() => site.close());
if (root !== undefined)
cleanup.push(() => rm(root, { recursive: true, force: true }));
await closeRuntimeFixtureResources(cleanup, primaryError);
}
}

View File

@ -14,6 +14,7 @@ import {
} from "../fixtures/browser-network-site.mjs";
import { assertBrowserNetworkEvidence } from "./browser-network-assertions.mjs";
import { scenarioProfiles } from "./browser-scenario-verifier.mjs";
import { closeRuntimeFixtureResources } from "./browser-runtime-fixture-lifecycle.mjs";
/** Exercise selected network content through real CLI and stdio MCP, one browser at a time. */
export async function verifyBrowserNetworkEvidence(
@ -21,9 +22,14 @@ export async function verifyBrowserNetworkEvidence(
entrypoint = fileURLToPath(new URL("../rea.mjs", import.meta.url)),
attachment,
) {
const site = await startBrowserNetworkSite();
const profilesBefore = await scenarioProfiles();
let site;
let profilesBefore;
let transport;
let client;
let primaryError;
try {
site = await startBrowserNetworkSite();
profilesBefore = await scenarioProfiles();
const scenario = browserScenarioSchema.parse({
browser: { mode: "launch", executable_path: executable },
start_url: { url: site.origin },
@ -97,58 +103,50 @@ export async function verifyBrowserNetworkEvidence(
() => assertBrowserNetworkEvidence(swapped, site.origin),
/associated with a different same-URL request/,
);
const transport = new StdioClientTransport({
transport = new StdioClientTransport({
command: process.execPath,
args: [entrypoint, "mcp"],
env,
stderr: "pipe",
});
const client = new Client({ name: "network-real-e2e", version: "1" });
client = new Client({ name: "network-real-e2e", version: "1" });
let mcpProof;
try {
await client.connect(transport);
const result = await client.callTool(
{ name: "capture_browser_scenario", arguments: scenario },
await client.connect(transport);
const result = await client.callTool(
{ name: "capture_browser_scenario", arguments: scenario },
{ timeout: 60_000 },
);
assert.notEqual(result.isError, true, JSON.stringify(result));
const evidence = parseEvidence(result.structuredContent);
mcpProof = assertBrowserNetworkEvidence(
browserScenarioCaptureSchema.parse(evidence.normalized_result),
site.origin,
);
if (attachment !== undefined) {
const connectedScenario = browserScenarioSchema.parse({
...scenario,
browser: { mode: "connect", ...attachment },
});
const connected = await client.callTool(
{ name: "capture_browser_scenario", arguments: connectedScenario },
{ timeout: 60_000 },
);
assert.notEqual(result.isError, true, JSON.stringify(result));
const evidence = parseEvidence(result.structuredContent);
mcpProof = assertBrowserNetworkEvidence(
browserScenarioCaptureSchema.parse(evidence.normalized_result),
site.origin,
);
if (attachment !== undefined) {
const connectedScenario = browserScenarioSchema.parse({
...scenario,
browser: { mode: "connect", ...attachment },
});
const connected = await client.callTool(
{ name: "capture_browser_scenario", arguments: connectedScenario },
{ timeout: 60_000 },
);
assert.notEqual(connected.isError, true, JSON.stringify(connected));
const connectedEvidence = parseEvidence(connected.structuredContent);
assert.deepEqual(
assertBrowserNetworkEvidence(
browserScenarioCaptureSchema.parse(
connectedEvidence.normalized_result,
),
site.origin,
"disconnected-external",
assert.notEqual(connected.isError, true, JSON.stringify(connected));
const connectedEvidence = parseEvidence(connected.structuredContent);
assert.deepEqual(
assertBrowserNetworkEvidence(
browserScenarioCaptureSchema.parse(
connectedEvidence.normalized_result,
),
cliProof,
);
assert.ok(
(await fetch(`${attachment.cdp_endpoint}/json/version`)).ok,
"Network capture closed the external browser",
);
}
} finally {
try {
await client.close();
} finally {
await transport.close();
}
site.origin,
"disconnected-external",
),
cliProof,
);
assert.ok(
(await fetch(`${attachment.cdp_endpoint}/json/version`)).ok,
"Network capture closed the external browser",
);
}
assert.deepEqual(mcpProof, cliProof);
for (const path of [
@ -180,7 +178,14 @@ export async function verifyBrowserNetworkEvidence(
profile_cleanup: true,
connected_network_verified: attachment !== undefined,
};
} catch (cause) {
primaryError = cause;
throw cause;
} finally {
await site.close();
const cleanup = [];
if (client !== undefined) cleanup.push(() => client.close());
if (transport !== undefined) cleanup.push(() => transport.close());
if (site !== undefined) cleanup.push(() => site.close());
await closeRuntimeFixtureResources(cleanup, primaryError);
}
}

View File

@ -15,6 +15,7 @@ import {
assertExportedScriptAnalysis,
} from "./browser-script-export-assertions.mjs";
import { mcpTextValue } from "./mcp-verifier-results.mjs";
import { closeRuntimeFixtureResources } from "./browser-runtime-fixture-lifecycle.mjs";
/** Verify capture → export → existing analysis through real CLI and stdio MCP. */
export async function verifyBrowserScriptExport(
@ -22,24 +23,29 @@ export async function verifyBrowserScriptExport(
entrypoint = fileURLToPath(new URL("../rea.mjs", import.meta.url)),
attachment,
) {
const site = await startBrowserScriptSite();
const root = await mkdtemp(join(tmpdir(), "rea-browser-script-export-"));
const env = {
...process.env,
REA_LOG_LEVEL: "silent",
HOPPER_LAUNCHER_PATH: "/rea-unconfigured-provider/hopper",
};
const cli = exportCli(entrypoint, env);
const scenario = scriptCaptureScenario(executable, site.origin);
const save = (name, capture) => saveCapture(root, name, capture);
const transport = new StdioClientTransport({
command: process.execPath,
args: [entrypoint, "mcp"],
env,
stderr: "pipe",
});
const client = new Client({ name: "web-script-real-e2e", version: "1" });
let site;
let root;
let transport;
let client;
let primaryError;
try {
site = await startBrowserScriptSite();
root = await mkdtemp(join(tmpdir(), "rea-browser-script-export-"));
const env = {
...process.env,
REA_LOG_LEVEL: "silent",
HOPPER_LAUNCHER_PATH: "/rea-unconfigured-provider/hopper",
};
const cli = exportCli(entrypoint, env);
const scenario = scriptCaptureScenario(executable, site.origin);
const save = (name, capture) => saveCapture(root, name, capture);
transport = new StdioClientTransport({
command: process.execPath,
args: [entrypoint, "mcp"],
env,
stderr: "pipe",
});
client = new Client({ name: "web-script-real-e2e", version: "1" });
const cliCapture = await cli(
"capture-browser-scenario",
JSON.stringify(scenario),
@ -103,11 +109,17 @@ export async function verifyBrowserScriptExport(
query_variants_isolated: true,
implicit_refetches: 0,
};
} catch (cause) {
primaryError = cause;
throw cause;
} finally {
await client.close();
await transport.close();
await site.close();
await rm(root, { recursive: true, force: true });
const cleanup = [];
if (client !== undefined) cleanup.push(() => client.close());
if (transport !== undefined) cleanup.push(() => transport.close());
if (site !== undefined) cleanup.push(() => site.close());
if (root !== undefined)
cleanup.push(() => rm(root, { recursive: true, force: true }));
await closeRuntimeFixtureResources(cleanup, primaryError);
}
}

View File

@ -12,35 +12,41 @@ import { parseEvidence } from "../../dist/domain/evidence.js";
import { webSourceLocationResultSchema } from "../../dist/domain/webSourceLocation.js";
import { startBrowserSourceMapSite } from "../fixtures/browser-source-map-site.mjs";
import { mcpTextValue } from "./mcp-verifier-results.mjs";
import { closeRuntimeFixtureResources } from "./browser-runtime-fixture-lifecycle.mjs";
/** Verify real Chrome capture → export → original compiler point through packaged CLI/MCP. */
export async function verifyBrowserSourceMap(
executable,
entrypoint = fileURLToPath(new URL("../rea.mjs", import.meta.url)),
) {
const site = await startBrowserSourceMapSite();
const root = await mkdtemp(join(tmpdir(), "rea-browser-source-map-"));
const env = {
...process.env,
REA_LOG_LEVEL: "silent",
HOPPER_LAUNCHER_PATH: "/rea-unconfigured-provider/hopper",
};
const cli = async (...args) => {
const { stdout } = await promisify(execFile)(
process.execPath,
[entrypoint, ...args, "--json"],
{ env, timeout: 45000, maxBuffer: 16 * 1024 * 1024 },
);
return parseEvidence(JSON.parse(stdout));
};
const transport = new StdioClientTransport({
command: process.execPath,
args: [entrypoint, "mcp"],
env,
stderr: "pipe",
});
const client = new Client({ name: "source-map-real-e2e", version: "1" });
let site;
let root;
let transport;
let client;
let primaryError;
try {
site = await startBrowserSourceMapSite();
root = await mkdtemp(join(tmpdir(), "rea-browser-source-map-"));
const env = {
...process.env,
REA_LOG_LEVEL: "silent",
HOPPER_LAUNCHER_PATH: "/rea-unconfigured-provider/hopper",
};
const cli = async (...args) => {
const { stdout } = await promisify(execFile)(
process.execPath,
[entrypoint, ...args, "--json"],
{ env, timeout: 45000, maxBuffer: 16 * 1024 * 1024 },
);
return parseEvidence(JSON.parse(stdout));
};
transport = new StdioClientTransport({
command: process.execPath,
args: [entrypoint, "mcp"],
env,
stderr: "pipe",
});
client = new Client({ name: "source-map-real-e2e", version: "1" });
const capture = await cli(
"capture-browser-scenario",
JSON.stringify({
@ -126,11 +132,17 @@ export async function verifyBrowserSourceMap(
selected_inert_userinfo_context_preserved: true,
public_point_cases: 4,
};
} catch (cause) {
primaryError = cause;
throw cause;
} finally {
await client.close();
await transport.close();
await site.close();
await rm(root, { recursive: true, force: true });
const cleanup = [];
if (client !== undefined) cleanup.push(() => client.close());
if (transport !== undefined) cleanup.push(() => transport.close());
if (site !== undefined) cleanup.push(() => site.close());
if (root !== undefined)
cleanup.push(() => rm(root, { recursive: true, force: true }));
await closeRuntimeFixtureResources(cleanup, primaryError);
}
}
function assertPoint(evidence, { site, input, capture, identity }) {

View File

@ -6,15 +6,21 @@ import { join } from "node:path";
import { chromium } from "playwright-core";
import { startBrowserVerifierSite } from "./fixtures/browser-verifier-site.mjs";
import { verifyBrowserDomDestinations } from "./lib/browser-dom-destinations-e2e.mjs";
import { closeRuntimeFixtureResources } from "./lib/browser-runtime-fixture-lifecycle.mjs";
import { requireOrdinaryWindowsVerifierCaller } from "./lib/windows-ordinary-user-verifier.mjs";
const executable = process.env.REA_BROWSER_EXECUTABLE;
if (!executable)
throw new Error("verify:browser:dom requires REA_BROWSER_EXECUTABLE");
const profile = await mkdtemp(join(tmpdir(), "rea-browser-dom-"));
const site = await startBrowserVerifierSite();
await requireOrdinaryWindowsVerifierCaller();
let profile;
let site;
let context;
let report;
let primaryError;
try {
profile = await mkdtemp(join(tmpdir(), "rea-browser-dom-"));
site = await startBrowserVerifierSite();
context = await chromium.launchPersistentContext(profile, {
executablePath: executable,
headless: true,
@ -50,9 +56,15 @@ try {
native_oracle: true,
verified: true,
};
} catch (cause) {
primaryError = cause;
throw cause;
} finally {
await context?.close();
await site.close();
await rm(profile, { recursive: true, force: true });
const cleanup = [];
if (context !== undefined) cleanup.push(() => context.close());
if (site !== undefined) cleanup.push(() => site.close());
if (profile !== undefined)
cleanup.push(() => rm(profile, { recursive: true, force: true }));
await closeRuntimeFixtureResources(cleanup, primaryError);
}
process.stdout.write(`${JSON.stringify(report)}\n`);

View File

@ -2,12 +2,14 @@
import { access } from "node:fs/promises";
import { verifyBrowserModules } from "./lib/browser-module-e2e.mjs";
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
import { requireOrdinaryWindowsVerifierCaller } from "./lib/windows-ordinary-user-verifier.mjs";
const executable = process.env.REA_BROWSER_EXECUTABLE;
if (!executable)
throw new Error(
"verify:browser:modules requires REA_BROWSER_EXECUTABLE for caller-supplied Chromium",
);
await requireOrdinaryWindowsVerifierCaller();
await access(executable);
const run = createVerifierRun();
const proof = await verifyBrowserModules(executable, process.argv[2]);

View File

@ -2,12 +2,14 @@
import { access } from "node:fs/promises";
import { verifyBrowserNetworkEvidence } from "./lib/browser-network-e2e.mjs";
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
import { requireOrdinaryWindowsVerifierCaller } from "./lib/windows-ordinary-user-verifier.mjs";
const executable = process.env.REA_BROWSER_EXECUTABLE;
if (executable === undefined || executable === "")
throw new Error(
"verify:browser:network requires REA_BROWSER_EXECUTABLE pointing to an installed Chrome-family browser",
);
await requireOrdinaryWindowsVerifierCaller();
await access(executable);
const run = createVerifierRun();
const proof = await verifyBrowserNetworkEvidence(executable, process.argv[2]);

View File

@ -2,12 +2,14 @@
import { access } from "node:fs/promises";
import { verifyBrowserScriptExport } from "./lib/browser-script-export-e2e.mjs";
import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs";
import { requireOrdinaryWindowsVerifierCaller } from "./lib/windows-ordinary-user-verifier.mjs";
const executable = process.env.REA_BROWSER_EXECUTABLE;
if (executable === undefined || executable === "")
throw new Error(
"verify:browser:scripts requires REA_BROWSER_EXECUTABLE pointing to an installed Chrome-family browser",
);
await requireOrdinaryWindowsVerifierCaller();
await access(executable);
const run = createVerifierRun();
const proof = await verifyBrowserScriptExport(executable, process.argv[2]);