* fix(browser): preserve unknown HTTP response comparison fields * fix(browser): retain proven request inventory changes * fix(javascript): preserve Electron identity and avoid quadratic property scans Share visible Electron mutations with wrapper expansion, index static object literal properties once, and align MCP assertions with current contracts. * fix(javascript): track writes through symbolic Electron aliases Resolve mutation targets through the same factories, module tables, containers, and conditional origins as call analysis. Share mutation coverage between direct and wrapper scans while isolating origin caches and preserving exact property paths, local rebinding semantics, and analysis resource limits. * fix(javascript): preserve container slots and imported mutation origins * perf(javascript): defer container mutation replay until property reads * fix(javascript): preserve captured object identities and write order * fix(javascript): preserve ordered mutation origins * fix(javascript): honor property mutation constraints * test(web): narrow PR to HTTP and CLI comparison regressions --------- Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
import { startFakeCdpBrowser, type FakeCdpBrowser } from "./fakeCdpBrowser.js";
|
|
|
|
export type HttpRequestObservation = {
|
|
readonly requestId: string;
|
|
readonly path?: string;
|
|
readonly status?: number;
|
|
readonly mimeType?: string;
|
|
readonly encodedDataLength?: number;
|
|
};
|
|
|
|
type CdpEvent = Parameters<FakeCdpBrowser["emitEvent"]>[0];
|
|
|
|
const requestEvents = (
|
|
observation: HttpRequestObservation,
|
|
origin: string,
|
|
sessionId: string | undefined,
|
|
): CdpEvent[] => {
|
|
const session = sessionId === undefined ? {} : { sessionId };
|
|
const url = `${origin}${observation.path ?? "/api/items"}`;
|
|
const { requestId, status, mimeType, encodedDataLength } = observation;
|
|
const events: CdpEvent[] = [
|
|
{
|
|
...session,
|
|
method: "Network.requestWillBeSent",
|
|
params: {
|
|
requestId,
|
|
timestamp: 1,
|
|
type: "Fetch",
|
|
request: { url, method: "GET", headers: {} },
|
|
initiator: { type: "other" },
|
|
},
|
|
},
|
|
];
|
|
if (status !== undefined || mimeType !== undefined)
|
|
events.push({
|
|
...session,
|
|
method: "Network.responseReceived",
|
|
params: {
|
|
requestId,
|
|
timestamp: 2,
|
|
type: "Fetch",
|
|
response: {
|
|
url,
|
|
headers: {},
|
|
...(status === undefined ? {} : { status }),
|
|
...(mimeType === undefined ? {} : { mimeType }),
|
|
},
|
|
},
|
|
});
|
|
if (encodedDataLength !== undefined)
|
|
events.push({
|
|
...session,
|
|
method: "Network.loadingFinished",
|
|
params: { requestId, timestamp: 3, encodedDataLength },
|
|
});
|
|
return events;
|
|
};
|
|
|
|
/** Capture changing response coverage through the real CDP wire boundary. */
|
|
export const startHttpComparisonBrowser = async (
|
|
initial: readonly HttpRequestObservation[],
|
|
): Promise<{
|
|
readonly browser: FakeCdpBrowser;
|
|
setRequests(next: readonly HttpRequestObservation[]): void;
|
|
}> => {
|
|
let requests = initial;
|
|
const browser = await startFakeCdpBrowser({
|
|
eventsBeforeReply: ["Network.enable"],
|
|
commandEvents(command, origin) {
|
|
return command.method === "Network.enable"
|
|
? requests.flatMap((request) =>
|
|
requestEvents(request, origin, command.sessionId),
|
|
)
|
|
: undefined;
|
|
},
|
|
});
|
|
return {
|
|
browser,
|
|
setRequests(next) {
|
|
requests = next;
|
|
},
|
|
};
|
|
};
|