Files
rea/tests/fixtures/fakeCdpBrowserTypes.ts
T
0155b89953 fix(browser): name web-bundle budgets and recover web deadlines (#6036)
* fix(browser): name web-bundle budgets and recover web deadlines

Name the existing heap, per-script, and total web-bundle phases, and reject a per-script deadline above the total. Promote capture, CDP command, source-map decode, and source-map fetch deadlines at today's defaults. Name DevTools timeoutMs, and state that discovery, cleanup grace, byte budgets, and Electron hook retention have no runtime override.

Refs #5910

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): apply selected web deadlines to the owning phase

Keep HTTP and browser-socket discovery on the fixed discovery deadline so a
short command_timeout_ms starts at the handshake. Apply scenario
command_timeout_ms to launch startup and the primary connect session, and
keep service-worker restoration on the fixed 5000 ms grace. Omit
command_timeout_ms from recovery text when the operation does not accept it.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): retain scenario commands that finish after their deadline

A timed-out scenario command stays owned so cleanup can close a late
browser or context and restore a mutation that lands after the deadline.
Child storage replies use that deadline, scenario recovery names
command_timeout_ms in the capture JSON, and the session test connection
implements beginCleanupGrace.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): keep child command timeouts as the public failure

A nested command such as Page.enable that is delivered but never answered
was stored as protocol_error, hiding the command name, selected deadline,
and recovery. Store the typed timeout and assert that public error.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): keep runtime cleanup on the fixed grace

Switch runtime restoration to the cleanup grace before the first send so a
short command_timeout_ms cannot fail an otherwise successful observation.
Stop advertising command_timeout_ms on list_browser_targets, which never
bounds a post-discovery command.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* test(browser): prove a short command deadline cannot fail runtime cleanup

Drive restoration through the runtime fixture. A cleanup command that
outlives command_timeout_ms still succeeds, and a stalled restoration
names the fixed 5000 ms grace.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): name the effective source-map decode deadline

codecBudgetLimitation reported a fixed 20-second deadline after a
caller selected decode_timeout_ms. Result and Evidence limitations
now name that effective millisecond deadline.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): separate handshake and target-attach deadlines

A browser-level Target.attachToTarget no longer shares the WebSocket
handshake budget. Blocked service-worker attachment keeps discovery on
its fixed deadline and applies command_timeout_ms to the later handshake
and attach.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): name the web-bundle resource each runtime exhausts

Bun ignores the V8 old-space flag. A Windows Job reports the process
commit limit, and other Bun hosts no longer suggest raising max_heap_mb.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): cite the browser-socket discovery message budget

WebSocket discovery enforces the 64 MiB protocol budget. Timeout
recovery no longer advertises the 8 MiB HTTP document budget.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): bound the blocked service-worker check before discovery

The first registration check has its own fixed 10s deadline. Discovery,
handshake, and Target.attachToTarget stay on their separate deadlines.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(browser): name the operand that stopped web-bundle admission

Host heap pressure no longer claims the fixed result budget is exhausted.
A Windows Bun allocation before the commit limit still names that limit.

Co-authored-by: morluto <morluto@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
2026-10-22 05:47:38 +08:00

132 lines
5.6 KiB
TypeScript

import type { JsonValue } from "../../src/domain/jsonValue.js";
import type { CdpEvent } from "../../src/browser/CdpConnection.js";
export interface FakeCdpCommand {
readonly id: number;
readonly method: string;
readonly params: Readonly<Record<string, unknown>>;
readonly sessionId?: string;
}
export interface FakeCdpBrowser {
readonly endpoint: string;
readonly browserWebSocketUrl: string;
readonly allowedOrigin: string;
readonly commands: readonly FakeCdpCommand[];
/** Actual WebSocket connections still held by the wire fixture. */
activeConnectionCount(): number;
/** WebSocket upgrades accepted over the fixture's lifetime. */
openedConnectionCount(): number;
/** Deliver actual malformed wire data without bypassing the production transport parser. */
emitRawMessage(message: string): void;
emitEvent(event: CdpEvent): void;
readonly httpRequests: readonly {
readonly url: string;
readonly authorization: string | undefined;
readonly cookie: string | undefined;
readonly referer: string | undefined;
}[];
close(): Promise<void>;
}
export interface FakeOptions {
/** Send these commands' producer events before acknowledging completion, as a wire barrier. */
readonly eventsBeforeReply?: readonly string[];
/** Return a native-shaped command rejection through the actual wire parser. */
readonly commandError?: (
command: FakeCdpCommand,
) => { readonly code: number; readonly message: string } | undefined;
/** Producer reply seam preserves the real HTTP/WebSocket transport and command parser. */
readonly commandResult?: (
command: FakeCdpCommand,
origin: string,
frameReads: number,
) => Readonly<Record<string, unknown>> | undefined;
/** Return undefined to use the stock producer events; an empty array suppresses them. */
readonly commandEvents?: (
command: FakeCdpCommand,
origin: string,
) => readonly CdpEvent[] | undefined;
/** Delay each HTTP discovery document so a short command deadline can be observed separately. */
readonly discoveryDelayMs?: number;
/** Delay WebSocket upgrade acceptance so handshake and attach deadlines stay distinct. */
readonly handshakeDelayMs?: number;
readonly malformedDiscovery?: boolean;
readonly oversizedDiscovery?: boolean;
readonly invalidBrowserWebSocket?: boolean;
readonly pageScopedVersionWebSocket?: boolean;
readonly omitTargetWebSocket?: boolean;
readonly additionalPageWithWebSocket?: boolean;
readonly additionalPageWithoutWebSocket?: boolean;
readonly additionalPageCount?: number;
readonly additionalElectronPageCount?: number;
readonly invalidAttachedSession?: boolean;
readonly malformedMessageOnMethod?: string;
readonly malformedEventOnMethod?: string;
readonly malformedEventShapeOnMethod?: string;
readonly closeOnMethod?: string;
readonly hangOnMethod?: string;
readonly unsupportedMethods?: readonly string[];
readonly transitionalFrameReads?: number;
readonly attachedFrameUrl?: string;
readonly frameUrlAfterFirstRead?: string;
readonly navigateDuringObservationUrl?: string;
readonly navigateDuringCaptureUrl?: string;
readonly navigateDuringScreenshotUrl?: string;
readonly screenshotDocumentLoader?: string;
readonly extraCollections?: boolean;
readonly indexedDbDateKeys?: boolean;
readonly foreignSessionEvents?: boolean;
readonly redirectToDisallowedOrigin?: boolean;
readonly redirectFromDisallowedOrigin?: boolean;
readonly redirectWithinOrigin?: boolean;
readonly malformedRedirectResponse?: boolean;
readonly omitRedirectResponse?: boolean;
readonly redirectResponseUrl?: string;
readonly redirectResponseEnvelope?: unknown;
readonly responseAfterMalformedUrl?: string;
readonly unrelatedWorker?: boolean;
readonly binaryWebSocketEvent?: boolean;
/** Emit an allowed WebSocket creation without any frames in the capture window. */
readonly webSocketWithoutFrames?: boolean;
readonly invalidBinaryWebSocketEvent?: boolean;
readonly sourceMapBody?: string;
/** Accept a source-map request and leave the response open. */
readonly hangSourceMap?: boolean;
readonly sourceMapRedirect?: string;
readonly sessionTimeline?:
| "same_origin"
| "outside_policy"
| "target_detached"
| "target_crashed";
readonly sessionTimelineEventCount?: number;
readonly sessionRedirectResourceType?: "Document" | "Fetch" | "Script";
readonly closeAfterMethod?: string;
readonly sensitiveShapes?: boolean;
/** Deliver a console argument the protocol spells as `{ type: "object", subtype: "null" }`. */
readonly nullConsoleArgument?: boolean;
readonly cachedResponseBody?: string;
readonly invalidResponseBodyBase64?: boolean;
readonly webMcpTools?: boolean;
readonly webMcpConsequential?: JsonValue;
/** Replaces the primary tool's registration stack; returning `undefined` omits it. */
readonly webMcpStackTrace?: (origin: string) => JsonValue | undefined;
readonly webMcpSameUrlRegistrations?: "retain" | "remove-second";
readonly webMcpFrameCount?: number;
readonly webMcpSchemaPropertyCount?: number;
readonly webMcpInputSchema?: JsonValue;
readonly webMcpChildLeavesScope?: boolean;
readonly webMcpChildTransientBlank?: boolean;
readonly webMcpChildRecoversAfterTransient?: boolean;
readonly webMcpChildNavigatesAllowed?: boolean;
readonly electronFileUrl?: string;
/** Omit attached from the Electron page's HTTP discovery target. */
readonly omitElectronTargetAttachmentState?: boolean;
readonly duplicateElectronInventory?: boolean;
readonly electronInventoryCount?: number;
readonly urlShapedAllowedTitle?:
| boolean
| "host-path"
| "root-relative"
| "prefixed";
}