chore: remove ExtendedEventEmitter and inline waitForEvent (#2529)

This commit is contained in:
Dmitry Gozman 2020-06-10 15:12:50 -07:00 committed by GitHub
parent 8ee19d53e7
commit 1bb33650b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 96 deletions

View File

@ -21,12 +21,13 @@ import { Page, PageBinding } from './page';
import { TimeoutSettings } from './timeoutSettings';
import * as types from './types';
import { Events } from './events';
import { ExtendedEventEmitter } from './extendedEventEmitter';
import { Download } from './download';
import { BrowserBase } from './browser';
import { InnerLogger, Logger } from './logger';
import { FunctionWithSource } from './frames';
import * as debugSupport from './debug/debugSupport';
import { EventEmitter } from 'events';
import { ProgressController } from './progress';
type CommonContextOptions = {
viewport?: types.Size | null,
@ -76,13 +77,13 @@ export interface BrowserContext {
close(): Promise<void>;
}
export abstract class BrowserContextBase extends ExtendedEventEmitter implements BrowserContext {
export abstract class BrowserContextBase extends EventEmitter implements BrowserContext {
readonly _timeoutSettings = new TimeoutSettings();
readonly _pageBindings = new Map<string, PageBinding>();
readonly _options: BrowserContextOptions;
_routes: { url: types.URLMatch, handler: network.RouteHandler }[] = [];
_closed = false;
private readonly _closePromise: Promise<Error>;
readonly _closePromise: Promise<Error>;
private _closePromiseFulfill: ((error: Error) => void) | undefined;
readonly _permissions = new Map<string, string[]>();
readonly _downloads = new Set<Download>();
@ -101,16 +102,12 @@ export abstract class BrowserContextBase extends ExtendedEventEmitter implements
await debugSupport.installConsoleHelpers(this);
}
protected _abortPromiseForEvent(event: string) {
return event === Events.BrowserContext.Close ? super._abortPromiseForEvent(event) : this._closePromise;
}
protected _getLogger(): InnerLogger {
return this._logger;
}
protected _getTimeoutSettings(): TimeoutSettings {
return this._timeoutSettings;
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
const progressController = new ProgressController(this._logger, this._timeoutSettings.timeout(options));
if (event !== Events.BrowserContext.Close)
this._closePromise.then(error => progressController.abort(error));
return progressController.run(progress => helper.waitForEvent(progress, this, event, options.predicate));
}
_browserClosed() {

View File

@ -1,57 +0,0 @@
/**
* 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 'events';
import { helper, RegisteredListener } from './helper';
import { ProgressController } from './progress';
import { InnerLogger } from './logger';
import { TimeoutSettings } from './timeoutSettings';
export abstract class ExtendedEventEmitter extends EventEmitter {
protected _abortPromiseForEvent(event: string) {
return new Promise<Error>(() => void 0);
}
protected abstract _getLogger(): InnerLogger;
protected abstract _getTimeoutSettings(): TimeoutSettings;
async waitForEvent(event: string, optionsOrPredicate: Function | { predicate?: Function, timeout?: number } = {}): Promise<any> {
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
const { predicate = () => true } = options;
const progressController = new ProgressController(this._getLogger(), this._getTimeoutSettings().timeout(options));
this._abortPromiseForEvent(event).then(error => progressController.abort(error));
return progressController.run(async progress => {
const listeners: RegisteredListener[] = [];
const promise = new Promise((resolve, reject) => {
listeners.push(helper.addEventListener(this, event, eventArg => {
try {
if (!predicate(eventArg))
return;
resolve(eventArg);
} catch (e) {
reject(e);
}
}));
});
progress.cleanupWhenAborted(() => helper.removeEventListeners(listeners));
const result = await promise;
helper.removeEventListeners(listeners);
return result;
});
}
}

View File

@ -21,6 +21,8 @@ import * as fs from 'fs';
import * as removeFolder from 'rimraf';
import * as util from 'util';
import * as types from './types';
import { Progress } from './progress';
const removeFolderAsync = util.promisify(removeFolder);
export type RegisteredListener = {
@ -278,6 +280,25 @@ class Helper {
return removeFolderAsync(dir).catch((err: Error) => console.error(err));
}));
}
static async waitForEvent(progress: Progress, emitter: EventEmitter, event: string, predicate?: Function): Promise<any> {
const listeners: RegisteredListener[] = [];
const promise = new Promise((resolve, reject) => {
listeners.push(helper.addEventListener(emitter, event, eventArg => {
try {
if (predicate && !predicate(eventArg))
return;
resolve(eventArg);
} catch (e) {
reject(e);
}
}));
});
progress.cleanupWhenAborted(() => helper.removeEventListeners(listeners));
const result = await promise;
helper.removeEventListeners(listeners);
return result;
}
}
export function assert(value: any, message?: string): asserts value {

View File

@ -28,10 +28,10 @@ import { Events } from './events';
import { BrowserContext, BrowserContextBase } from './browserContext';
import { ConsoleMessage, ConsoleMessageLocation } from './console';
import * as accessibility from './accessibility';
import { ExtendedEventEmitter } from './extendedEventEmitter';
import { EventEmitter } from 'events';
import { FileChooser } from './fileChooser';
import { logError, InnerLogger } from './logger';
import { ProgressController } from './progress';
export interface PageDelegate {
readonly rawMouse: input.RawMouse;
@ -88,7 +88,7 @@ type PageState = {
extraHTTPHeaders: network.Headers | null;
};
export class Page extends ExtendedEventEmitter {
export class Page extends EventEmitter {
private _closed = false;
private _closedCallback: () => void;
private _closedPromise: Promise<void>;
@ -138,18 +138,6 @@ export class Page extends ExtendedEventEmitter {
this.coverage = delegate.coverage ? delegate.coverage() : null;
}
protected _abortPromiseForEvent(event: string) {
return this._disconnectedPromise;
}
protected _getLogger(): InnerLogger {
return this._logger;
}
protected _getTimeoutSettings(): TimeoutSettings {
return this._timeoutSettings;
}
_didClose() {
assert(!this._closed, 'Page closed twice');
this._closed = true;
@ -337,6 +325,13 @@ export class Page extends ExtendedEventEmitter {
return this.waitForEvent(Events.Page.Response, { predicate, timeout: options.timeout });
}
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
const progressController = new ProgressController(this._logger, this._timeoutSettings.timeout(options));
this._disconnectedPromise.then(error => progressController.abort(error));
return progressController.run(progress => helper.waitForEvent(progress, this, event, options.predicate));
}
async goBack(options?: types.NavigateOptions): Promise<network.Response | null> {
const waitPromise = this.waitForNavigation(options);
const result = await this._delegate.goBack();

View File

@ -19,7 +19,6 @@ import { CRBrowser, CRBrowserContext } from '../chromium/crBrowser';
import { CRConnection, CRSession } from '../chromium/crConnection';
import { CRExecutionContext } from '../chromium/crExecutionContext';
import { Events } from '../events';
import { ExtendedEventEmitter } from '../extendedEventEmitter';
import * as js from '../javascript';
import { InnerLogger, Logger } from '../logger';
import { Page } from '../page';
@ -30,7 +29,9 @@ import { BrowserServer } from './browserServer';
import { launchProcess, waitForLine } from './processLauncher';
import { BrowserContext } from '../browserContext';
import type {BrowserWindow} from 'electron';
import { runAbortableTask } from '../progress';
import { runAbortableTask, ProgressController } from '../progress';
import { EventEmitter } from 'events';
import { helper } from '../helper';
type ElectronLaunchOptions = {
args?: string[],
@ -55,7 +56,7 @@ interface ElectronPage extends Page {
_browserWindowId: number;
}
export class ElectronApplication extends ExtendedEventEmitter {
export class ElectronApplication extends EventEmitter {
private _logger: InnerLogger;
private _browserContext: CRBrowserContext;
private _nodeConnection: CRConnection;
@ -128,6 +129,14 @@ export class ElectronApplication extends ExtendedEventEmitter {
this._nodeConnection.close();
}
async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
const options = typeof optionsOrPredicate === 'function' ? { predicate: optionsOrPredicate } : optionsOrPredicate;
const progressController = new ProgressController(this._logger, this._timeoutSettings.timeout(options));
if (event !== ElectronEvents.ElectronApplication.Close)
this._browserContext._closePromise.then(error => progressController.abort(error));
return progressController.run(progress => helper.waitForEvent(progress, this, event, options.predicate));
}
async _init() {
this._nodeSession.once('Runtime.executionContextCreated', event => {
this._nodeExecutionContext = new js.ExecutionContext(new CRExecutionContext(this._nodeSession, event.context));
@ -152,14 +161,6 @@ export class ElectronApplication extends ExtendedEventEmitter {
async evaluateHandle<R, Arg>(pageFunction: types.FuncOn<any, Arg, R>, arg: Arg): Promise<types.SmartHandle<R>> {
return this._nodeElectronHandle!.evaluateHandle(pageFunction, arg);
}
protected _getLogger(): InnerLogger {
return this._logger;
}
protected _getTimeoutSettings(): TimeoutSettings {
return this._timeoutSettings;
}
}
export class Electron {

View File

@ -185,4 +185,6 @@ export type ProxySettings = {
bypass?: string,
username?: string,
password?: string
}
};
export type WaitForEventOptions = Function | { predicate?: Function, timeout?: number };