Files
rea/src/browser/execution/CdpExecutionWindow.test.ts
T
morluto 0bd14ca16c fix(browser): preserve uncertain main-frame navigation identity
Own CDP frame applicability and identity at the parsed event boundary. Preserve malformed or incomplete main-frame facts, recognize replacement roots, and carry the same document identity through captures, screenshots, timelines, and execution windows.

Validation: full check:ci and docs:check; 763 browser and dispatch tests passed, 6 skipped. Independent source and fixture-lifecycle review passed. Local real-Chrome behavior was not exercised.

Closes #5665
2026-10-21 07:16:47 +08:00

120 lines
3.7 KiB
TypeScript

import { expect, it, vi } from "vitest";
import { CdpExecutionWindow } from "./CdpExecutionWindow.js";
it("settles an already lost transport without arming a timer that cannot resolve", async () => {
const window = new CdpExecutionWindow({
target: { frame_id: "selected-main" },
operation: "observe_web_execution",
options: {},
});
window.end("target_terminated");
await expect(window.start(30_000)).resolves.toBe("target_terminated");
expect(window.active).toBe(false);
expect(window.armedAt).toBeUndefined();
});
it("ends the actual armed window at its selected duration and disposes its timer", async () => {
vi.useFakeTimers();
const window = new CdpExecutionWindow({
target: { frame_id: "selected-main" },
operation: "observe_web_execution",
options: {},
});
try {
const result = window.start(10);
expect(window.active).toBe(true);
vi.advanceTimersByTime(10);
await expect(result).resolves.toBe("window_elapsed");
expect(window.active).toBe(false);
expect(vi.getTimerCount()).toBe(0);
} finally {
window.dispose();
vi.useRealTimers();
}
});
it("settles caller cancellation and removes its local timer", async () => {
vi.useFakeTimers();
const controller = new AbortController();
const window = new CdpExecutionWindow({
target: { frame_id: "selected-main" },
operation: "observe_web_execution",
options: { signal: controller.signal },
});
try {
const reason = new Error("operator stopped the armed window");
const result = window.start(30_000).catch((error: unknown) => error);
controller.abort(reason);
const failure = await result;
expect(failure).toMatchObject({
_tag: "AnalysisCancelledError",
cause: reason,
});
expect(() => window.check()).toThrow(failure as Error);
const endedAt = window.endedAt;
window.end("target_terminated");
expect(window.reason).toBeUndefined();
expect(window.endedAt).toBe(endedAt);
await expect(window.start(30_000)).rejects.toBe(failure);
expect(window.active).toBe(false);
expect(vi.getTimerCount()).toBe(0);
} finally {
window.dispose();
vi.useRealTimers();
}
});
it("keeps a root document transition distinct from a child frame event", async () => {
const root = new CdpExecutionWindow({
target: { frame_id: "selected-main" },
operation: "observe_web_execution",
options: {},
});
const rootResult = root.start(30_000);
root.ingest({
method: "Page.frameNavigated",
params: { frame: { id: "new-main", url: "https://example.test/" } },
});
await expect(rootResult).resolves.toBe("document_changed");
const child = new CdpExecutionWindow({
target: { frame_id: "selected-main" },
operation: "observe_web_execution",
options: {},
});
const childResult = child.start(30_000);
child.ingest({
method: "Page.frameNavigated",
params: {
frame: {
id: "child-frame",
parentId: "selected-main",
url: "https://example.test/child",
},
},
});
expect(child.active).toBe(true);
child.end("window_elapsed");
await expect(childResult).resolves.toBe("window_elapsed");
});
it("surfaces malformed frame identity as a protocol failure without guessing a transition", async () => {
const window = new CdpExecutionWindow({
target: { frame_id: "selected-main" },
operation: "observe_web_execution",
options: {},
});
const result = window.start(30_000);
window.ingest({
method: "Page.frameNavigated",
params: {
frame: { id: "child-frame", parentId: 7, url: "https://example.test/" },
},
});
await expect(result).rejects.toMatchObject({
_tag: "BrowserObservationError",
reason: "protocol_error",
});
expect(window.reason).toBeUndefined();
});