184 lines
5.5 KiB
TypeScript
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();
|
|
}
|
|
});
|