Skip to content

Commit

Permalink
chore(waitForEvent): refactor waitForEvent into a single implementati…
Browse files Browse the repository at this point in the history
…on (#1602)

Moves the `waitForEvent` implementation into an `ExtendedEventEmitter` class.

This is step one if we want to add `waitForEvent` to `Worker`, `Browser`, and `BrowserServer` objects. All of these only have a 'close' event, but I still feel we should be consistent with our event emitters.
  • Loading branch information
JoelEinbinder committed Mar 31, 2020
1 parent 314eb40 commit 9e85f8d
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 21 deletions.
23 changes: 10 additions & 13 deletions src/browserContext.ts
Expand Up @@ -18,10 +18,10 @@
import { helper } from './helper';
import * as network from './network';
import { Page, PageBinding } from './page';
import * as platform from './platform';
import { TimeoutSettings } from './timeoutSettings';
import * as types from './types';
import { Events } from './events';
import { ExtendedEventEmitter } from './extendedEventEmitter';

export type BrowserContextOptions = {
viewport?: types.Size | null,
Expand Down Expand Up @@ -62,7 +62,7 @@ export interface BrowserContext {
close(): Promise<void>;
}

export abstract class BrowserContextBase extends platform.EventEmitter implements BrowserContext {
export abstract class BrowserContextBase extends ExtendedEventEmitter implements BrowserContext {
readonly _timeoutSettings = new TimeoutSettings();
readonly _pageBindings = new Map<string, PageBinding>();
readonly _options: BrowserContextOptions;
Expand All @@ -78,6 +78,14 @@ export abstract class BrowserContextBase extends platform.EventEmitter implement
this._closePromise = new Promise(fulfill => this._closePromiseFulfill = fulfill);
}

protected _abortPromiseForEvent(event: string) {
return event === Events.BrowserContext.Close ? super._abortPromiseForEvent(event) : this._closePromise;
}

protected _timeoutForEvent(event: string): number {
return this._timeoutSettings.timeout();
}

_browserClosed() {
for (const page of this.pages())
page._didClose();
Expand Down Expand Up @@ -132,17 +140,6 @@ export abstract class BrowserContextBase extends platform.EventEmitter implement
setDefaultTimeout(timeout: number) {
this._timeoutSettings.setDefaultTimeout(timeout);
}

async waitForEvent(event: string, optionsOrPredicate?: Function | (types.TimeoutOptions & { predicate?: Function })): Promise<any> {
if (!optionsOrPredicate)
optionsOrPredicate = {};
if (typeof optionsOrPredicate === 'function')
optionsOrPredicate = { predicate: optionsOrPredicate };
const { timeout = this._timeoutSettings.timeout(), predicate = () => true } = optionsOrPredicate;

const abortPromise = (event === Events.BrowserContext.Close) ? new Promise<Error>(() => { }) : this._closePromise;
return helper.waitForEvent(this, event, (...args: any[]) => !!predicate(...args), timeout, abortPromise);
}
}

export function assertBrowserContextIsNotOwned(context: BrowserContextBase) {
Expand Down
36 changes: 36 additions & 0 deletions src/extendedEventEmitter.ts
@@ -0,0 +1,36 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { EventEmitter } from './platform';
import { helper } from './helper';

export class ExtendedEventEmitter extends EventEmitter {
protected _abortPromiseForEvent(event: string) {
return new Promise<Error>(() => void 0);
}

protected _timeoutForEvent(event: string): number {
throw new Error('unimplemented');
}

async waitForEvent(event: string, optionsOrPredicate: Function|{ predicate?: Function, timeout?: number } = {}): Promise<any> {
const {
predicate = () => true,
timeout = this._timeoutForEvent(event)
} = typeof optionsOrPredicate === 'function' ? {predicate: optionsOrPredicate} : optionsOrPredicate;
return helper.waitForEvent(this, event, predicate, timeout, this._abortPromiseForEvent(event));
}
}
18 changes: 10 additions & 8 deletions src/page.ts
Expand Up @@ -29,6 +29,7 @@ import { BrowserContext, BrowserContextBase } from './browserContext';
import { ConsoleMessage, ConsoleMessageLocation } from './console';
import * as accessibility from './accessibility';
import * as platform from './platform';
import { ExtendedEventEmitter } from './extendedEventEmitter';

export interface PageDelegate {
readonly rawMouse: input.RawMouse;
Expand Down Expand Up @@ -87,7 +88,7 @@ export type FileChooser = {
multiple: boolean
};

export class Page extends platform.EventEmitter {
export class Page extends ExtendedEventEmitter {
private _closed = false;
private _closedCallback: () => void;
private _closedPromise: Promise<void>;
Expand Down Expand Up @@ -142,6 +143,14 @@ export class Page extends platform.EventEmitter {
this.coverage = delegate.coverage ? delegate.coverage() : null;
}

protected _abortPromiseForEvent(event: string) {
return this._disconnectedPromise;
}

protected _timeoutForEvent(event: string): number {
return this._timeoutSettings.timeout();
}

_didClose() {
assert(!this._closed, 'Page closed twice');
this._closed = true;
Expand Down Expand Up @@ -303,13 +312,6 @@ export class Page extends platform.EventEmitter {
return this.mainFrame().waitForNavigation(options);
}

async waitForEvent(event: string, optionsOrPredicate: Function | (types.TimeoutOptions & { predicate?: Function }) = {}): Promise<any> {
if (typeof optionsOrPredicate === 'function')
optionsOrPredicate = { predicate: optionsOrPredicate };
const { timeout = this._timeoutSettings.timeout(), predicate = () => true } = optionsOrPredicate;
return helper.waitForEvent(this, event, (...args: any[]) => !!predicate(...args), timeout, this._disconnectedPromise);
}

async waitForRequest(urlOrPredicate: string | RegExp | ((r: network.Request) => boolean), options: types.TimeoutOptions = {}): Promise<network.Request> {
const { timeout = this._timeoutSettings.timeout() } = options;
return helper.waitForEvent(this, Events.Page.Request, (request: network.Request) => {
Expand Down

0 comments on commit 9e85f8d

Please sign in to comment.