From 09fa33f7e27d78bc1ab96c83b93a0dc4983151bd Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 14 Feb 2026 20:54:51 +0000 Subject: [PATCH] refactor(test): share pw-tools-core test setup --- ...re.clamps-timeoutms-scrollintoview.test.ts | 74 +++++------------- ...ls-core.last-file-chooser-arm-wins.test.ts | 62 ++++----------- ...-core.screenshots-element-selector.test.ts | 78 ++++++------------- src/browser/pw-tools-core.test-harness.ts | 64 +++++++++++++++ ...-core.waits-next-download-saves-it.test.ts | 70 +++++------------ 5 files changed, 139 insertions(+), 209 deletions(-) create mode 100644 src/browser/pw-tools-core.test-harness.ts diff --git a/src/browser/pw-tools-core.clamps-timeoutms-scrollintoview.test.ts b/src/browser/pw-tools-core.clamps-timeoutms-scrollintoview.test.ts index 55216b79bb..f0695634be 100644 --- a/src/browser/pw-tools-core.clamps-timeoutms-scrollintoview.test.ts +++ b/src/browser/pw-tools-core.clamps-timeoutms-scrollintoview.test.ts @@ -1,54 +1,18 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { describe, expect, it, vi } from "vitest"; +import { + 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; -}; - -const sessionMocks = vi.hoisted(() => ({ - getPageForTargetId: vi.fn(async () => { - if (!currentPage) { - throw new Error("missing page"); - } - return currentPage; - }), - ensurePageState: vi.fn(() => pageState), - restoreRoleRefsForTarget: vi.fn(() => {}), - refLocator: vi.fn(() => { - if (!currentRefLocator) { - throw new Error("missing locator"); - } - return currentRefLocator; - }), - rememberRoleRefsForTarget: vi.fn(() => {}), -})); - -vi.mock("./pw-session.js", () => sessionMocks); +installPwToolsCoreTestHooks(); const mod = await import("./pw-tools-core.js"); 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(); - } - }); - it("clamps timeoutMs for scrollIntoView", async () => { const scrollIntoViewIfNeeded = vi.fn(async () => {}); - currentRefLocator = { scrollIntoViewIfNeeded }; - currentPage = {}; + setPwToolsCoreCurrentRefLocator({ scrollIntoViewIfNeeded }); + setPwToolsCoreCurrentPage({}); await mod.scrollIntoViewViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -63,8 +27,8 @@ describe("pw-tools-core", () => { const scrollIntoViewIfNeeded = vi.fn(async () => { throw new Error('Error: strict mode violation: locator("aria-ref=1") resolved to 2 elements'); }); - currentRefLocator = { scrollIntoViewIfNeeded }; - currentPage = {}; + setPwToolsCoreCurrentRefLocator({ scrollIntoViewIfNeeded }); + setPwToolsCoreCurrentPage({}); await expect( mod.scrollIntoViewViaPlaywright({ @@ -78,8 +42,8 @@ describe("pw-tools-core", () => { const scrollIntoViewIfNeeded = vi.fn(async () => { throw new Error('Timeout 5000ms exceeded. waiting for locator("aria-ref=1") to be visible'); }); - currentRefLocator = { scrollIntoViewIfNeeded }; - currentPage = {}; + setPwToolsCoreCurrentRefLocator({ scrollIntoViewIfNeeded }); + setPwToolsCoreCurrentPage({}); await expect( mod.scrollIntoViewViaPlaywright({ @@ -93,8 +57,8 @@ describe("pw-tools-core", () => { const click = vi.fn(async () => { throw new Error('Error: strict mode violation: locator("aria-ref=1") resolved to 2 elements'); }); - currentRefLocator = { click }; - currentPage = {}; + setPwToolsCoreCurrentRefLocator({ click }); + setPwToolsCoreCurrentPage({}); await expect( mod.clickViaPlaywright({ @@ -108,8 +72,8 @@ describe("pw-tools-core", () => { const click = vi.fn(async () => { throw new Error('Timeout 5000ms exceeded. waiting for locator("aria-ref=1") to be visible'); }); - currentRefLocator = { click }; - currentPage = {}; + setPwToolsCoreCurrentRefLocator({ click }); + setPwToolsCoreCurrentPage({}); await expect( mod.clickViaPlaywright({ @@ -125,8 +89,8 @@ describe("pw-tools-core", () => { "Element is not receiving pointer events because another element intercepts pointer events", ); }); - currentRefLocator = { click }; - currentPage = {}; + setPwToolsCoreCurrentRefLocator({ click }); + setPwToolsCoreCurrentPage({}); await expect( mod.clickViaPlaywright({ diff --git a/src/browser/pw-tools-core.last-file-chooser-arm-wins.test.ts b/src/browser/pw-tools-core.last-file-chooser-arm-wins.test.ts index baaf3e1ba8..78c6068e58 100644 --- a/src/browser/pw-tools-core.last-file-chooser-arm-wins.test.ts +++ b/src/browser/pw-tools-core.last-file-chooser-arm-wins.test.ts @@ -1,50 +1,13 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { describe, expect, it, vi } from "vitest"; +import { + installPwToolsCoreTestHooks, + setPwToolsCoreCurrentPage, +} 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; -}; - -const sessionMocks = vi.hoisted(() => ({ - getPageForTargetId: vi.fn(async () => { - if (!currentPage) { - throw new Error("missing page"); - } - return currentPage; - }), - ensurePageState: vi.fn(() => pageState), - restoreRoleRefsForTarget: vi.fn(() => {}), - refLocator: vi.fn(() => { - if (!currentRefLocator) { - throw new Error("missing locator"); - } - return currentRefLocator; - }), - rememberRoleRefsForTarget: vi.fn(() => {}), -})); - -vi.mock("./pw-session.js", () => sessionMocks); +installPwToolsCoreTestHooks(); const mod = await import("./pw-tools-core.js"); 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(); - } - }); - it("last file-chooser arm wins", async () => { let resolve1: ((value: unknown) => void) | null = null; let resolve2: ((value: unknown) => void) | null = null; @@ -67,10 +30,10 @@ describe("pw-tools-core", () => { }), ); - currentPage = { + setPwToolsCoreCurrentPage({ waitForEvent, keyboard: { press: vi.fn(async () => {}) }, - }; + }); await mod.armFileUploadViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -93,9 +56,9 @@ describe("pw-tools-core", () => { const dismiss = vi.fn(async () => {}); const dialog = { accept, dismiss }; const waitForEvent = vi.fn(async () => dialog); - currentPage = { + setPwToolsCoreCurrentPage({ waitForEvent, - }; + }); await mod.armDialogViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -129,7 +92,7 @@ describe("pw-tools-core", () => { const waitForFunction = vi.fn(async () => {}); const waitForTimeout = vi.fn(async () => {}); - currentPage = { + const page = { locator: vi.fn(() => ({ first: () => ({ waitFor: waitForSelector }), })), @@ -139,6 +102,7 @@ describe("pw-tools-core", () => { waitForTimeout, getByText: vi.fn(() => ({ first: () => ({ waitFor: vi.fn() }) })), }; + setPwToolsCoreCurrentPage(page); await mod.waitForViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -151,7 +115,7 @@ describe("pw-tools-core", () => { }); expect(waitForTimeout).toHaveBeenCalledWith(50); - expect(currentPage.locator as ReturnType).toHaveBeenCalledWith("#main"); + expect(page.locator as ReturnType).toHaveBeenCalledWith("#main"); expect(waitForSelector).toHaveBeenCalledWith({ state: "visible", timeout: 1234, diff --git a/src/browser/pw-tools-core.screenshots-element-selector.test.ts b/src/browser/pw-tools-core.screenshots-element-selector.test.ts index 96a4a06ea5..843d07050f 100644 --- a/src/browser/pw-tools-core.screenshots-element-selector.test.ts +++ b/src/browser/pw-tools-core.screenshots-element-selector.test.ts @@ -1,58 +1,25 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { 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; -}; - -const sessionMocks = vi.hoisted(() => ({ - getPageForTargetId: vi.fn(async () => { - if (!currentPage) { - throw new Error("missing page"); - } - return currentPage; - }), - ensurePageState: vi.fn(() => pageState), - restoreRoleRefsForTarget: vi.fn(() => {}), - refLocator: vi.fn(() => { - if (!currentRefLocator) { - throw new Error("missing locator"); - } - return currentRefLocator; - }), - rememberRoleRefsForTarget: vi.fn(() => {}), -})); - -vi.mock("./pw-session.js", () => sessionMocks); +installPwToolsCoreTestHooks(); +const sessionMocks = getPwToolsCoreSessionMocks(); const mod = await import("./pw-tools-core.js"); 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(); - } - }); - it("screenshots an element selector", async () => { const elementScreenshot = vi.fn(async () => Buffer.from("E")); - currentPage = { + const page = { locator: vi.fn(() => ({ first: () => ({ screenshot: elementScreenshot }), })), screenshot: vi.fn(async () => Buffer.from("P")), }; + setPwToolsCoreCurrentPage(page); const res = await mod.takeScreenshotViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -63,16 +30,17 @@ describe("pw-tools-core", () => { expect(res.buffer.toString()).toBe("E"); expect(sessionMocks.getPageForTargetId).toHaveBeenCalled(); - expect(currentPage.locator as ReturnType).toHaveBeenCalledWith("#main"); + expect(page.locator as ReturnType).toHaveBeenCalledWith("#main"); expect(elementScreenshot).toHaveBeenCalledWith({ type: "png" }); }); it("screenshots a ref locator", async () => { const refScreenshot = vi.fn(async () => Buffer.from("R")); - currentRefLocator = { screenshot: refScreenshot }; - currentPage = { + setPwToolsCoreCurrentRefLocator({ screenshot: refScreenshot }); + const page = { locator: vi.fn(), screenshot: vi.fn(async () => Buffer.from("P")), }; + setPwToolsCoreCurrentPage(page); const res = await mod.takeScreenshotViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -82,17 +50,17 @@ describe("pw-tools-core", () => { }); expect(res.buffer.toString()).toBe("R"); - expect(sessionMocks.refLocator).toHaveBeenCalledWith(currentPage, "76"); + expect(sessionMocks.refLocator).toHaveBeenCalledWith(page, "76"); expect(refScreenshot).toHaveBeenCalledWith({ type: "jpeg" }); }); it("rejects fullPage for element or ref screenshots", async () => { - currentRefLocator = { screenshot: vi.fn(async () => Buffer.from("R")) }; - currentPage = { + setPwToolsCoreCurrentRefLocator({ screenshot: vi.fn(async () => Buffer.from("R")) }); + setPwToolsCoreCurrentPage({ locator: vi.fn(() => ({ first: () => ({ screenshot: vi.fn(async () => Buffer.from("E")) }), })), screenshot: vi.fn(async () => Buffer.from("P")), - }; + }); await expect( mod.takeScreenshotViaPlaywright({ @@ -115,10 +83,10 @@ describe("pw-tools-core", () => { it("arms the next file chooser and sets files (default timeout)", async () => { const fileChooser = { setFiles: vi.fn(async () => {}) }; const waitForEvent = vi.fn(async (_event: string, _opts: unknown) => fileChooser); - currentPage = { + setPwToolsCoreCurrentPage({ waitForEvent, keyboard: { press: vi.fn(async () => {}) }, - }; + }); await mod.armFileUploadViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -138,10 +106,10 @@ describe("pw-tools-core", () => { const fileChooser = { setFiles: vi.fn(async () => {}) }; const press = vi.fn(async () => {}); const waitForEvent = vi.fn(async () => fileChooser); - currentPage = { + setPwToolsCoreCurrentPage({ waitForEvent, keyboard: { press }, - }; + }); await mod.armFileUploadViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", diff --git a/src/browser/pw-tools-core.test-harness.ts b/src/browser/pw-tools-core.test-harness.ts new file mode 100644 index 0000000000..d6bdb84550 --- /dev/null +++ b/src/browser/pw-tools-core.test-harness.ts @@ -0,0 +1,64 @@ +import { beforeEach, vi } from "vitest"; + +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), + restoreRoleRefsForTarget: vi.fn(() => {}), + refLocator: vi.fn(() => { + if (!currentRefLocator) { + throw new Error("missing locator"); + } + return currentRefLocator; + }), + rememberRoleRefsForTarget: vi.fn(() => {}), +})); + +vi.mock("./pw-session.js", () => sessionMocks); + +export function getPwToolsCoreSessionMocks() { + return sessionMocks; +} + +export function setPwToolsCoreCurrentPage(page: Record | null) { + currentPage = page; +} + +export function setPwToolsCoreCurrentRefLocator(locator: Record | null) { + currentRefLocator = locator; +} + +export function installPwToolsCoreTestHooks() { + beforeEach(() => { + currentPage = null; + currentRefLocator = null; + pageState = { + console: [], + armIdUpload: 0, + armIdDialog: 0, + armIdDownload: 0, + }; + + for (const fn of Object.values(sessionMocks)) { + fn.mockClear(); + } + }); +} diff --git a/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts b/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts index 71be19a2d1..7a9a562b4e 100644 --- a/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts +++ b/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts @@ -1,34 +1,14 @@ import path from "node:path"; import { 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; -}; - -const sessionMocks = vi.hoisted(() => ({ - getPageForTargetId: vi.fn(async () => { - if (!currentPage) { - throw new Error("missing page"); - } - return currentPage; - }), - ensurePageState: vi.fn(() => pageState), - restoreRoleRefsForTarget: vi.fn(() => {}), - refLocator: vi.fn(() => { - if (!currentRefLocator) { - throw new Error("missing locator"); - } - return currentRefLocator; - }), - rememberRoleRefsForTarget: vi.fn(() => {}), -})); - -vi.mock("./pw-session.js", () => sessionMocks); +installPwToolsCoreTestHooks(); +const sessionMocks = getPwToolsCoreSessionMocks(); const tmpDirMocks = vi.hoisted(() => ({ resolvePreferredOpenClawTmpDir: vi.fn(() => "/tmp/openclaw"), })); @@ -37,17 +17,6 @@ const mod = await import("./pw-tools-core.js"); 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(); } @@ -70,7 +39,7 @@ describe("pw-tools-core", () => { saveAs, }; - currentPage = { on, off }; + setPwToolsCoreCurrentPage({ on, off }); const targetPath = path.resolve("/tmp/file.bin"); const p = mod.waitForDownloadViaPlaywright({ @@ -98,7 +67,7 @@ describe("pw-tools-core", () => { const off = vi.fn(); const click = vi.fn(async () => {}); - currentRefLocator = { click }; + setPwToolsCoreCurrentRefLocator({ click }); const saveAs = vi.fn(async () => {}); const download = { @@ -107,7 +76,7 @@ describe("pw-tools-core", () => { saveAs, }; - currentPage = { on, off }; + setPwToolsCoreCurrentPage({ on, off }); const targetPath = path.resolve("/tmp/report.pdf"); const p = mod.downloadViaPlaywright({ @@ -145,7 +114,7 @@ describe("pw-tools-core", () => { }; tmpDirMocks.resolvePreferredOpenClawTmpDir.mockReturnValue("/tmp/openclaw-preferred"); - currentPage = { on, off }; + setPwToolsCoreCurrentPage({ on, off }); const p = mod.waitForDownloadViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -189,7 +158,7 @@ describe("pw-tools-core", () => { }; tmpDirMocks.resolvePreferredOpenClawTmpDir.mockReturnValue("/tmp/openclaw-preferred"); - currentPage = { on, off }; + setPwToolsCoreCurrentPage({ on, off }); const p = mod.waitForDownloadViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -219,7 +188,7 @@ describe("pw-tools-core", () => { } }); const off = vi.fn(); - currentPage = { on, off }; + setPwToolsCoreCurrentPage({ on, off }); const resp = { url: () => "https://example.com/api/data", @@ -248,8 +217,9 @@ describe("pw-tools-core", () => { }); it("scrolls a ref into view (default timeout)", async () => { const scrollIntoViewIfNeeded = vi.fn(async () => {}); - currentRefLocator = { scrollIntoViewIfNeeded }; - currentPage = {}; + setPwToolsCoreCurrentRefLocator({ scrollIntoViewIfNeeded }); + const page = {}; + setPwToolsCoreCurrentPage(page); await mod.scrollIntoViewViaPlaywright({ cdpUrl: "http://127.0.0.1:18792", @@ -257,12 +227,12 @@ describe("pw-tools-core", () => { ref: "1", }); - expect(sessionMocks.refLocator).toHaveBeenCalledWith(currentPage, "1"); + expect(sessionMocks.refLocator).toHaveBeenCalledWith(page, "1"); expect(scrollIntoViewIfNeeded).toHaveBeenCalledWith({ timeout: 20_000 }); }); it("requires a ref for scrollIntoView", async () => { - currentRefLocator = { scrollIntoViewIfNeeded: vi.fn(async () => {}) }; - currentPage = {}; + setPwToolsCoreCurrentRefLocator({ scrollIntoViewIfNeeded: vi.fn(async () => {}) }); + setPwToolsCoreCurrentPage({}); await expect( mod.scrollIntoViewViaPlaywright({