diff --git a/src/browser.ts b/src/browser.ts index c86e7a8c94..a193351236 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -19,7 +19,6 @@ import { BrowserContext } from './browserContext'; import { Page } from './page'; import { EventEmitter } from 'events'; import { Download } from './download'; -import { Events } from './events'; import { ProxySettings } from './types'; import { ChildProcess } from 'child_process'; @@ -40,6 +39,10 @@ export type BrowserOptions = types.UIOptions & { }; export abstract class Browser extends EventEmitter { + static Events = { + Disconnected: 'disconnected', + }; + readonly _options: BrowserOptions; private _downloads = new Map(); _defaultContext: BrowserContext | null = null; @@ -87,7 +90,7 @@ export abstract class Browser extends EventEmitter { context._browserClosed(); if (this._defaultContext) this._defaultContext._browserClosed(); - this.emit(Events.Browser.Disconnected); + this.emit(Browser.Events.Disconnected); } async close() { @@ -96,7 +99,7 @@ export abstract class Browser extends EventEmitter { await this._options.browserProcess.close(); } if (this.isConnected()) - await new Promise(x => this.once(Events.Browser.Disconnected, x)); + await new Promise(x => this.once(Browser.Events.Disconnected, x)); } } diff --git a/src/browserContext.ts b/src/browserContext.ts index f8fe3305a6..a1a66dd0bd 100644 --- a/src/browserContext.ts +++ b/src/browserContext.ts @@ -23,7 +23,6 @@ import { Page, PageBinding } from './page'; import { TimeoutSettings } from './timeoutSettings'; import * as frames from './frames'; import * as types from './types'; -import { Events } from './events'; import { Download } from './download'; import { Browser } from './browser'; import { EventEmitter } from 'events'; @@ -40,6 +39,13 @@ export class Screencast { } export abstract class BrowserContext extends EventEmitter { + static Events = { + Close: 'close', + Page: 'page', + ScreencastStarted: 'screencaststarted', + ScreencastStopped: 'screencaststopped', + }; + readonly _timeoutSettings = new TimeoutSettings(); readonly _pageBindings = new Map(); readonly _options: types.BrowserContextOptions; @@ -81,7 +87,7 @@ export abstract class BrowserContext extends EventEmitter { this._closedStatus = 'closed'; this._downloads.clear(); this._closePromiseFulfill!(new Error('Context closed')); - this.emit(Events.BrowserContext.Close); + this.emit(BrowserContext.Events.Close); } // BrowserContext methods. @@ -160,7 +166,7 @@ export abstract class BrowserContext extends EventEmitter { async _loadDefaultContext(progress: Progress) { if (!this.pages().length) { - const waitForEvent = helper.waitForEvent(progress, this, Events.BrowserContext.Page); + const waitForEvent = helper.waitForEvent(progress, this, BrowserContext.Events.Page); progress.cleanupWhenAborted(() => waitForEvent.dispose); await waitForEvent.promise; } diff --git a/src/chromium/crBrowser.ts b/src/chromium/crBrowser.ts index e5e05e225f..be97bf7614 100644 --- a/src/chromium/crBrowser.ts +++ b/src/chromium/crBrowser.ts @@ -17,7 +17,6 @@ import { Browser, BrowserOptions } from '../browser'; import { assertBrowserContextIsNotOwned, BrowserContext, validateBrowserContextOptions, verifyGeolocation } from '../browserContext'; -import { Events as CommonEvents } from '../events'; import { assert } from '../helper'; import * as network from '../network'; import { Page, PageBinding, Worker } from '../page'; @@ -26,7 +25,6 @@ import * as types from '../types'; import { ConnectionEvents, CRConnection, CRSession } from './crConnection'; import { CRPage } from './crPage'; import { readProtocolStream } from './crProtocolHelper'; -import { Events } from './events'; import { Protocol } from './protocol'; import { CRExecutionContext } from './crExecutionContext'; import { CRDevTools } from './crDevTools'; @@ -151,7 +149,7 @@ export class CRBrowser extends Browser { const backgroundPage = new CRPage(session, targetInfo.targetId, context, null, false); this._backgroundPages.set(targetInfo.targetId, backgroundPage); backgroundPage.pageOrError().then(() => { - context!.emit(Events.ChromiumBrowserContext.BackgroundPage, backgroundPage._page); + context!.emit(CRBrowserContext.CREvents.BackgroundPage, backgroundPage._page); }); return; } @@ -164,11 +162,11 @@ export class CRBrowser extends Browser { const page = crPage._page; if (pageOrError instanceof Error) page._setIsError(); - context!.emit(CommonEvents.BrowserContext.Page, page); + context!.emit(BrowserContext.Events.Page, page); if (opener) { opener.pageOrError().then(openerPage => { if (openerPage instanceof Page && !openerPage.isClosed()) - openerPage.emit(CommonEvents.Page.Popup, page); + openerPage.emit(Page.Events.Popup, page); }); } }); @@ -178,7 +176,7 @@ export class CRBrowser extends Browser { if (targetInfo.type === 'service_worker') { const serviceWorker = new CRServiceWorker(context, session, targetInfo.url); this._serviceWorkers.set(targetInfo.targetId, serviceWorker); - context.emit(Events.ChromiumBrowserContext.ServiceWorker, serviceWorker); + context.emit(CRBrowserContext.CREvents.ServiceWorker, serviceWorker); return; } @@ -202,7 +200,7 @@ export class CRBrowser extends Browser { const serviceWorker = this._serviceWorkers.get(targetId); if (serviceWorker) { this._serviceWorkers.delete(targetId); - serviceWorker.emit(CommonEvents.Worker.Close); + serviceWorker.emit(Worker.Events.Close); return; } } @@ -280,6 +278,11 @@ class CRServiceWorker extends Worker { } export class CRBrowserContext extends BrowserContext { + static CREvents = { + BackgroundPage: 'backgroundpage', + ServiceWorker: 'serviceworker', + }; + readonly _browser: CRBrowser; readonly _browserContextId: string | null; readonly _evaluateOnNewDocumentSources: string[]; @@ -432,7 +435,7 @@ export class CRBrowserContext extends BrowserContext { // asynchronously and we get detached from them later. // To avoid the wrong order of notifications, we manually fire // "close" event here and forget about the serivce worker. - serviceWorker.emit(CommonEvents.Worker.Close); + serviceWorker.emit(Worker.Events.Close); this._browser._serviceWorkers.delete(targetId); } } diff --git a/src/chromium/crPage.ts b/src/chromium/crPage.ts index 391c419483..0dbb46ffc9 100644 --- a/src/chromium/crPage.ts +++ b/src/chromium/crPage.ts @@ -24,7 +24,6 @@ import { CRExecutionContext } from './crExecutionContext'; import { CRNetworkManager } from './crNetworkManager'; import { Page, Worker, PageBinding } from '../page'; import { Protocol } from './protocol'; -import { Events } from '../events'; import { toConsoleMessageLocation, exceptionToError, releaseObject } from './crProtocolHelper'; import * as dialog from '../dialog'; import { PageDelegate } from '../page'; @@ -590,7 +589,7 @@ class FrameSession { const args = event.args.map(o => worker._existingExecutionContext!.createHandle(o)); this._page._addConsoleMessage(event.type, args, toConsoleMessageLocation(event.stackTrace)); }); - session.on('Runtime.exceptionThrown', exception => this._page.emit(Events.Page.PageError, exceptionToError(exception.exceptionDetails))); + session.on('Runtime.exceptionThrown', exception => this._page.emit(Page.Events.PageError, exceptionToError(exception.exceptionDetails))); // TODO: attribute workers to the right frame. this._networkManager.instrumentNetworkEvents(session, this._page._frameManager.frame(this._targetId)!); } @@ -664,7 +663,7 @@ class FrameSession { } _onDialog(event: Protocol.Page.javascriptDialogOpeningPayload) { - this._page.emit(Events.Page.Dialog, new dialog.Dialog( + this._page.emit(Page.Events.Dialog, new dialog.Dialog( event.type, event.message, async (accept: boolean, promptText?: string) => { @@ -674,7 +673,7 @@ class FrameSession { } _handleException(exceptionDetails: Protocol.Runtime.ExceptionDetails) { - this._page.emit(Events.Page.PageError, exceptionToError(exceptionDetails)); + this._page.emit(Page.Events.PageError, exceptionToError(exceptionDetails)); } async _onTargetCrashed() { @@ -692,7 +691,7 @@ class FrameSession { lineNumber: lineNumber || 0, columnNumber: 0, }; - this._page.emit(Events.Page.Console, new ConsoleMessage(level, text, [], location)); + this._page.emit(Page.Events.Console, new ConsoleMessage(level, text, [], location)); } } diff --git a/src/chromium/events.ts b/src/chromium/events.ts deleted file mode 100644 index ab8326b047..0000000000 --- a/src/chromium/events.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright 2019 Google Inc. All rights reserved. - * Modifications 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. - */ - -export const Events = { - ChromiumBrowserContext: { - BackgroundPage: 'backgroundpage', - ServiceWorker: 'serviceworker', - } -}; diff --git a/src/debug/debugController.ts b/src/debug/debugController.ts index 7fb26f8af0..d18af7707f 100644 --- a/src/debug/debugController.ts +++ b/src/debug/debugController.ts @@ -15,7 +15,6 @@ */ import { BrowserContext } from '../browserContext'; -import { Events } from '../events'; import * as frames from '../frames'; import * as js from '../javascript'; import { Page } from '../page'; @@ -23,10 +22,10 @@ import DebugScript from './injected/debugScript'; export class DebugController { constructor(context: BrowserContext) { - context.on(Events.BrowserContext.Page, (page: Page) => { + context.on(BrowserContext.Events.Page, (page: Page) => { for (const frame of page.frames()) this.ensureInstalledInFrame(frame); - page.on(Events.Page.FrameNavigated, frame => this.ensureInstalledInFrame(frame)); + page.on(Page.Events.FrameNavigated, frame => this.ensureInstalledInFrame(frame)); }); } diff --git a/src/download.ts b/src/download.ts index 065cf0906d..93e9e0c268 100644 --- a/src/download.ts +++ b/src/download.ts @@ -18,7 +18,6 @@ import * as path from 'path'; import * as fs from 'fs'; import * as util from 'util'; import { Page } from './page'; -import { Events } from './events'; import { Readable } from 'stream'; import { assert, mkdirIfNeeded } from './helper'; @@ -47,13 +46,13 @@ export class Download { page._browserContext._downloads.add(this); this._acceptDownloads = !!this._page._browserContext._options.acceptDownloads; if (suggestedFilename !== undefined) - this._page.emit(Events.Page.Download, this); + this._page.emit(Page.Events.Download, this); } _filenameSuggested(suggestedFilename: string) { assert(this._suggestedFilename === undefined); this._suggestedFilename = suggestedFilename; - this._page.emit(Events.Page.Download, this); + this._page.emit(Page.Events.Download, this); } url(): string { diff --git a/src/events.ts b/src/events.ts deleted file mode 100644 index f8208d2edd..0000000000 --- a/src/events.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright 2019 Google Inc. All rights reserved. - * Modifications 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. - */ - -export const Events = { - Browser: { - Disconnected: 'disconnected' - }, - - BrowserContext: { - Close: 'close', - Page: 'page', - ScreencastStarted: 'screencaststarted', - ScreencastStopped: 'screencaststopped', - }, - - BrowserServer: { - Close: 'close', - }, - - Page: { - Close: 'close', - Crash: 'crash', - Console: 'console', - Dialog: 'dialog', - Download: 'download', - FileChooser: 'filechooser', - DOMContentLoaded: 'domcontentloaded', - // Can't use just 'error' due to node.js special treatment of error events. - // @see https://nodejs.org/api/events.html#events_error_events - PageError: 'pageerror', - Request: 'request', - Response: 'response', - RequestFailed: 'requestfailed', - RequestFinished: 'requestfinished', - FrameAttached: 'frameattached', - FrameDetached: 'framedetached', - FrameNavigated: 'framenavigated', - Load: 'load', - Popup: 'popup', - Worker: 'worker', - }, - - Worker: { - Close: 'close', - }, -}; diff --git a/src/firefox/ffBrowser.ts b/src/firefox/ffBrowser.ts index 8d824874f1..6627724228 100644 --- a/src/firefox/ffBrowser.ts +++ b/src/firefox/ffBrowser.ts @@ -17,7 +17,6 @@ import { Browser, BrowserOptions } from '../browser'; import { assertBrowserContextIsNotOwned, BrowserContext, validateBrowserContextOptions, verifyGeolocation } from '../browserContext'; -import { Events } from '../events'; import { assert, helper, RegisteredListener } from '../helper'; import * as network from '../network'; import { Page, PageBinding } from '../page'; @@ -129,12 +128,12 @@ export class FFBrowser extends Browser { const page = ffPage._page; if (pageOrError instanceof Error) page._setIsError(); - context.emit(Events.BrowserContext.Page, page); + context.emit(BrowserContext.Events.Page, page); if (!opener) return; const openerPage = await opener.pageOrError(); if (openerPage instanceof Page && !openerPage.isClosed()) - openerPage.emit(Events.Page.Popup, page); + openerPage.emit(Page.Events.Popup, page); }); } diff --git a/src/firefox/ffPage.ts b/src/firefox/ffPage.ts index 62cf56a021..01353e87ef 100644 --- a/src/firefox/ffPage.ts +++ b/src/firefox/ffPage.ts @@ -17,7 +17,6 @@ import * as dialog from '../dialog'; import * as dom from '../dom'; -import { Events } from '../events'; import * as frames from '../frames'; import { assert, helper, RegisteredListener } from '../helper'; import { Page, PageBinding, PageDelegate, Worker } from '../page'; @@ -32,7 +31,7 @@ import { FFNetworkManager } from './ffNetworkManager'; import { Protocol } from './protocol'; import { selectors } from '../selectors'; import { rewriteErrorMessage } from '../utils/stackTrace'; -import { Screencast } from '../browserContext'; +import { Screencast, BrowserContext } from '../browserContext'; const UTILITY_WORLD_NAME = '__playwright_utility_world__'; @@ -62,7 +61,7 @@ export class FFPage implements PageDelegate { this._browserContext = browserContext; this._page = new Page(this, browserContext); this._networkManager = new FFNetworkManager(session, this._page); - this._page.on(Events.Page.FrameDetached, frame => this._removeContextsForFrame(frame)); + this._page.on(Page.Events.FrameDetached, frame => this._removeContextsForFrame(frame)); // TODO: remove Page.willOpenNewWindowAsynchronously from the protocol. this._eventListeners = [ helper.addEventListener(this._session, 'Page.eventFired', this._onEventFired.bind(this)), @@ -179,7 +178,7 @@ export class FFPage implements PageDelegate { const message = params.message.startsWith('Error: ') ? params.message.substring(7) : params.message; const error = new Error(message); error.stack = params.stack; - this._page.emit(Events.Page.PageError, error); + this._page.emit(Page.Events.PageError, error); } _onConsole(payload: Protocol.Runtime.consolePayload) { @@ -189,7 +188,7 @@ export class FFPage implements PageDelegate { } _onDialogOpened(params: Protocol.Page.dialogOpenedPayload) { - this._page.emit(Events.Page.Dialog, new dialog.Dialog( + this._page.emit(Page.Events.Dialog, new dialog.Dialog( params.type, params.message, async (accept: boolean, promptText?: string) => { @@ -262,7 +261,7 @@ export class FFPage implements PageDelegate { _onScreencastStarted(event: Protocol.Page.screencastStartedPayload) { const screencast = new Screencast(event.file, this._page); this._idToScreencast.set(event.uid, screencast); - this._browserContext.emit(Events.BrowserContext.ScreencastStarted, screencast); + this._browserContext.emit(BrowserContext.Events.ScreencastStarted, screencast); } _onScreencastStopped(event: Protocol.Page.screencastStoppedPayload) { @@ -270,7 +269,7 @@ export class FFPage implements PageDelegate { if (!screencast) return; this._idToScreencast.delete(event.uid); - this._browserContext.emit(Events.BrowserContext.ScreencastStopped, screencast); + this._browserContext.emit(BrowserContext.Events.ScreencastStopped, screencast); } async exposeBinding(binding: PageBinding) { diff --git a/src/frames.ts b/src/frames.ts index 522a099ef0..79b99887a0 100644 --- a/src/frames.ts +++ b/src/frames.ts @@ -17,7 +17,6 @@ import { ConsoleMessage } from './console'; import * as dom from './dom'; -import { Events } from './events'; import { assert, helper, RegisteredListener, debugLogger } from './helper'; import * as js from './javascript'; import * as network from './network'; @@ -50,7 +49,6 @@ type ConsoleTagHandler = () => void; export type FunctionWithSource = (source: { context: BrowserContext, page: Page, frame: Frame}, ...args: any) => any; -export const kNavigationEvent = Symbol('navigation'); export type NavigationEvent = { // New frame url after navigation. url: string, @@ -63,8 +61,6 @@ export type NavigationEvent = { // the navigation did not commit. error?: Error, }; -export const kAddLifecycleEvent = Symbol('addLifecycle'); -export const kRemoveLifecycleEvent = Symbol('removeLifecycle'); export class FrameManager { private _page: Page; @@ -120,7 +116,7 @@ export class FrameManager { assert(!this._frames.has(frameId)); const frame = new Frame(this._page, frameId, parentFrame); this._frames.set(frameId, frame); - this._page.emit(Events.Page.FrameAttached, frame); + this._page.emit(Page.Events.FrameAttached, frame); return frame; } } @@ -197,10 +193,10 @@ export class FrameManager { frame._onClearLifecycle(); const navigationEvent: NavigationEvent = { url, name, newDocument: frame._currentDocument }; - frame._eventEmitter.emit(kNavigationEvent, navigationEvent); + frame.emit(Frame.Events.Navigation, navigationEvent); if (!initial) { debugLogger.log('api', ` navigated to "${url}"`); - this._page.emit(Events.Page.FrameNavigated, frame); + this._page.emit(Page.Events.FrameNavigated, frame); } // Restore pending if any - see comments above about keepPending. frame._pendingDocument = keepPending; @@ -212,9 +208,9 @@ export class FrameManager { return; frame._url = url; const navigationEvent: NavigationEvent = { url, name: frame._name }; - frame._eventEmitter.emit(kNavigationEvent, navigationEvent); + frame.emit(Frame.Events.Navigation, navigationEvent); debugLogger.log('api', ` navigated to "${url}"`); - this._page.emit(Events.Page.FrameNavigated, frame); + this._page.emit(Page.Events.FrameNavigated, frame); } frameAbortedNavigation(frameId: string, errorText: string, documentId?: string) { @@ -230,7 +226,7 @@ export class FrameManager { error: new Error(errorText), }; frame._pendingDocument = undefined; - frame._eventEmitter.emit(kNavigationEvent, navigationEvent); + frame.emit(Frame.Events.Navigation, navigationEvent); } frameDetached(frameId: string) { @@ -266,13 +262,13 @@ export class FrameManager { requestReceivedResponse(response: network.Response) { if (!response.request()._isFavicon) - this._page.emit(Events.Page.Response, response); + this._page.emit(Page.Events.Response, response); } requestFinished(request: network.Request) { this._inflightRequestFinished(request); if (!request._isFavicon) - this._page.emit(Events.Page.RequestFinished, request); + this._page.emit(Page.Events.RequestFinished, request); } requestFailed(request: network.Request, canceled: boolean) { @@ -285,7 +281,7 @@ export class FrameManager { this.frameAbortedNavigation(frame._id, errorText, frame._pendingDocument.documentId); } if (!request._isFavicon) - this._page.emit(Events.Page.RequestFailed, request); + this._page.emit(Page.Events.RequestFailed, request); } removeChildFramesRecursively(frame: Frame) { @@ -297,7 +293,7 @@ export class FrameManager { this.removeChildFramesRecursively(frame); frame._onDetached(); this._frames.delete(frame._id); - this._page.emit(Events.Page.FrameDetached, frame); + this._page.emit(Page.Events.FrameDetached, frame); } private _inflightRequestFinished(request: network.Request) { @@ -333,8 +329,13 @@ export class FrameManager { } } -export class Frame { - readonly _eventEmitter: EventEmitter; +export class Frame extends EventEmitter { + static Events = { + Navigation: 'navigation', + AddLifecycle: 'addlifecycle', + RemoveLifecycle: 'removelifecycle', + }; + _id: string; private _firedLifecycleEvents = new Set(); _subtreeLifecycleEvents = new Set(); @@ -354,8 +355,8 @@ export class Frame { private _detachedCallback = () => {}; constructor(page: Page, id: string, parentFrame: Frame | null) { - this._eventEmitter = new EventEmitter(); - this._eventEmitter.setMaxListeners(0); + super(); + this.setMaxListeners(0); this._id = id; this._page = page; this._parentFrame = parentFrame; @@ -406,18 +407,18 @@ export class Frame { for (const event of events) { // Checking whether we have already notified about this event. if (!this._subtreeLifecycleEvents.has(event)) { - this._eventEmitter.emit(kAddLifecycleEvent, event); + this.emit(Frame.Events.AddLifecycle, event); if (this === mainFrame && this._url !== 'about:blank') debugLogger.log('api', ` "${event}" event fired`); if (this === mainFrame && event === 'load') - this._page.emit(Events.Page.Load); + this._page.emit(Page.Events.Load); if (this === mainFrame && event === 'domcontentloaded') - this._page.emit(Events.Page.DOMContentLoaded); + this._page.emit(Page.Events.DOMContentLoaded); } } for (const event of this._subtreeLifecycleEvents) { if (!events.has(event)) - this._eventEmitter.emit(kRemoveLifecycleEvent, event); + this.emit(Frame.Events.RemoveLifecycle, event); } this._subtreeLifecycleEvents = events; } @@ -436,13 +437,13 @@ export class Frame { } url = helper.completeUserURL(url); - const sameDocument = helper.waitForEvent(progress, this._eventEmitter, kNavigationEvent, (e: NavigationEvent) => !e.newDocument); + const sameDocument = helper.waitForEvent(progress, this, Frame.Events.Navigation, (e: NavigationEvent) => !e.newDocument); const navigateResult = await this._page._delegate.navigateFrame(this, url, referer); let event: NavigationEvent; if (navigateResult.newDocumentId) { sameDocument.dispose(); - event = await helper.waitForEvent(progress, this._eventEmitter, kNavigationEvent, (event: NavigationEvent) => { + event = await helper.waitForEvent(progress, this, Frame.Events.Navigation, (event: NavigationEvent) => { // We are interested either in this specific document, or any other document that // did commit and replaced the expected document. return event.newDocument && (event.newDocument.documentId === navigateResult.newDocumentId || !event.error); @@ -460,7 +461,7 @@ export class Frame { } if (!this._subtreeLifecycleEvents.has(waitUntil)) - await helper.waitForEvent(progress, this._eventEmitter, kAddLifecycleEvent, (e: types.LifecycleEvent) => e === waitUntil).promise; + await helper.waitForEvent(progress, this, Frame.Events.AddLifecycle, (e: types.LifecycleEvent) => e === waitUntil).promise; const request = event.newDocument ? event.newDocument.request : undefined; const response = request ? request._finalRequest().response() : null; @@ -474,7 +475,7 @@ export class Frame { const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil); progress.log(`waiting for navigation until "${waitUntil}"`); - const navigationEvent: NavigationEvent = await helper.waitForEvent(progress, this._eventEmitter, kNavigationEvent, (event: NavigationEvent) => { + const navigationEvent: NavigationEvent = await helper.waitForEvent(progress, this, Frame.Events.Navigation, (event: NavigationEvent) => { // Any failed navigation results in a rejection. if (event.error) return true; @@ -485,7 +486,7 @@ export class Frame { throw navigationEvent.error; if (!this._subtreeLifecycleEvents.has(waitUntil)) - await helper.waitForEvent(progress, this._eventEmitter, kAddLifecycleEvent, (e: types.LifecycleEvent) => e === waitUntil).promise; + await helper.waitForEvent(progress, this, Frame.Events.AddLifecycle, (e: types.LifecycleEvent) => e === waitUntil).promise; const request = navigationEvent.newDocument ? navigationEvent.newDocument.request : undefined; return request ? request._finalRequest().response() : null; @@ -499,7 +500,7 @@ export class Frame { async _waitForLoadState(progress: Progress, state: types.LifecycleEvent): Promise { const waitUntil = verifyLifecycle('state', state); if (!this._subtreeLifecycleEvents.has(waitUntil)) - await helper.waitForEvent(progress, this._eventEmitter, kAddLifecycleEvent, (e: types.LifecycleEvent) => e === waitUntil).promise; + await helper.waitForEvent(progress, this, Frame.Events.AddLifecycle, (e: types.LifecycleEvent) => e === waitUntil).promise; } async frameElement(): Promise { @@ -752,7 +753,7 @@ export class Frame { resolve(); }); const errorPromise = new Promise(resolve => { - listeners.push(helper.addEventListener(this._page, Events.Page.Console, (message: ConsoleMessage) => { + listeners.push(helper.addEventListener(this._page, Page.Events.Console, (message: ConsoleMessage) => { if (message.type() === 'error' && message.text().includes('Content Security Policy')) { cspMessage = message; resolve(); @@ -1045,7 +1046,7 @@ class SignalBarrier { async addFrameNavigation(frame: Frame) { this.retain(); - const waiter = helper.waitForEvent(null, frame._eventEmitter, kNavigationEvent, (e: NavigationEvent) => { + const waiter = helper.waitForEvent(null, frame, Frame.Events.Navigation, (e: NavigationEvent) => { if (!e.error && this._progress) this._progress.log(` navigated to "${frame._url}"`); return true; diff --git a/src/page.ts b/src/page.ts index fdb8df9947..5527530b2b 100644 --- a/src/page.ts +++ b/src/page.ts @@ -24,7 +24,6 @@ import * as network from './network'; import { Screenshotter } from './screenshotter'; import { TimeoutSettings } from './timeoutSettings'; import * as types from './types'; -import { Events } from './events'; import { BrowserContext } from './browserContext'; import { ConsoleMessage } from './console'; import * as accessibility from './accessibility'; @@ -91,6 +90,29 @@ type PageState = { }; export class Page extends EventEmitter { + static Events = { + Close: 'close', + Crash: 'crash', + Console: 'console', + Dialog: 'dialog', + Download: 'download', + FileChooser: 'filechooser', + DOMContentLoaded: 'domcontentloaded', + // Can't use just 'error' due to node.js special treatment of error events. + // @see https://nodejs.org/api/events.html#events_error_events + PageError: 'pageerror', + Request: 'request', + Response: 'response', + RequestFailed: 'requestfailed', + RequestFinished: 'requestfinished', + FrameAttached: 'frameattached', + FrameDetached: 'framedetached', + FrameNavigated: 'framenavigated', + Load: 'load', + Popup: 'popup', + Worker: 'worker', + }; + private _closedState: 'open' | 'closing' | 'closed' = 'open'; private _closedCallback: () => void; private _closedPromise: Promise; @@ -154,13 +176,13 @@ export class Page extends EventEmitter { this._frameManager.dispose(); assert(this._closedState !== 'closed', 'Page closed twice'); this._closedState = 'closed'; - this.emit(Events.Page.Close); + this.emit(Page.Events.Close); this._closedCallback(); } _didCrash() { this._frameManager.dispose(); - this.emit(Events.Page.Crash); + this.emit(Page.Events.Crash); this._crashedCallback(new Error('Page crashed')); } @@ -179,12 +201,12 @@ export class Page extends EventEmitter { async _onFileChooserOpened(handle: dom.ElementHandle) { const multiple = await handle.evaluate(element => !!(element as HTMLInputElement).multiple); - if (!this.listenerCount(Events.Page.FileChooser)) { + if (!this.listenerCount(Page.Events.FileChooser)) { handle.dispose(); return; } const fileChooser = new FileChooser(this, handle, multiple); - this.emit(Events.Page.FileChooser, fileChooser); + this.emit(Page.Events.FileChooser, fileChooser); } context(): BrowserContext { @@ -235,10 +257,10 @@ export class Page extends EventEmitter { _addConsoleMessage(type: string, args: js.JSHandle[], location: types.ConsoleMessageLocation, text?: string) { const message = new ConsoleMessage(type, text, args, location); const intercepted = this._frameManager.interceptConsoleMessage(message); - if (intercepted || !this.listenerCount(Events.Page.Console)) + if (intercepted || !this.listenerCount(Page.Events.Console)) args.forEach(arg => arg.dispose()); else - this.emit(Events.Page.Console, message); + this.emit(Page.Events.Console, message); } async reload(options?: types.NavigateOptions): Promise { @@ -315,7 +337,7 @@ export class Page extends EventEmitter { } _requestStarted(request: network.Request) { - this.emit(Events.Page.Request, request); + this.emit(Page.Events.Request, request); const route = request._route(); if (!route) return; @@ -362,20 +384,20 @@ export class Page extends EventEmitter { _addWorker(workerId: string, worker: Worker) { this._workers.set(workerId, worker); - this.emit(Events.Page.Worker, worker); + this.emit(Page.Events.Worker, worker); } _removeWorker(workerId: string) { const worker = this._workers.get(workerId); if (!worker) return; - worker.emit(Events.Worker.Close, worker); + worker.emit(Worker.Events.Close, worker); this._workers.delete(workerId); } _clearWorkers() { for (const [workerId, worker] of this._workers) { - worker.emit(Events.Worker.Close, worker); + worker.emit(Worker.Events.Close, worker); this._workers.delete(workerId); } } @@ -386,6 +408,10 @@ export class Page extends EventEmitter { } export class Worker extends EventEmitter { + static Events = { + Close: 'close', + }; + private _url: string; private _executionContextPromise: Promise; private _executionContextCallback: (value?: js.ExecutionContext) => void; diff --git a/src/rpc/server/browserContextDispatcher.ts b/src/rpc/server/browserContextDispatcher.ts index 7a3529ad60..4183401830 100644 --- a/src/rpc/server/browserContextDispatcher.ts +++ b/src/rpc/server/browserContextDispatcher.ts @@ -15,14 +15,12 @@ */ import { BrowserContext } from '../../browserContext'; -import { Events } from '../../events'; import { Dispatcher, DispatcherScope, lookupDispatcher } from './dispatcher'; import { PageDispatcher, BindingCallDispatcher, WorkerDispatcher } from './pageDispatcher'; import * as channels from '../channels'; import { RouteDispatcher, RequestDispatcher } from './networkDispatchers'; import { CRBrowserContext } from '../../chromium/crBrowser'; import { CDPSessionDispatcher } from './cdpSessionDispatcher'; -import { Events as ChromiumEvents } from '../../chromium/events'; export class BrowserContextDispatcher extends Dispatcher implements channels.BrowserContextChannel { private _context: BrowserContext; @@ -33,8 +31,8 @@ export class BrowserContextDispatcher extends Dispatcher this._dispatchEvent('page', { page: new PageDispatcher(this._scope, page) })); - context.on(Events.BrowserContext.Close, () => { + context.on(BrowserContext.Events.Page, page => this._dispatchEvent('page', { page: new PageDispatcher(this._scope, page) })); + context.on(BrowserContext.Events.Close, () => { this._dispatchEvent('close'); this._dispose(); }); @@ -42,10 +40,10 @@ export class BrowserContextDispatcher extends Dispatcher this._dispatchEvent('crBackgroundPage', { page: new PageDispatcher(this._scope, page) })); + context.on(CRBrowserContext.CREvents.BackgroundPage, page => this._dispatchEvent('crBackgroundPage', { page: new PageDispatcher(this._scope, page) })); for (const serviceWorker of (context as CRBrowserContext).serviceWorkers()) this._dispatchEvent('crServiceWorker', new WorkerDispatcher(this._scope, serviceWorker)); - context.on(ChromiumEvents.ChromiumBrowserContext.ServiceWorker, serviceWorker => this._dispatchEvent('crServiceWorker', { worker: new WorkerDispatcher(this._scope, serviceWorker) })); + context.on(CRBrowserContext.CREvents.ServiceWorker, serviceWorker => this._dispatchEvent('crServiceWorker', { worker: new WorkerDispatcher(this._scope, serviceWorker) })); } } diff --git a/src/rpc/server/browserDispatcher.ts b/src/rpc/server/browserDispatcher.ts index 1f686e3d85..d690b19946 100644 --- a/src/rpc/server/browserDispatcher.ts +++ b/src/rpc/server/browserDispatcher.ts @@ -15,7 +15,6 @@ */ import { Browser } from '../../browser'; -import { Events } from '../../events'; import * as channels from '../channels'; import { BrowserContextDispatcher } from './browserContextDispatcher'; import { CDPSessionDispatcher } from './cdpSessionDispatcher'; @@ -26,7 +25,7 @@ import { PageDispatcher } from './pageDispatcher'; export class BrowserDispatcher extends Dispatcher implements channels.BrowserChannel { constructor(scope: DispatcherScope, browser: Browser, guid?: string) { super(scope, browser, 'Browser', { version: browser.version() }, true, guid); - browser.on(Events.Browser.Disconnected, () => this._didClose()); + browser.on(Browser.Events.Disconnected, () => this._didClose()); } _didClose() { diff --git a/src/rpc/server/electronDispatcher.ts b/src/rpc/server/electronDispatcher.ts index a046b53d9c..190cfcf7ad 100644 --- a/src/rpc/server/electronDispatcher.ts +++ b/src/rpc/server/electronDispatcher.ts @@ -15,7 +15,7 @@ */ import { Dispatcher, DispatcherScope, lookupDispatcher } from './dispatcher'; -import { Electron, ElectronApplication, ElectronEvents, ElectronPage } from '../../server/electron'; +import { Electron, ElectronApplication, ElectronPage } from '../../server/electron'; import * as channels from '../channels'; import { BrowserContextDispatcher } from './browserContextDispatcher'; import { PageDispatcher } from './pageDispatcher'; @@ -37,11 +37,11 @@ export class ElectronApplicationDispatcher extends Dispatcher { + electronApplication.on(ElectronApplication.Events.Close, () => { this._dispatchEvent('close'); this._dispose(); }); - electronApplication.on(ElectronEvents.ElectronApplication.Window, (page: ElectronPage) => { + electronApplication.on(ElectronApplication.Events.Window, (page: ElectronPage) => { this._dispatchEvent('window', { page: lookupDispatcher(page), browserWindow: createHandle(this._scope, page.browserWindow), diff --git a/src/rpc/server/frameDispatcher.ts b/src/rpc/server/frameDispatcher.ts index fa0d04b4f9..c918bfc6bc 100644 --- a/src/rpc/server/frameDispatcher.ts +++ b/src/rpc/server/frameDispatcher.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Frame, kAddLifecycleEvent, kRemoveLifecycleEvent, kNavigationEvent, NavigationEvent } from '../../frames'; +import { Frame, NavigationEvent } from '../../frames'; import * as types from '../../types'; import * as channels from '../channels'; import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from './dispatcher'; @@ -38,13 +38,13 @@ export class FrameDispatcher extends Dispatcher { + frame.on(Frame.Events.AddLifecycle, (event: types.LifecycleEvent) => { this._dispatchEvent('loadstate', { add: event }); }); - frame._eventEmitter.on(kRemoveLifecycleEvent, (event: types.LifecycleEvent) => { + frame.on(Frame.Events.RemoveLifecycle, (event: types.LifecycleEvent) => { this._dispatchEvent('loadstate', { remove: event }); }); - frame._eventEmitter.on(kNavigationEvent, (event: NavigationEvent) => { + frame.on(Frame.Events.Navigation, (event: NavigationEvent) => { const params = { url: event.url, name: event.name, error: event.error ? event.error.message : undefined }; if (event.newDocument) (params as any).newDocument = { request: RequestDispatcher.fromNullable(this._scope, event.newDocument.request || null) }; diff --git a/src/rpc/server/pageDispatcher.ts b/src/rpc/server/pageDispatcher.ts index d23a402e64..1f83bcad3d 100644 --- a/src/rpc/server/pageDispatcher.ts +++ b/src/rpc/server/pageDispatcher.ts @@ -15,7 +15,6 @@ */ import { BrowserContext } from '../../browserContext'; -import { Events } from '../../events'; import { Frame } from '../../frames'; import { Request } from '../../network'; import { Page, Worker } from '../../page'; @@ -44,29 +43,29 @@ export class PageDispatcher extends Dispatcher i isClosed: page.isClosed() }); this._page = page; - page.on(Events.Page.Close, () => this._dispatchEvent('close')); - page.on(Events.Page.Console, message => this._dispatchEvent('console', { message: new ConsoleMessageDispatcher(this._scope, message) })); - page.on(Events.Page.Crash, () => this._dispatchEvent('crash')); - page.on(Events.Page.DOMContentLoaded, () => this._dispatchEvent('domcontentloaded')); - page.on(Events.Page.Dialog, dialog => this._dispatchEvent('dialog', { dialog: new DialogDispatcher(this._scope, dialog) })); - page.on(Events.Page.Download, dialog => this._dispatchEvent('download', { download: new DownloadDispatcher(this._scope, dialog) })); - this._page.on(Events.Page.FileChooser, (fileChooser: FileChooser) => this._dispatchEvent('fileChooser', { + page.on(Page.Events.Close, () => this._dispatchEvent('close')); + page.on(Page.Events.Console, message => this._dispatchEvent('console', { message: new ConsoleMessageDispatcher(this._scope, message) })); + page.on(Page.Events.Crash, () => this._dispatchEvent('crash')); + page.on(Page.Events.DOMContentLoaded, () => this._dispatchEvent('domcontentloaded')); + page.on(Page.Events.Dialog, dialog => this._dispatchEvent('dialog', { dialog: new DialogDispatcher(this._scope, dialog) })); + page.on(Page.Events.Download, dialog => this._dispatchEvent('download', { download: new DownloadDispatcher(this._scope, dialog) })); + this._page.on(Page.Events.FileChooser, (fileChooser: FileChooser) => this._dispatchEvent('fileChooser', { element: new ElementHandleDispatcher(this._scope, fileChooser.element()), isMultiple: fileChooser.isMultiple() })); - page.on(Events.Page.FrameAttached, frame => this._onFrameAttached(frame)); - page.on(Events.Page.FrameDetached, frame => this._onFrameDetached(frame)); - page.on(Events.Page.Load, () => this._dispatchEvent('load')); - page.on(Events.Page.PageError, error => this._dispatchEvent('pageError', { error: serializeError(error) })); - page.on(Events.Page.Popup, page => this._dispatchEvent('popup', { page: lookupDispatcher(page) })); - page.on(Events.Page.Request, request => this._dispatchEvent('request', { request: RequestDispatcher.from(this._scope, request) })); - page.on(Events.Page.RequestFailed, (request: Request) => this._dispatchEvent('requestFailed', { + page.on(Page.Events.FrameAttached, frame => this._onFrameAttached(frame)); + page.on(Page.Events.FrameDetached, frame => this._onFrameDetached(frame)); + page.on(Page.Events.Load, () => this._dispatchEvent('load')); + page.on(Page.Events.PageError, error => this._dispatchEvent('pageError', { error: serializeError(error) })); + page.on(Page.Events.Popup, page => this._dispatchEvent('popup', { page: lookupDispatcher(page) })); + page.on(Page.Events.Request, request => this._dispatchEvent('request', { request: RequestDispatcher.from(this._scope, request) })); + page.on(Page.Events.RequestFailed, (request: Request) => this._dispatchEvent('requestFailed', { request: RequestDispatcher.from(this._scope, request), failureText: request._failureText })); - page.on(Events.Page.RequestFinished, request => this._dispatchEvent('requestFinished', { request: RequestDispatcher.from(scope, request) })); - page.on(Events.Page.Response, response => this._dispatchEvent('response', { response: new ResponseDispatcher(this._scope, response) })); - page.on(Events.Page.Worker, worker => this._dispatchEvent('worker', { worker: new WorkerDispatcher(this._scope, worker) })); + page.on(Page.Events.RequestFinished, request => this._dispatchEvent('requestFinished', { request: RequestDispatcher.from(scope, request) })); + page.on(Page.Events.Response, response => this._dispatchEvent('response', { response: new ResponseDispatcher(this._scope, response) })); + page.on(Page.Events.Worker, worker => this._dispatchEvent('worker', { worker: new WorkerDispatcher(this._scope, worker) })); } async setDefaultNavigationTimeoutNoReply(params: channels.PageSetDefaultNavigationTimeoutNoReplyParams): Promise { @@ -232,7 +231,7 @@ export class WorkerDispatcher extends Dispatcher this._dispatchEvent('close')); + worker.on(Worker.Events.Close, () => this._dispatchEvent('close')); } async evaluateExpression(params: channels.WorkerEvaluateExpressionParams): Promise { diff --git a/src/server/electron.ts b/src/server/electron.ts index 7d03eee8c0..acad60e540 100644 --- a/src/server/electron.ts +++ b/src/server/electron.ts @@ -18,7 +18,6 @@ import * as path from 'path'; import { CRBrowser, CRBrowserContext } from '../chromium/crBrowser'; import { CRConnection, CRSession } from '../chromium/crConnection'; import { CRExecutionContext } from '../chromium/crExecutionContext'; -import { Events } from '../events'; import * as js from '../javascript'; import { Page } from '../page'; import { TimeoutSettings } from '../timeoutSettings'; @@ -42,19 +41,17 @@ export type ElectronLaunchOptionsBase = { timeout?: number, }; -export const ElectronEvents = { - ElectronApplication: { - Close: 'close', - Window: 'window', - } -}; - export interface ElectronPage extends Page { browserWindow: js.JSHandle; _browserWindowId: number; } export class ElectronApplication extends EventEmitter { + static Events = { + Close: 'close', + Window: 'window', + }; + private _browserContext: CRBrowserContext; private _nodeConnection: CRConnection; private _nodeSession: CRSession; @@ -67,11 +64,11 @@ export class ElectronApplication extends EventEmitter { constructor(browser: CRBrowser, nodeConnection: CRConnection) { super(); this._browserContext = browser._defaultContext as CRBrowserContext; - this._browserContext.on(Events.BrowserContext.Close, () => { + this._browserContext.on(BrowserContext.Events.Close, () => { // Emit application closed after context closed. - Promise.resolve().then(() => this.emit(ElectronEvents.ElectronApplication.Close)); + Promise.resolve().then(() => this.emit(ElectronApplication.Events.Close)); }); - this._browserContext.on(Events.BrowserContext.Page, event => this._onPage(event)); + this._browserContext.on(BrowserContext.Events.Page, event => this._onPage(event)); this._nodeConnection = nodeConnection; this._nodeSession = nodeConnection.rootSession; } @@ -85,13 +82,13 @@ export class ElectronApplication extends EventEmitter { return; page.browserWindow = handle; page._browserWindowId = windowId; - page.on(Events.Page.Close, () => { + page.on(Page.Events.Close, () => { page.browserWindow.dispose(); this._windows.delete(page); }); this._windows.add(page); await page.mainFrame().waitForLoadState('domcontentloaded').catch(e => {}); // can happen after detach - this.emit(ElectronEvents.ElectronApplication.Window, page); + this.emit(ElectronApplication.Events.Window, page); } async newBrowserWindow(options: any): Promise { @@ -106,7 +103,7 @@ export class ElectronApplication extends EventEmitter { return page; } - return await this._waitForEvent(ElectronEvents.ElectronApplication.Window, (page: ElectronPage) => page._browserWindowId === windowId); + return await this._waitForEvent(ElectronApplication.Events.Window, (page: ElectronPage) => page._browserWindowId === windowId); } context(): BrowserContext { @@ -114,7 +111,7 @@ export class ElectronApplication extends EventEmitter { } async close() { - const closed = this._waitForEvent(ElectronEvents.ElectronApplication.Close); + const closed = this._waitForEvent(ElectronApplication.Events.Close); await this._nodeElectronHandle!.evaluate(({ app }) => app.quit()); this._nodeConnection.close(); await closed; @@ -122,7 +119,7 @@ export class ElectronApplication extends EventEmitter { private async _waitForEvent(event: string, predicate?: Function): Promise { const progressController = new ProgressController(this._timeoutSettings.timeout({})); - if (event !== ElectronEvents.ElectronApplication.Close) + if (event !== ElectronApplication.Events.Close) this._browserContext._closePromise.then(error => progressController.abort(error)); return progressController.run(progress => helper.waitForEvent(progress, this, event, predicate).promise); } diff --git a/src/webkit/wkBrowser.ts b/src/webkit/wkBrowser.ts index fb13858354..6b307c5ad1 100644 --- a/src/webkit/wkBrowser.ts +++ b/src/webkit/wkBrowser.ts @@ -17,7 +17,6 @@ import { Browser, BrowserOptions } from '../browser'; import { assertBrowserContextIsNotOwned, BrowserContext, validateBrowserContextOptions, verifyGeolocation } from '../browserContext'; -import { Events } from '../events'; import { helper, RegisteredListener, assert } from '../helper'; import * as network from '../network'; import { Page, PageBinding } from '../page'; @@ -150,13 +149,13 @@ export class WKBrowser extends Browser { const page = wkPage._page; if (pageOrError instanceof Error) page._setIsError(); - context!.emit(Events.BrowserContext.Page, page); + context!.emit(BrowserContext.Events.Page, page); if (!opener) return; await opener.pageOrError(); const openerPage = opener._page; if (!openerPage.isClosed()) - openerPage.emit(Events.Page.Popup, page); + openerPage.emit(Page.Events.Popup, page); }); } diff --git a/src/webkit/wkPage.ts b/src/webkit/wkPage.ts index bcfd7c23e7..294fbff6a9 100644 --- a/src/webkit/wkPage.ts +++ b/src/webkit/wkPage.ts @@ -15,13 +15,12 @@ * limitations under the License. */ -import { Screencast } from '../browserContext'; +import { Screencast, BrowserContext } from '../browserContext'; import * as frames from '../frames'; import { helper, RegisteredListener, assert, debugAssert } from '../helper'; import * as dom from '../dom'; import * as network from '../network'; import { WKSession } from './wkConnection'; -import { Events } from '../events'; import { WKExecutionContext } from './wkExecutionContext'; import { WKInterceptableRequest } from './wkInterceptableRequest'; import { WKWorkers } from './wkWorkers'; @@ -81,7 +80,7 @@ export class WKPage implements PageDelegate { this._workers = new WKWorkers(this._page); this._session = undefined as any as WKSession; this._browserContext = browserContext; - this._page.on(Events.Page.FrameDetached, (frame: frames.Frame) => this._removeContextsForFrame(frame, false)); + this._page.on(Page.Events.FrameDetached, (frame: frames.Frame) => this._removeContextsForFrame(frame, false)); this._eventListeners = [ helper.addEventListener(this._pageProxySession, 'Target.targetCreated', this._onTargetCreated.bind(this)), helper.addEventListener(this._pageProxySession, 'Target.targetDestroyed', this._onTargetDestroyed.bind(this)), @@ -474,7 +473,7 @@ export class WKPage implements PageDelegate { } else { error.stack = ''; } - this._page.emit(Events.Page.PageError, error); + this._page.emit(Page.Events.PageError, error); return; } @@ -524,7 +523,7 @@ export class WKPage implements PageDelegate { } _onDialog(event: Protocol.Dialog.javascriptDialogOpeningPayload) { - this._page.emit(Events.Page.Dialog, new dialog.Dialog( + this._page.emit(Page.Events.Dialog, new dialog.Dialog( event.type as dialog.DialogType, event.message, async (accept: boolean, promptText?: string) => { @@ -718,7 +717,7 @@ export class WKPage implements PageDelegate { height: options.height, scale: options.scale, }); - this._browserContext.emit(Events.BrowserContext.ScreencastStarted, new Screencast(options.outputFile, this._initializedPage!)); + this._browserContext.emit(BrowserContext.Events.ScreencastStarted, new Screencast(options.outputFile, this._initializedPage!)); } catch (e) { this._recordingVideoFile = null; throw e; @@ -731,7 +730,7 @@ export class WKPage implements PageDelegate { const fileName = this._recordingVideoFile; this._recordingVideoFile = null; await this._pageProxySession.send('Screencast.stopVideoRecording'); - this._browserContext.emit(Events.BrowserContext.ScreencastStopped, new Screencast(fileName, this._initializedPage!)); + this._browserContext.emit(BrowserContext.Events.ScreencastStopped, new Screencast(fileName, this._initializedPage!)); } async takeScreenshot(format: string, documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined): Promise { diff --git a/test/coverage.js b/test/coverage.js index 7ab1a88a6d..303699b440 100644 --- a/test/coverage.js +++ b/test/coverage.js @@ -61,32 +61,11 @@ function traceAPICoverage(apiCoverage, api, events) { * @param {string} browserName */ function apiForBrowser(browserName) { - const BROWSER_CONFIGS = [ - { - name: 'Firefox', - events: require('../lib/events').Events, - }, - { - name: 'WebKit', - events: require('../lib/events').Events, - }, - { - name: 'Chromium', - events: { - ...require('../lib/events').Events, - ...require('../lib/chromium/events').Events, - } - }, - ]; - const browserConfig = BROWSER_CONFIGS.find(config => config.name.toLowerCase() === browserName); - const events = browserConfig.events; - // TODO: we should rethink our api.ts approach to ensure coverage and async stacks. - const api = { - ...require('../lib/rpc/client/api'), - }; - + const events = require('../lib/rpc/client/events').Events; + const api = require('../lib/rpc/client/api'); + const otherBrowsers = ['chromium', 'webkit', 'firefox'].filter(name => name.toLowerCase() !== browserName.toLowerCase()); const filteredKeys = Object.keys(api).filter(apiName => { - return !BROWSER_CONFIGS.some(config => apiName.startsWith(config.name)) || apiName.startsWith(browserConfig.name); + return !otherBrowsers.some(otherName => apiName.toLowerCase().startsWith(otherName)); }); const filteredAPI = {}; for (const key of filteredKeys)