Files
rea/tests/boundary/browser/cdpCaptureNavigation.test.ts

184 lines
5.5 KiB
TypeScript

import { expect, it, onTestFinished } from "vitest";
import { inspectWebPageInputSchema } from "../../../src/domain/browserObservation.js";
import { CdpBrowserProvider } from "../../../src/browser/CdpBrowserProvider.js";
import { BrowserObservationError } from "../../../src/domain/browserObservationError.js";
import { startFakeCdpBrowser } from "../../fixtures/fakeCdpBrowser.js";
it("captures a page without aborting on a duplicate frame event", async () => {
const browser = await startFakeCdpBrowser({ sessionTimeline: "same_origin" });
onTestFinished(async () => {
await browser.close();
});
const result = await new CdpBrowserProvider().inspectPage(
inspectWebPageInputSchema.parse({
cdp_endpoint: browser.endpoint,
allowed_origins: [browser.allowedOrigin],
target_id: "allowed-page",
observation_ms: 0,
}),
);
expect(result.ok).toBe(true);
});
it("accepts child navigation when the frame-tree root has an identity", async () => {
const browser = await startFakeCdpBrowser({
eventsBeforeReply: ["Network.enable"],
commandResult: (command, origin) =>
command.method === "Page.getFrameTree"
? {
frameTree: {
frame: { id: "main", url: `${origin}/app` },
childFrames: [
{
frame: {
id: "child",
parentId: "main",
url: `${origin}/child`,
},
},
],
},
}
: undefined,
commandEvents: (command, origin) =>
command.method === "Network.enable"
? [
{
method: "Page.frameNavigated",
sessionId: command.sessionId,
params: {
frame: {
id: "child",
parentId: "main",
url: `${origin}/child`,
},
},
},
]
: undefined,
});
const provider = new CdpBrowserProvider();
try {
const result = await provider.inspectPage(
inspectWebPageInputSchema.parse({
cdp_endpoint: browser.endpoint,
allowed_origins: [browser.allowedOrigin],
target_id: "allowed-page",
observation_ms: 0,
}),
);
expect(result.ok).toBe(true);
} finally {
await provider.close();
await browser.close();
}
});
it.each([false, true])(
"requires the actual frame-tree root identity before observing (child event: %s)",
async (navigateChild) => {
const commands: string[] = [];
const browser = await startFakeCdpBrowser({
eventsBeforeReply: ["Network.enable"],
commandResult: (command, origin) => {
commands.push(command.method);
if (command.method !== "Page.getFrameTree") return undefined;
return {
frameTree: {
frame: { url: `${origin}/app` },
childFrames: [
{
frame: {
id: "child",
parentId: "main",
url: `${origin}/child`,
},
},
],
},
};
},
commandEvents: (command, origin) =>
navigateChild && command.method === "Network.enable"
? [
{
method: "Page.frameNavigated",
sessionId: command.sessionId,
params: {
frame: {
id: "child",
parentId: "main",
url: `${origin}/child`,
},
},
},
]
: undefined,
});
const provider = new CdpBrowserProvider();
try {
const result = await provider.inspectPage(
inspectWebPageInputSchema.parse({
cdp_endpoint: browser.endpoint,
allowed_origins: [browser.allowedOrigin],
target_id: "allowed-page",
observation_ms: 0,
}),
);
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.error).toBeInstanceOf(BrowserObservationError);
expect(result.error).toMatchObject({ reason: "protocol_error" });
}
expect(commands).not.toContain("Network.enable");
expect(commands).not.toContain("Runtime.enable");
expect(commands).not.toContain("Debugger.enable");
} finally {
await provider.close();
await browser.close();
}
},
);
it("does not promote a child when the final frame-tree root loses its identity", async () => {
let reads = 0;
const browser = await startFakeCdpBrowser({
commandResult: (command, origin) => {
if (command.method !== "Page.getFrameTree") return undefined;
reads += 1;
return {
frameTree: {
frame: {
...(reads === 1 ? { id: "main" } : {}),
url: `${origin}/app`,
},
childFrames: [
{
frame: { id: "child", parentId: "main", url: `${origin}/child` },
},
],
},
};
},
});
const provider = new CdpBrowserProvider();
try {
const result = await provider.inspectPage(
inspectWebPageInputSchema.parse({
cdp_endpoint: browser.endpoint,
allowed_origins: [browser.allowedOrigin],
target_id: "allowed-page",
observation_ms: 0,
}),
);
expect(reads).toBeGreaterThanOrEqual(2);
expect(result.ok).toBe(false);
if (!result.ok)
expect(result.error).toMatchObject({ reason: "protocol_error" });
} finally {
await provider.close();
await browser.close();
}
});