From b2bdad5bee5afcb74778280d6b31ec3d594a9596 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 28 May 2026 23:48:25 -0400 Subject: [PATCH] fix(browser): default non-finite snapshot timeouts --- .../browser/pw-tools-core.snapshot.test.ts | 31 +++++++++++++++++++ .../src/browser/pw-tools-core.snapshot.ts | 10 ++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/extensions/browser/src/browser/pw-tools-core.snapshot.test.ts b/extensions/browser/src/browser/pw-tools-core.snapshot.test.ts index ffbb41d7464..04eb0b64f13 100644 --- a/extensions/browser/src/browser/pw-tools-core.snapshot.test.ts +++ b/extensions/browser/src/browser/pw-tools-core.snapshot.test.ts @@ -131,6 +131,37 @@ describe("pw-tools-core aria snapshot storage", () => { expect(ariaSnapshotMock).toHaveBeenCalledWith({ mode: "ai", timeout: 8888 }); }); + it("uses the default snapshot timeout for non-finite role-aria timeouts", async () => { + const ariaSnapshotMock = vi.fn().mockResolvedValue(""); + const page = { ariaSnapshot: ariaSnapshotMock }; + getPageForTargetId.mockResolvedValue(page); + + const mod = await import("./pw-tools-core.snapshot.js"); + await mod.snapshotRoleViaPlaywright({ + cdpUrl: "http://127.0.0.1:9222", + targetId: "tab-1", + refsMode: "aria", + timeoutMs: Number.NaN, + }); + + expect(ariaSnapshotMock).toHaveBeenCalledWith({ mode: "ai", timeout: 5000 }); + }); + + it("uses the default snapshot timeout for non-finite ai snapshot timeouts", async () => { + const ariaSnapshotMock = vi.fn().mockResolvedValue(""); + const page = { ariaSnapshot: ariaSnapshotMock }; + getPageForTargetId.mockResolvedValue(page); + + const mod = await import("./pw-tools-core.snapshot.js"); + await mod.snapshotAiViaPlaywright({ + cdpUrl: "http://127.0.0.1:9222", + targetId: "tab-1", + timeoutMs: Number.NaN, + }); + + expect(ariaSnapshotMock).toHaveBeenCalledWith({ mode: "ai", timeout: 5000 }); + }); + it("stores role fallback metadata when backend markers are unavailable", async () => { const page = { id: "page-1" }; const mod = await import("./pw-tools-core.snapshot.js"); diff --git a/extensions/browser/src/browser/pw-tools-core.snapshot.ts b/extensions/browser/src/browser/pw-tools-core.snapshot.ts index 357c74b3e36..27b5a8196bf 100644 --- a/extensions/browser/src/browser/pw-tools-core.snapshot.ts +++ b/extensions/browser/src/browser/pw-tools-core.snapshot.ts @@ -1,3 +1,4 @@ +import { parseFiniteNumber } from "openclaw/plugin-sdk/number-runtime"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, @@ -34,6 +35,11 @@ type SnapshotUrlEntry = { url: string; }; +function resolveSnapshotTimeoutMs(timeoutMs: number | undefined): number { + const parsed = parseFiniteNumber(timeoutMs); + return Math.max(500, Math.min(60_000, Math.floor(parsed ?? 5_000))); +} + async function collectSnapshotUrls(page: Page): Promise { const urls = await page .evaluate(() => { @@ -227,7 +233,7 @@ export async function snapshotAiViaPlaywright(opts: { let snapshot = await page.ariaSnapshot({ mode: "ai", - timeout: Math.max(500, Math.min(60_000, Math.floor(opts.timeoutMs ?? 5000))), + timeout: resolveSnapshotTimeoutMs(opts.timeoutMs), }); if (opts.urls) { snapshot = appendSnapshotUrls(snapshot, await collectSnapshotUrls(page)); @@ -284,7 +290,7 @@ export async function snapshotRoleViaPlaywright(opts: { }); } - const ariaSnapshotTimeout = Math.max(500, Math.min(60_000, Math.floor(opts.timeoutMs ?? 5000))); + const ariaSnapshotTimeout = resolveSnapshotTimeoutMs(opts.timeoutMs); if (opts.refsMode === "aria") { if (normalizeOptionalString(opts.selector) || normalizeOptionalString(opts.frameSelector)) {