test(browser): isolate auth and download mocks

This commit is contained in:
Peter Steinberger
2026-03-27 23:20:43 +00:00
parent c720fa83bb
commit 6fec75f15d
2 changed files with 112 additions and 48 deletions

View File

@@ -4,6 +4,25 @@ import type { OpenClawConfig } from "../config/config.js";
const mocks = vi.hoisted(() => ({
loadConfig: vi.fn<() => OpenClawConfig>(),
resolveGatewayAuth: vi.fn(
({
authConfig,
}: {
authConfig?: NonNullable<NonNullable<OpenClawConfig["gateway"]>["auth"]> | undefined;
}) => {
const token =
typeof authConfig?.token === "string"
? authConfig.token
: typeof authConfig?.token === "object"
? undefined
: undefined;
const password = typeof authConfig?.password === "string" ? authConfig.password : undefined;
return {
token,
password,
};
},
),
ensureGatewayStartupAuth: vi.fn(async ({ cfg }: { cfg: OpenClawConfig }) => ({
cfg: {
...cfg,
@@ -25,18 +44,18 @@ const mocks = vi.hoisted(() => ({
})),
}));
vi.mock("../config/config.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../config/config.js")>();
return {
...actual,
loadConfig: mocks.loadConfig,
};
});
vi.mock("../config/config.js", () => ({
loadConfig: mocks.loadConfig,
}));
vi.mock("../gateway/startup-auth.js", () => ({
ensureGatewayStartupAuth: mocks.ensureGatewayStartupAuth,
}));
vi.mock("../gateway/auth.js", () => ({
resolveGatewayAuth: mocks.resolveGatewayAuth,
}));
let ensureBrowserControlAuth: typeof import("./control-auth.js").ensureBrowserControlAuth;
describe("ensureBrowserControlAuth", () => {
@@ -74,6 +93,7 @@ describe("ensureBrowserControlAuth", () => {
({ ensureBrowserControlAuth } = await import("./control-auth.js"));
vi.restoreAllMocks();
mocks.loadConfig.mockClear();
mocks.resolveGatewayAuth.mockClear();
mocks.ensureGatewayStartupAuth.mockClear();
});

View File

@@ -2,31 +2,102 @@ 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";
installPwToolsCoreTestHooks();
const sessionMocks = getPwToolsCoreSessionMocks();
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"),
}));
vi.mock("../infra/tmp-openclaw-dir.js", () => tmpDirMocks);
let mod: typeof import("./pw-tools-core.js");
const chromeMocks = vi.hoisted(() => ({
getChromeWebSocketUrl: vi.fn(async () => "ws://127.0.0.1/devtools/browser/mock"),
}));
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);
vi.mock("../infra/tmp-openclaw-dir.js", () => ({
resolvePreferredOpenClawTmpDir: tmpDirMocks.resolvePreferredOpenClawTmpDir,
}));
let mod: Pick<
typeof import("./pw-tools-core.downloads.js"),
"downloadViaPlaywright" | "waitForDownloadViaPlaywright"
> &
Pick<typeof import("./pw-tools-core.responses.js"), "responseBodyViaPlaywright">;
describe("pw-tools-core", () => {
beforeAll(async () => {
vi.resetModules();
mod = await import("./pw-tools-core.js");
vi.doMock("./pw-session.js", () => sessionMocks);
vi.doMock("./chrome.js", () => chromeMocks);
vi.doMock("../infra/tmp-openclaw-dir.js", () => ({
resolvePreferredOpenClawTmpDir: tmpDirMocks.resolvePreferredOpenClawTmpDir,
}));
const [downloads, responses] = await Promise.all([
import("./pw-tools-core.downloads.js"),
import("./pw-tools-core.responses.js"),
]);
mod = {
downloadViaPlaywright: downloads.downloadViaPlaywright,
waitForDownloadViaPlaywright: downloads.waitForDownloadViaPlaywright,
responseBodyViaPlaywright: responses.responseBodyViaPlaywright,
};
});
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();
}
for (const fn of Object.values(chromeMocks)) {
fn.mockClear();
}
for (const fn of Object.values(clientFetchMocks)) {
fn.mockClear();
}
tmpDirMocks.resolvePreferredOpenClawTmpDir.mockReturnValue("/tmp/openclaw");
});
@@ -72,7 +143,7 @@ describe("pw-tools-core", () => {
}
});
const off = vi.fn();
setPwToolsCoreCurrentPage({ on, off });
currentPage = { on, off };
return {
trigger: (download: unknown) => {
downloadHandler?.(download);
@@ -137,7 +208,7 @@ describe("pw-tools-core", () => {
const harness = createDownloadEventHarness();
const click = vi.fn(async () => {});
setPwToolsCoreCurrentRefLocator({ click });
currentRefLocator = { click };
const saveAs = vi.fn(async (outPath: string) => {
await fs.writeFile(outPath, "report-content", "utf8");
@@ -244,7 +315,7 @@ describe("pw-tools-core", () => {
}
});
const off = vi.fn();
setPwToolsCoreCurrentPage({ on, off });
currentPage = { on, off };
const resp = {
url: () => "https://example.com/api/data",
@@ -271,31 +342,4 @@ describe("pw-tools-core", () => {
expect(res.body).toBe('{"ok":true');
expect(res.truncated).toBe(true);
});
it("scrolls a ref into view (default timeout)", async () => {
const scrollIntoViewIfNeeded = vi.fn(async () => {});
setPwToolsCoreCurrentRefLocator({ scrollIntoViewIfNeeded });
const page = {};
setPwToolsCoreCurrentPage(page);
await mod.scrollIntoViewViaPlaywright({
cdpUrl: "http://127.0.0.1:18792",
targetId: "T1",
ref: "1",
});
expect(sessionMocks.refLocator).toHaveBeenCalledWith(page, "1");
expect(scrollIntoViewIfNeeded).toHaveBeenCalledWith({ timeout: 20_000 });
});
it("requires a ref for scrollIntoView", async () => {
setPwToolsCoreCurrentRefLocator({ scrollIntoViewIfNeeded: vi.fn(async () => {}) });
setPwToolsCoreCurrentPage({});
await expect(
mod.scrollIntoViewViaPlaywright({
cdpUrl: "http://127.0.0.1:18792",
targetId: "T1",
ref: " ",
}),
).rejects.toThrow(/ref or selector is required/i);
});
});