Skip to content

Commit 3000997

Browse files
authored
chore: migrate waitForEvent to Progress (#2483)
Drive-by: remove/simplify some helper code.
1 parent fb058ff commit 3000997

File tree

6 files changed

+64
-102
lines changed

6 files changed

+64
-102
lines changed

src/browserContext.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,12 @@ export abstract class BrowserContextBase extends ExtendedEventEmitter implements
104104
return event === Events.BrowserContext.Close ? super._abortPromiseForEvent(event) : this._closePromise;
105105
}
106106

107-
protected _computeDeadline(options?: types.TimeoutOptions): number {
108-
return this._timeoutSettings.computeDeadline(options);
107+
protected _getLogger(): InnerLogger {
108+
return this._logger;
109+
}
110+
111+
protected _getTimeoutSettings(): TimeoutSettings {
112+
return this._timeoutSettings;
109113
}
110114

111115
_browserClosed() {

src/extendedEventEmitter.ts

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,43 @@
1515
*/
1616

1717
import { EventEmitter } from 'events';
18-
import { helper } from './helper';
19-
import { TimeoutOptions } from './types';
18+
import { helper, RegisteredListener } from './helper';
19+
import { ProgressController } from './progress';
20+
import { InnerLogger } from './logger';
21+
import { TimeoutSettings } from './timeoutSettings';
2022

21-
export class ExtendedEventEmitter extends EventEmitter {
23+
export abstract class ExtendedEventEmitter extends EventEmitter {
2224
protected _abortPromiseForEvent(event: string) {
2325
return new Promise<Error>(() => void 0);
2426
}
27+
protected abstract _getLogger(): InnerLogger;
28+
protected abstract _getTimeoutSettings(): TimeoutSettings;
2529

26-
protected _computeDeadline(options?: TimeoutOptions): number {
27-
throw new Error('unimplemented');
28-
}
30+
async waitForEvent(event: string, optionsOrPredicate: Function | { predicate?: Function, timeout?: number } = {}): Promise<any> {
31+
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
32+
const { predicate = () => true } = options;
33+
34+
const progressController = new ProgressController(options, this._getLogger(), this._getTimeoutSettings());
35+
this._abortPromiseForEvent(event).then(error => progressController.abort(error));
36+
37+
return progressController.run(async progress => {
38+
const listeners: RegisteredListener[] = [];
39+
const promise = new Promise((resolve, reject) => {
40+
listeners.push(helper.addEventListener(this, event, eventArg => {
41+
try {
42+
if (!predicate(eventArg))
43+
return;
44+
resolve(eventArg);
45+
} catch (e) {
46+
reject(e);
47+
}
48+
}));
49+
});
50+
progress.cleanupWhenAborted(() => helper.removeEventListeners(listeners));
2951

30-
async waitForEvent(event: string, optionsOrPredicate: Function|{ predicate?: Function, timeout?: number } = {}): Promise<any> {
31-
const deadline = this._computeDeadline(typeof optionsOrPredicate === 'function' ? undefined : optionsOrPredicate);
32-
const {
33-
predicate = () => true,
34-
} = typeof optionsOrPredicate === 'function' ? {predicate: optionsOrPredicate} : optionsOrPredicate;
35-
return helper.waitForEvent(this, event, predicate, deadline, this._abortPromiseForEvent(event));
52+
const result = await promise;
53+
helper.removeEventListeners(listeners);
54+
return result;
55+
});
3656
}
3757
}

src/helper.ts

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ import * as crypto from 'crypto';
1919
import { EventEmitter } from 'events';
2020
import * as fs from 'fs';
2121
import * as util from 'util';
22-
import { TimeoutError } from './errors';
2322
import * as types from './types';
24-
import { ChildProcess, execSync } from 'child_process';
2523

2624
export type RegisteredListener = {
2725
emitter: EventEmitter;
@@ -124,59 +122,6 @@ class Helper {
124122
return typeof obj === 'boolean' || obj instanceof Boolean;
125123
}
126124

127-
static async waitForEvent(
128-
emitter: EventEmitter,
129-
eventName: (string | symbol),
130-
predicate: Function,
131-
deadline: number,
132-
abortPromise: Promise<Error>): Promise<any> {
133-
let resolveCallback: (event: any) => void = () => {};
134-
let rejectCallback: (error: any) => void = () => {};
135-
const promise = new Promise((resolve, reject) => {
136-
resolveCallback = resolve;
137-
rejectCallback = reject;
138-
});
139-
140-
// Add listener.
141-
const listener = Helper.addEventListener(emitter, eventName, event => {
142-
try {
143-
if (!predicate(event))
144-
return;
145-
resolveCallback(event);
146-
} catch (e) {
147-
rejectCallback(e);
148-
}
149-
});
150-
151-
// Reject upon timeout.
152-
const eventTimeout = setTimeout(() => {
153-
rejectCallback(new TimeoutError(`Timeout exceeded while waiting for ${String(eventName)}`));
154-
}, helper.timeUntilDeadline(deadline));
155-
156-
// Reject upon abort.
157-
abortPromise.then(rejectCallback);
158-
159-
try {
160-
return await promise;
161-
} finally {
162-
Helper.removeEventListeners([listener]);
163-
clearTimeout(eventTimeout);
164-
}
165-
}
166-
167-
static async waitWithDeadline<T>(promise: Promise<T>, taskName: string, deadline: number, debugName: string): Promise<T> {
168-
let reject: (error: Error) => void;
169-
const timeoutError = new TimeoutError(`Waiting for ${taskName} failed: timeout exceeded. Re-run with the DEBUG=${debugName} env variable to see the debug log.`);
170-
const timeoutPromise = new Promise<T>((resolve, x) => reject = x);
171-
const timeoutTimer = setTimeout(() => reject(timeoutError), helper.timeUntilDeadline(deadline));
172-
try {
173-
return await Promise.race([promise, timeoutPromise]);
174-
} finally {
175-
if (timeoutTimer)
176-
clearTimeout(timeoutTimer);
177-
}
178-
}
179-
180125
static globToRegex(glob: string): RegExp {
181126
const tokens = ['^'];
182127
let inGroup;
@@ -321,31 +266,10 @@ class Helper {
321266
return seconds * 1000 + (nanoseconds / 1000000 | 0);
322267
}
323268

324-
static isPastDeadline(deadline: number) {
325-
return deadline !== Number.MAX_SAFE_INTEGER && this.monotonicTime() >= deadline;
326-
}
327-
328269
static timeUntilDeadline(deadline: number): number {
329270
return Math.min(deadline - this.monotonicTime(), 2147483647); // 2^31-1 safe setTimeout in Node.
330271
}
331272

332-
static optionsWithUpdatedTimeout<T extends types.TimeoutOptions>(options: T | undefined, deadline: number): T {
333-
return { ...(options || {}) as T, timeout: this.timeUntilDeadline(deadline) };
334-
}
335-
336-
static killProcess(proc: ChildProcess) {
337-
if (proc.pid && !proc.killed) {
338-
try {
339-
if (process.platform === 'win32')
340-
execSync(`taskkill /pid ${proc.pid} /T /F`);
341-
else
342-
process.kill(-proc.pid, 'SIGKILL');
343-
} catch (e) {
344-
// the process might have already stopped
345-
}
346-
}
347-
}
348-
349273
static getViewportSizeFromWindowFeatures(features: string[]): types.Size | null {
350274
const widthString = features.find(f => f.startsWith('width='));
351275
const heightString = features.find(f => f.startsWith('height='));

src/page.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,12 @@ export class Page extends ExtendedEventEmitter implements InnerLogger {
140140
return this._disconnectedPromise;
141141
}
142142

143-
protected _computeDeadline(options?: types.TimeoutOptions): number {
144-
return this._timeoutSettings.computeDeadline(options);
143+
protected _getLogger(): InnerLogger {
144+
return this;
145+
}
146+
147+
protected _getTimeoutSettings(): TimeoutSettings {
148+
return this._timeoutSettings;
145149
}
146150

147151
_didClose() {
@@ -314,21 +318,21 @@ export class Page extends ExtendedEventEmitter implements InnerLogger {
314318
}
315319

316320
async waitForRequest(urlOrPredicate: string | RegExp | ((r: network.Request) => boolean), options: types.TimeoutOptions = {}): Promise<network.Request> {
317-
const deadline = this._timeoutSettings.computeDeadline(options);
318-
return helper.waitForEvent(this, Events.Page.Request, (request: network.Request) => {
321+
const predicate = (request: network.Request) => {
319322
if (helper.isString(urlOrPredicate) || helper.isRegExp(urlOrPredicate))
320323
return helper.urlMatches(request.url(), urlOrPredicate);
321324
return urlOrPredicate(request);
322-
}, deadline, this._disconnectedPromise);
325+
};
326+
return this.waitForEvent(Events.Page.Request, { predicate, timeout: options.timeout });
323327
}
324328

325329
async waitForResponse(urlOrPredicate: string | RegExp | ((r: network.Response) => boolean), options: types.TimeoutOptions = {}): Promise<network.Response> {
326-
const deadline = this._timeoutSettings.computeDeadline(options);
327-
return helper.waitForEvent(this, Events.Page.Response, (response: network.Response) => {
330+
const predicate = (response: network.Response) => {
328331
if (helper.isString(urlOrPredicate) || helper.isRegExp(urlOrPredicate))
329332
return helper.urlMatches(response.url(), urlOrPredicate);
330333
return urlOrPredicate(response);
331-
}, deadline, this._disconnectedPromise);
334+
};
335+
return this.waitForEvent(Events.Page.Response, { predicate, timeout: options.timeout });
332336
}
333337

334338
async goBack(options?: types.NavigateOptions): Promise<network.Response | null> {

src/server/browserServer.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,16 @@ export class BrowserServer extends EventEmitter {
8383
}
8484

8585
async _closeOrKill(deadline: number): Promise<void> {
86+
let timer: NodeJS.Timer;
8687
try {
87-
await helper.waitWithDeadline(this.close(), '', deadline, ''); // The error message is ignored.
88+
await Promise.race([
89+
this.close(),
90+
new Promise((resolve, reject) => timer = setTimeout(reject, helper.timeUntilDeadline(deadline))),
91+
]);
8892
} catch (ignored) {
89-
await this.kill(); // Make sure to await actual process exit.
93+
await this.kill().catch(ignored => {}); // Make sure to await actual process exit.
94+
} finally {
95+
clearTimeout(timer!);
9096
}
9197
}
9298
}

src/server/electron.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,12 @@ export class ElectronApplication extends ExtendedEventEmitter {
153153
return this._nodeElectronHandle!.evaluateHandle(pageFunction, arg);
154154
}
155155

156-
protected _computeDeadline(options?: types.TimeoutOptions): number {
157-
return this._timeoutSettings.computeDeadline(options);
156+
protected _getLogger(): InnerLogger {
157+
return this._logger;
158+
}
159+
160+
protected _getTimeoutSettings(): TimeoutSettings {
161+
return this._timeoutSettings;
158162
}
159163
}
160164

0 commit comments

Comments
 (0)