Skip to content

Commit 46158b4

Browse files
Normalize waitForSettledDOM timeout bounds
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent a5a3b3e commit 46158b4

2 files changed

Lines changed: 44 additions & 2 deletions

File tree

‎src/utils/waitForSettledDOM.test.ts‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,38 @@ describe("waitForSettledDOM diagnostics", () => {
183183
expect(stats.peakInflight).toBe(1);
184184
});
185185

186+
it("normalizes invalid timeout values instead of timing out immediately", async () => {
187+
const { session } = createSessionWithEvents();
188+
const cdpClient: CDPClient = {
189+
rootSession: session,
190+
createSession: async () => session,
191+
acquireSession: async () => session,
192+
dispose: async () => undefined,
193+
};
194+
getCDPClient.mockResolvedValue(cdpClient);
195+
getOrCreateFrameContextManager.mockReturnValue({
196+
setDebug: jest.fn(),
197+
});
198+
getDebugOptions.mockReturnValue({
199+
enabled: false,
200+
traceWait: false,
201+
});
202+
203+
const page = {
204+
context: () => ({}),
205+
} as never;
206+
207+
const waitPromise = waitForSettledDOM(page, Number.NaN as unknown as number);
208+
await Promise.resolve();
209+
await Promise.resolve();
210+
await jest.advanceTimersByTimeAsync(600);
211+
const stats = await waitPromise;
212+
213+
expect(stats.resolvedByTimeout).toBe(false);
214+
expect(stats.requestsSeen).toBe(0);
215+
expect(stats.forcedDrops).toBe(0);
216+
});
217+
186218
it("falls back to timeout when network listener registration fails", async () => {
187219
const warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
188220
const { session } = createSessionWithEvents({

‎src/utils/waitForSettledDOM.ts‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ const STALLED_REQUEST_MS = 2000;
2727
const STALLED_SWEEP_INTERVAL_MS = 500;
2828
const MAX_WAIT_DIAGNOSTIC_CHARS = 400;
2929
const MAX_WAIT_IDENTIFIER_CHARS = 200;
30+
const DEFAULT_WAIT_TIMEOUT_MS = 10_000;
31+
const MAX_WAIT_TIMEOUT_MS = 120_000;
3032
const ENV_TRACE_WAIT =
3133
process.env.HYPERAGENT_TRACE_WAIT === "1" ||
3234
process.env.HYPERAGENT_TRACE_WAIT === "true";
@@ -117,6 +119,13 @@ function detachSessionListener<TPayload extends unknown[]>(
117119
}
118120
}
119121

122+
function normalizeWaitTimeoutMs(value: number): number {
123+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
124+
return DEFAULT_WAIT_TIMEOUT_MS;
125+
}
126+
return Math.min(Math.floor(value), MAX_WAIT_TIMEOUT_MS);
127+
}
128+
120129
export interface LifecycleOptions {
121130
waitUntil?: Array<"domcontentloaded" | "load" | "networkidle">;
122131
timeoutMs?: number;
@@ -134,8 +143,9 @@ export interface WaitForSettledStats {
134143

135144
export async function waitForSettledDOM(
136145
page: Page,
137-
timeoutMs: number = 10000
146+
timeoutMs: number = DEFAULT_WAIT_TIMEOUT_MS
138147
): Promise<WaitForSettledStats> {
148+
const normalizedTimeoutMs = normalizeWaitTimeoutMs(timeoutMs);
139149
const ctx = page.context() as BrowserContext & {
140150
_options?: { recordVideo?: unknown };
141151
};
@@ -163,7 +173,7 @@ export async function waitForSettledDOM(
163173

164174
const networkStart = performance.now();
165175
const stats = await waitForNetworkIdle(lifecycleSession, {
166-
timeoutMs,
176+
timeoutMs: normalizedTimeoutMs,
167177
trace: traceWaitFlag,
168178
});
169179
const networkDuration = performance.now() - networkStart;

0 commit comments

Comments
 (0)