From d03366214533da4bbdf2c03b7a7e93e826e06d4c Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 20:33:13 +0100 Subject: [PATCH] test: share browser cdp fixtures --- .../browser/src/browser/cdp.internal.test.ts | 123 +++++++++--------- ...-core.waits-next-download-saves-it.test.ts | 63 ++------- 2 files changed, 74 insertions(+), 112 deletions(-) diff --git a/extensions/browser/src/browser/cdp.internal.test.ts b/extensions/browser/src/browser/cdp.internal.test.ts index 8bff372dac7..a562148abb5 100644 --- a/extensions/browser/src/browser/cdp.internal.test.ts +++ b/extensions/browser/src/browser/cdp.internal.test.ts @@ -28,6 +28,42 @@ type CdpReplyHandler = ( msg: { id?: number; method?: string; params?: Record }, socket: WebSocket, ) => void; +type CdpMockMessage = Parameters[0]; + +function sendCdpResult(socket: WebSocket, id: number | undefined, result: Record) { + 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[0], "wsUrl">, + ) { + const observed: Array> = []; + 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> = []; - 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> = []; - 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 }); diff --git a/extensions/browser/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts b/extensions/browser/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts index f427df805f5..38600433ee8 100644 --- a/extensions/browser/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts +++ b/extensions/browser/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts @@ -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 | null = null; -let currentRefLocator: Record | 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",