chore: refactor waitForNetworkIdle + waitForEvent (#10277)

This commit is contained in:
Nikolay Vitkov 2023-05-31 09:32:16 +02:00 committed by GitHub
parent 54d6192262
commit e61d9cbb4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 33 additions and 44 deletions

View File

@ -1641,31 +1641,28 @@ export class Page extends EventEmitter {
const idleDeferred = createDeferred<void>(); const idleDeferred = createDeferred<void>();
const abortDeferred = createDeferred<Error>(); const abortDeferred = createDeferred<Error>();
let idleTimer: NodeJS.Timeout; let idleTimer: NodeJS.Timeout | undefined;
const cleanup = () => { const cleanup = () => {
idleTimer && clearTimeout(idleTimer); clearTimeout(idleTimer);
abortDeferred.reject(new Error('abort')); abortDeferred.reject(new Error('abort'));
}; };
const evaluate = () => { const evaluate = () => {
idleTimer && clearTimeout(idleTimer); clearTimeout(idleTimer);
if (networkManager.inFlightRequestsCount() === 0) { if (networkManager.inFlightRequestsCount() === 0) {
idleTimer = setTimeout(idleDeferred.resolve, idleTime); idleTimer = setTimeout(idleDeferred.resolve, idleTime);
} }
}; };
evaluate();
const eventHandler = () => {
evaluate();
return false;
};
const listenToEvent = (event: symbol) => { const listenToEvent = (event: symbol) => {
return waitForEvent( return waitForEvent(
networkManager, networkManager,
event, event,
eventHandler, () => {
evaluate();
return false;
},
timeout, timeout,
abortDeferred.valueOrThrow() abortDeferred.valueOrThrow()
); );
@ -1677,6 +1674,8 @@ export class Page extends EventEmitter {
listenToEvent(NetworkManagerEmittedEvents.RequestFailed), listenToEvent(NetworkManagerEmittedEvents.RequestFailed),
]; ];
evaluate();
await Promise.race([ await Promise.race([
idleDeferred.valueOrThrow(), idleDeferred.valueOrThrow(),
...eventPromises, ...eventPromises,

View File

@ -150,13 +150,13 @@ export class NetworkEventManager {
} }
inFlightRequestsCount(): number { inFlightRequestsCount(): number {
let inProgressRequestCounter = 0; let inFlightRequestCounter = 0;
for (const [, request] of this.#httpRequestsMap) { for (const request of this.#httpRequestsMap.values()) {
if (!request.response()) { if (!request.response()) {
inProgressRequestCounter++; inFlightRequestCounter++;
} }
} }
return inProgressRequestCounter; return inFlightRequestCounter;
} }
storeRequestWillBeSent( storeRequestWillBeSent(

View File

@ -103,7 +103,7 @@ export class NetworkManager extends EventEmitter {
inFlightRequestsCount(): number { inFlightRequestsCount(): number {
let inFlightRequestCounter = 0; let inFlightRequestCounter = 0;
for (const [, request] of this.#requestMap) { for (const request of this.#requestMap.values()) {
if (!request.response() || request._failureText) { if (!request.response() || request._failureText) {
inFlightRequestCounter++; inFlightRequestCounter++;
} }

View File

@ -22,6 +22,7 @@ import type {ElementHandle} from '../api/ElementHandle.js';
import type {JSHandle} from '../api/JSHandle.js'; import type {JSHandle} from '../api/JSHandle.js';
import {Page} from '../api/Page.js'; import {Page} from '../api/Page.js';
import {isNode} from '../environment.js'; import {isNode} from '../environment.js';
import {createDeferred} from '../puppeteer-core.js';
import {assert} from '../util/assert.js'; import {assert} from '../util/assert.js';
import {isErrorLike} from '../util/ErrorLike.js'; import {isErrorLike} from '../util/ErrorLike.js';
@ -382,45 +383,28 @@ export async function waitForEvent<T>(
timeout: number, timeout: number,
abortPromise: Promise<Error> abortPromise: Promise<Error>
): Promise<T> { ): Promise<T> {
let eventTimeout: NodeJS.Timeout; const deferred = createDeferred<T>({
let resolveCallback: (value: T | PromiseLike<T>) => void; message: `Timeout exceeded while waiting for event ${String(eventName)}`,
let rejectCallback: (value: Error) => void; timeout,
const promise = new Promise<T>((resolve, reject) => {
resolveCallback = resolve;
rejectCallback = reject;
}); });
const listener = addEventListener(emitter, eventName, async event => { const listener = addEventListener(emitter, eventName, async event => {
if (!(await predicate(event))) { if (await predicate(event)) {
return; deferred.resolve(event);
} }
resolveCallback(event);
}); });
if (timeout) { return Promise.race([deferred.valueOrThrow(), abortPromise]).then(
eventTimeout = setTimeout(() => {
rejectCallback(
new TimeoutError('Timeout exceeded while waiting for event')
);
}, timeout);
}
function cleanup(): void {
removeEventListeners([listener]);
clearTimeout(eventTimeout);
}
const result = await Promise.race([promise, abortPromise]).then(
r => { r => {
cleanup(); removeEventListeners([listener]);
if (isErrorLike(r)) {
throw r;
}
return r; return r;
}, },
error => { error => {
cleanup(); removeEventListeners([listener]);
throw error; throw error;
} }
); );
if (isErrorLike(result)) {
throw result;
}
return result;
} }
/** /**

View File

@ -2099,6 +2099,12 @@
"parameters": ["chrome", "webDriverBiDi"], "parameters": ["chrome", "webDriverBiDi"],
"expectations": ["PASS"] "expectations": ["PASS"]
}, },
{
"testIdPattern": "[page.spec] Page Page.waitForNetworkIdle should work",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[page.spec] Page Page.waitForNetworkIdle should work with aborted requests", "testIdPattern": "[page.spec] Page Page.waitForNetworkIdle should work with aborted requests",
"platforms": ["linux"], "platforms": ["linux"],