mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:20:43 +00:00
test: share browser cdp fixtures
This commit is contained in:
@@ -28,6 +28,42 @@ type CdpReplyHandler = (
|
||||
msg: { id?: number; method?: string; params?: Record<string, unknown> },
|
||||
socket: WebSocket,
|
||||
) => void;
|
||||
type CdpMockMessage = Parameters<CdpReplyHandler>[0];
|
||||
|
||||
function sendCdpResult(socket: WebSocket, id: number | undefined, result: Record<string, unknown>) {
|
||||
socket.send(JSON.stringify({ id, result }));
|
||||
}
|
||||
|
||||
function replyToPageEnable(msg: CdpMockMessage, socket: WebSocket): boolean {
|
||||
if (msg.method !== "Page.enable") {
|
||||
return false;
|
||||
}
|
||||
sendCdpResult(socket, msg.id, {});
|
||||
return true;
|
||||
}
|
||||
|
||||
function replyWithScreenshotData(msg: CdpMockMessage, socket: WebSocket, data: string): boolean {
|
||||
if (msg.method !== "Page.captureScreenshot") {
|
||||
return false;
|
||||
}
|
||||
sendCdpResult(socket, msg.id, { data: Buffer.from(data).toString("base64") });
|
||||
return true;
|
||||
}
|
||||
|
||||
function replyToViewportCommandOrScreenshot(
|
||||
msg: CdpMockMessage,
|
||||
socket: WebSocket,
|
||||
data: string,
|
||||
): boolean {
|
||||
if (
|
||||
msg.method === "Emulation.setDeviceMetricsOverride" ||
|
||||
msg.method === "Emulation.clearDeviceMetricsOverride"
|
||||
) {
|
||||
sendCdpResult(socket, msg.id, {});
|
||||
return true;
|
||||
}
|
||||
return replyWithScreenshotData(msg, socket, data);
|
||||
}
|
||||
|
||||
async function startMockWsServer(handle: CdpReplyHandler) {
|
||||
const wss = new WebSocketServer({ port: 0, host: "127.0.0.1" });
|
||||
@@ -60,6 +96,24 @@ describe("cdp internal", () => {
|
||||
}
|
||||
});
|
||||
|
||||
async function captureScreenshotAndObserveParams(
|
||||
options: Omit<Parameters<typeof captureScreenshot>[0], "wsUrl">,
|
||||
) {
|
||||
const observed: Array<Record<string, unknown>> = [];
|
||||
const server = await startMockWsServer((msg, socket) => {
|
||||
if (replyToPageEnable(msg, socket)) {
|
||||
return;
|
||||
}
|
||||
if (msg.method === "Page.captureScreenshot") {
|
||||
observed.push(msg.params ?? {});
|
||||
replyWithScreenshotData(msg, socket, "JPG");
|
||||
}
|
||||
});
|
||||
wss = server.wss;
|
||||
const buf = await captureScreenshot({ wsUrl: server.wsUrl, ...options });
|
||||
return { buf, observed };
|
||||
}
|
||||
|
||||
describe("captureScreenshot", () => {
|
||||
it("captures a PNG without fullPage", async () => {
|
||||
const server = await startMockWsServer((msg, socket) => {
|
||||
@@ -104,24 +158,10 @@ describe("cdp internal", () => {
|
||||
});
|
||||
|
||||
it("clamps out-of-range JPEG quality values into [0, 100]", async () => {
|
||||
const observed: Array<Record<string, unknown>> = [];
|
||||
const server = await startMockWsServer((msg, socket) => {
|
||||
if (msg.method === "Page.enable") {
|
||||
socket.send(JSON.stringify({ id: msg.id, result: {} }));
|
||||
return;
|
||||
}
|
||||
if (msg.method === "Page.captureScreenshot") {
|
||||
observed.push(msg.params ?? {});
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
id: msg.id,
|
||||
result: { data: Buffer.from("JPG").toString("base64") },
|
||||
}),
|
||||
);
|
||||
}
|
||||
const { observed } = await captureScreenshotAndObserveParams({
|
||||
format: "jpeg",
|
||||
quality: 250,
|
||||
});
|
||||
wss = server.wss;
|
||||
await captureScreenshot({ wsUrl: server.wsUrl, format: "jpeg", quality: 250 });
|
||||
expect(observed[0]?.format).toBe("jpeg");
|
||||
expect(observed[0]?.quality).toBe(100);
|
||||
});
|
||||
@@ -160,22 +200,9 @@ describe("cdp internal", () => {
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (msg.method === "Emulation.setDeviceMetricsOverride") {
|
||||
socket.send(JSON.stringify({ id: msg.id, result: {} }));
|
||||
if (replyToViewportCommandOrScreenshot(msg, socket, "FULL")) {
|
||||
return;
|
||||
}
|
||||
if (msg.method === "Emulation.clearDeviceMetricsOverride") {
|
||||
socket.send(JSON.stringify({ id: msg.id, result: {} }));
|
||||
return;
|
||||
}
|
||||
if (msg.method === "Page.captureScreenshot") {
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
id: msg.id,
|
||||
result: { data: Buffer.from("FULL").toString("base64") },
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
wss = server.wss;
|
||||
const buf = await captureScreenshot({ wsUrl: server.wsUrl, fullPage: true });
|
||||
@@ -650,24 +677,7 @@ describe("cdp internal", () => {
|
||||
|
||||
describe("captureScreenshot branch coverage", () => {
|
||||
it("uses the default jpeg quality when opts.quality is omitted", async () => {
|
||||
const observed: Array<Record<string, unknown>> = [];
|
||||
const server = await startMockWsServer((msg, socket) => {
|
||||
if (msg.method === "Page.enable") {
|
||||
socket.send(JSON.stringify({ id: msg.id, result: {} }));
|
||||
return;
|
||||
}
|
||||
if (msg.method === "Page.captureScreenshot") {
|
||||
observed.push(msg.params ?? {});
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
id: msg.id,
|
||||
result: { data: Buffer.from("J").toString("base64") },
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
wss = server.wss;
|
||||
await captureScreenshot({ wsUrl: server.wsUrl, format: "jpeg" });
|
||||
const { observed } = await captureScreenshotAndObserveParams({ format: "jpeg" });
|
||||
expect(observed[0]?.quality).toBe(85);
|
||||
});
|
||||
|
||||
@@ -720,22 +730,9 @@ describe("cdp internal", () => {
|
||||
socket.send(JSON.stringify({ id: msg.id, result: { result: { value: {} } } }));
|
||||
return;
|
||||
}
|
||||
if (msg.method === "Emulation.setDeviceMetricsOverride") {
|
||||
socket.send(JSON.stringify({ id: msg.id, result: {} }));
|
||||
if (replyToViewportCommandOrScreenshot(msg, socket, "C")) {
|
||||
return;
|
||||
}
|
||||
if (msg.method === "Emulation.clearDeviceMetricsOverride") {
|
||||
socket.send(JSON.stringify({ id: msg.id, result: {} }));
|
||||
return;
|
||||
}
|
||||
if (msg.method === "Page.captureScreenshot") {
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
id: msg.id,
|
||||
result: { data: Buffer.from("C").toString("base64") },
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
wss = server.wss;
|
||||
const buf = await captureScreenshot({ wsUrl: server.wsUrl, fullPage: true });
|
||||
|
||||
@@ -2,40 +2,13 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
getPwToolsCoreSessionMocks,
|
||||
installPwToolsCoreTestHooks,
|
||||
setPwToolsCoreCurrentPage,
|
||||
setPwToolsCoreCurrentRefLocator,
|
||||
} from "./pw-tools-core.test-harness.js";
|
||||
|
||||
let currentPage: Record<string, unknown> | null = null;
|
||||
let currentRefLocator: Record<string, unknown> | null = null;
|
||||
let pageState: {
|
||||
console: unknown[];
|
||||
armIdUpload: number;
|
||||
armIdDialog: number;
|
||||
armIdDownload: number;
|
||||
} = {
|
||||
console: [],
|
||||
armIdUpload: 0,
|
||||
armIdDialog: 0,
|
||||
armIdDownload: 0,
|
||||
};
|
||||
|
||||
const sessionMocks = vi.hoisted(() => ({
|
||||
getPageForTargetId: vi.fn(async () => {
|
||||
if (!currentPage) {
|
||||
throw new Error("missing page");
|
||||
}
|
||||
return currentPage;
|
||||
}),
|
||||
ensurePageState: vi.fn(() => pageState),
|
||||
forceDisconnectPlaywrightForTarget: vi.fn(async () => {}),
|
||||
restoreRoleRefsForTarget: vi.fn(() => {}),
|
||||
storeRoleRefsForTarget: vi.fn(() => {}),
|
||||
refLocator: vi.fn(() => {
|
||||
if (!currentRefLocator) {
|
||||
throw new Error("missing locator");
|
||||
}
|
||||
return currentRefLocator;
|
||||
}),
|
||||
rememberRoleRefsForTarget: vi.fn(() => {}),
|
||||
}));
|
||||
const tmpDirMocks = vi.hoisted(() => ({
|
||||
resolvePreferredOpenClawTmpDir: vi.fn(() => "/tmp/openclaw"),
|
||||
}));
|
||||
@@ -45,9 +18,11 @@ const chromeMocks = vi.hoisted(() => ({
|
||||
const clientFetchMocks = vi.hoisted(() => ({
|
||||
resolveBrowserRateLimitMessage: vi.fn(() => undefined),
|
||||
}));
|
||||
vi.mock("./pw-session.js", () => sessionMocks);
|
||||
vi.mock("./chrome.js", () => chromeMocks);
|
||||
vi.mock("./client-fetch.js", () => clientFetchMocks);
|
||||
|
||||
const sessionMocks = getPwToolsCoreSessionMocks();
|
||||
|
||||
let mod: Pick<
|
||||
typeof import("./pw-tools-core.downloads.js"),
|
||||
"downloadViaPlaywright" | "waitForDownloadViaPlaywright"
|
||||
@@ -56,6 +31,8 @@ let mod: Pick<
|
||||
let tmpDirModule: typeof import("../infra/tmp-openclaw-dir.js");
|
||||
|
||||
describe("pw-tools-core", () => {
|
||||
installPwToolsCoreTestHooks();
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.doMock("./pw-session.js", () => sessionMocks);
|
||||
vi.doMock("./chrome.js", () => chromeMocks);
|
||||
@@ -75,18 +52,6 @@ describe("pw-tools-core", () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
currentPage = null;
|
||||
currentRefLocator = null;
|
||||
pageState = {
|
||||
console: [],
|
||||
armIdUpload: 0,
|
||||
armIdDialog: 0,
|
||||
armIdDownload: 0,
|
||||
};
|
||||
|
||||
for (const fn of Object.values(sessionMocks)) {
|
||||
fn.mockClear();
|
||||
}
|
||||
for (const fn of Object.values(tmpDirMocks)) {
|
||||
fn.mockClear();
|
||||
}
|
||||
@@ -144,7 +109,7 @@ describe("pw-tools-core", () => {
|
||||
}
|
||||
});
|
||||
const off = vi.fn();
|
||||
currentPage = { on, off };
|
||||
setPwToolsCoreCurrentPage({ on, off });
|
||||
return {
|
||||
trigger: (download: unknown) => {
|
||||
downloadHandler?.(download);
|
||||
@@ -209,7 +174,7 @@ describe("pw-tools-core", () => {
|
||||
const harness = createDownloadEventHarness();
|
||||
|
||||
const click = vi.fn(async () => {});
|
||||
currentRefLocator = { click };
|
||||
setPwToolsCoreCurrentRefLocator({ click });
|
||||
|
||||
const saveAs = vi.fn(async (outPath: string) => {
|
||||
await fs.writeFile(outPath, "report-content", "utf8");
|
||||
@@ -316,7 +281,7 @@ describe("pw-tools-core", () => {
|
||||
}
|
||||
});
|
||||
const off = vi.fn();
|
||||
currentPage = { on, off };
|
||||
setPwToolsCoreCurrentPage({ on, off });
|
||||
|
||||
const resp = {
|
||||
url: () => "https://example.com/api/data",
|
||||
|
||||
Reference in New Issue
Block a user