diff --git a/src/cli/driver.ts b/src/cli/driver.ts index 9edb855c53..936eb153c0 100644 --- a/src/cli/driver.ts +++ b/src/cli/driver.ts @@ -25,7 +25,7 @@ import { PlaywrightDispatcher } from '../dispatchers/playwrightDispatcher'; import { Transport } from '../protocol/transport'; import { PlaywrightServer } from '../remote/playwrightServer'; import { createPlaywright } from '../server/playwright'; -import { gracefullyCloseAll } from '../server/processLauncher'; +import { gracefullyCloseAll } from '../utils/processLauncher'; export function printApiJson() { // Note: this file is generated by build-playwright-driver.sh diff --git a/src/remote/playwrightServer.ts b/src/remote/playwrightServer.ts index a6e3335614..529f5b65f5 100644 --- a/src/remote/playwrightServer.ts +++ b/src/remote/playwrightServer.ts @@ -20,7 +20,7 @@ import * as ws from 'ws'; import { DispatcherConnection, DispatcherScope } from '../dispatchers/dispatcher'; import { PlaywrightDispatcher } from '../dispatchers/playwrightDispatcher'; import { createPlaywright } from '../server/playwright'; -import { gracefullyCloseAll } from '../server/processLauncher'; +import { gracefullyCloseAll } from '../utils/processLauncher'; const debugLog = debug('pw:server'); diff --git a/src/server/browserType.ts b/src/server/browserType.ts index 54e673b7ca..6d4c2792fe 100644 --- a/src/server/browserType.ts +++ b/src/server/browserType.ts @@ -21,7 +21,7 @@ import { BrowserContext, normalizeProxySettings, validateBrowserContextOptions } import * as registry from '../utils/registry'; import { ConnectionTransport, WebSocketTransport } from './transport'; import { BrowserOptions, Browser, BrowserProcess, PlaywrightOptions } from './browser'; -import { launchProcess, Env, envArrayToObject } from './processLauncher'; +import { launchProcess, Env, envArrayToObject } from '../utils/processLauncher'; import { PipeTransport } from './pipeTransport'; import { Progress, ProgressController } from './progress'; import * as types from './types'; diff --git a/src/server/chromium/chromium.ts b/src/server/chromium/chromium.ts index e81b2a57c6..f32645d3f7 100644 --- a/src/server/chromium/chromium.ts +++ b/src/server/chromium/chromium.ts @@ -19,7 +19,7 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; import { CRBrowser } from './crBrowser'; -import { Env } from '../processLauncher'; +import { Env } from '../../utils/processLauncher'; import { kBrowserCloseMessageId } from './crConnection'; import { rewriteErrorMessage } from '../../utils/stackTrace'; import { BrowserType } from '../browserType'; diff --git a/src/server/chromium/crCoverage.ts b/src/server/chromium/crCoverage.ts index 28e12fcd0f..17d4268932 100644 --- a/src/server/chromium/crCoverage.ts +++ b/src/server/chromium/crCoverage.ts @@ -16,7 +16,7 @@ */ import { CRSession } from './crConnection'; -import { helper, RegisteredListener } from '../helper'; +import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; import { Protocol } from './protocol'; import * as types from '../types'; import { assert } from '../../utils/utils'; @@ -77,9 +77,9 @@ class JSCoverage { this._scriptIds.clear(); this._scriptSources.clear(); this._eventListeners = [ - helper.addEventListener(this._client, 'Debugger.scriptParsed', this._onScriptParsed.bind(this)), - helper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this)), - helper.addEventListener(this._client, 'Debugger.paused', this._onDebuggerPaused.bind(this)), + eventsHelper.addEventListener(this._client, 'Debugger.scriptParsed', this._onScriptParsed.bind(this)), + eventsHelper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this)), + eventsHelper.addEventListener(this._client, 'Debugger.paused', this._onDebuggerPaused.bind(this)), ]; await Promise.all([ this._client.send('Profiler.enable'), @@ -120,7 +120,7 @@ class JSCoverage { this._client.send('Profiler.disable'), this._client.send('Debugger.disable'), ] as const); - helper.removeEventListeners(this._eventListeners); + eventsHelper.removeEventListeners(this._eventListeners); const coverage: types.JSCoverageEntry[] = []; for (const entry of profileResponse.result) { @@ -163,8 +163,8 @@ class CSSCoverage { this._stylesheetURLs.clear(); this._stylesheetSources.clear(); this._eventListeners = [ - helper.addEventListener(this._client, 'CSS.styleSheetAdded', this._onStyleSheet.bind(this)), - helper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this)), + eventsHelper.addEventListener(this._client, 'CSS.styleSheetAdded', this._onStyleSheet.bind(this)), + eventsHelper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this)), ]; await Promise.all([ this._client.send('DOM.enable'), @@ -201,7 +201,7 @@ class CSSCoverage { this._client.send('CSS.disable'), this._client.send('DOM.disable'), ]); - helper.removeEventListeners(this._eventListeners); + eventsHelper.removeEventListeners(this._eventListeners); // aggregate by styleSheetId const styleSheetIdToCoverage = new Map(); diff --git a/src/server/chromium/crNetworkManager.ts b/src/server/chromium/crNetworkManager.ts index 835d644654..8a777a5601 100644 --- a/src/server/chromium/crNetworkManager.ts +++ b/src/server/chromium/crNetworkManager.ts @@ -17,7 +17,8 @@ import { CRSession } from './crConnection'; import { Page } from '../page'; -import { helper, RegisteredListener } from '../helper'; +import { helper } from '../helper'; +import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; import { Protocol } from './protocol'; import * as network from '../network'; import * as frames from '../frames'; @@ -48,20 +49,20 @@ export class CRNetworkManager { instrumentNetworkEvents(session: CRSession, workerFrame?: frames.Frame): RegisteredListener[] { return [ - helper.addEventListener(session, 'Fetch.requestPaused', this._onRequestPaused.bind(this, workerFrame)), - helper.addEventListener(session, 'Fetch.authRequired', this._onAuthRequired.bind(this)), - helper.addEventListener(session, 'Network.requestWillBeSent', this._onRequestWillBeSent.bind(this, workerFrame)), - helper.addEventListener(session, 'Network.requestWillBeSentExtraInfo', this._onRequestWillBeSentExtraInfo.bind(this)), - helper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)), - helper.addEventListener(session, 'Network.loadingFinished', this._onLoadingFinished.bind(this)), - helper.addEventListener(session, 'Network.loadingFailed', this._onLoadingFailed.bind(this)), - helper.addEventListener(session, 'Network.webSocketCreated', e => this._page._frameManager.onWebSocketCreated(e.requestId, e.url)), - helper.addEventListener(session, 'Network.webSocketWillSendHandshakeRequest', e => this._page._frameManager.onWebSocketRequest(e.requestId)), - helper.addEventListener(session, 'Network.webSocketHandshakeResponseReceived', e => this._page._frameManager.onWebSocketResponse(e.requestId, e.response.status, e.response.statusText)), - helper.addEventListener(session, 'Network.webSocketFrameSent', e => e.response.payloadData && this._page._frameManager.onWebSocketFrameSent(e.requestId, e.response.opcode, e.response.payloadData)), - helper.addEventListener(session, 'Network.webSocketFrameReceived', e => e.response.payloadData && this._page._frameManager.webSocketFrameReceived(e.requestId, e.response.opcode, e.response.payloadData)), - helper.addEventListener(session, 'Network.webSocketClosed', e => this._page._frameManager.webSocketClosed(e.requestId)), - helper.addEventListener(session, 'Network.webSocketFrameError', e => this._page._frameManager.webSocketError(e.requestId, e.errorMessage)), + eventsHelper.addEventListener(session, 'Fetch.requestPaused', this._onRequestPaused.bind(this, workerFrame)), + eventsHelper.addEventListener(session, 'Fetch.authRequired', this._onAuthRequired.bind(this)), + eventsHelper.addEventListener(session, 'Network.requestWillBeSent', this._onRequestWillBeSent.bind(this, workerFrame)), + eventsHelper.addEventListener(session, 'Network.requestWillBeSentExtraInfo', this._onRequestWillBeSentExtraInfo.bind(this)), + eventsHelper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)), + eventsHelper.addEventListener(session, 'Network.loadingFinished', this._onLoadingFinished.bind(this)), + eventsHelper.addEventListener(session, 'Network.loadingFailed', this._onLoadingFailed.bind(this)), + eventsHelper.addEventListener(session, 'Network.webSocketCreated', e => this._page._frameManager.onWebSocketCreated(e.requestId, e.url)), + eventsHelper.addEventListener(session, 'Network.webSocketWillSendHandshakeRequest', e => this._page._frameManager.onWebSocketRequest(e.requestId)), + eventsHelper.addEventListener(session, 'Network.webSocketHandshakeResponseReceived', e => this._page._frameManager.onWebSocketResponse(e.requestId, e.response.status, e.response.statusText)), + eventsHelper.addEventListener(session, 'Network.webSocketFrameSent', e => e.response.payloadData && this._page._frameManager.onWebSocketFrameSent(e.requestId, e.response.opcode, e.response.payloadData)), + eventsHelper.addEventListener(session, 'Network.webSocketFrameReceived', e => e.response.payloadData && this._page._frameManager.webSocketFrameReceived(e.requestId, e.response.opcode, e.response.payloadData)), + eventsHelper.addEventListener(session, 'Network.webSocketClosed', e => this._page._frameManager.webSocketClosed(e.requestId)), + eventsHelper.addEventListener(session, 'Network.webSocketFrameError', e => this._page._frameManager.webSocketError(e.requestId, e.errorMessage)), ]; } @@ -70,7 +71,7 @@ export class CRNetworkManager { } dispose() { - helper.removeEventListeners(this._eventListeners); + eventsHelper.removeEventListeners(this._eventListeners); } async authenticate(credentials: types.Credentials | null) { diff --git a/src/server/chromium/crPage.ts b/src/server/chromium/crPage.ts index c480eb3ac5..9eb076a707 100644 --- a/src/server/chromium/crPage.ts +++ b/src/server/chromium/crPage.ts @@ -17,7 +17,8 @@ import * as dom from '../dom'; import * as frames from '../frames'; -import { helper, RegisteredListener } from '../helper'; +import { helper } from '../helper'; +import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; import * as network from '../network'; import { CRSession, CRConnection, CRSessionEvents } from './crConnection'; import { CRExecutionContext } from './crExecutionContext'; @@ -397,31 +398,31 @@ class FrameSession { private _addRendererListeners() { this._eventListeners.push(...[ - helper.addEventListener(this._client, 'Log.entryAdded', event => this._onLogEntryAdded(event)), - helper.addEventListener(this._client, 'Page.fileChooserOpened', event => this._onFileChooserOpened(event)), - helper.addEventListener(this._client, 'Page.frameAttached', event => this._onFrameAttached(event.frameId, event.parentFrameId)), - helper.addEventListener(this._client, 'Page.frameDetached', event => this._onFrameDetached(event.frameId, event.reason)), - helper.addEventListener(this._client, 'Page.frameNavigated', event => this._onFrameNavigated(event.frame, false)), - helper.addEventListener(this._client, 'Page.frameRequestedNavigation', event => this._onFrameRequestedNavigation(event)), - helper.addEventListener(this._client, 'Page.frameStoppedLoading', event => this._onFrameStoppedLoading(event.frameId)), - helper.addEventListener(this._client, 'Page.javascriptDialogOpening', event => this._onDialog(event)), - helper.addEventListener(this._client, 'Page.navigatedWithinDocument', event => this._onFrameNavigatedWithinDocument(event.frameId, event.url)), - helper.addEventListener(this._client, 'Runtime.bindingCalled', event => this._onBindingCalled(event)), - helper.addEventListener(this._client, 'Runtime.consoleAPICalled', event => this._onConsoleAPI(event)), - helper.addEventListener(this._client, 'Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails)), - helper.addEventListener(this._client, 'Runtime.executionContextCreated', event => this._onExecutionContextCreated(event.context)), - helper.addEventListener(this._client, 'Runtime.executionContextDestroyed', event => this._onExecutionContextDestroyed(event.executionContextId)), - helper.addEventListener(this._client, 'Runtime.executionContextsCleared', event => this._onExecutionContextsCleared()), - helper.addEventListener(this._client, 'Target.attachedToTarget', event => this._onAttachedToTarget(event)), - helper.addEventListener(this._client, 'Target.detachedFromTarget', event => this._onDetachedFromTarget(event)), + eventsHelper.addEventListener(this._client, 'Log.entryAdded', event => this._onLogEntryAdded(event)), + eventsHelper.addEventListener(this._client, 'Page.fileChooserOpened', event => this._onFileChooserOpened(event)), + eventsHelper.addEventListener(this._client, 'Page.frameAttached', event => this._onFrameAttached(event.frameId, event.parentFrameId)), + eventsHelper.addEventListener(this._client, 'Page.frameDetached', event => this._onFrameDetached(event.frameId, event.reason)), + eventsHelper.addEventListener(this._client, 'Page.frameNavigated', event => this._onFrameNavigated(event.frame, false)), + eventsHelper.addEventListener(this._client, 'Page.frameRequestedNavigation', event => this._onFrameRequestedNavigation(event)), + eventsHelper.addEventListener(this._client, 'Page.frameStoppedLoading', event => this._onFrameStoppedLoading(event.frameId)), + eventsHelper.addEventListener(this._client, 'Page.javascriptDialogOpening', event => this._onDialog(event)), + eventsHelper.addEventListener(this._client, 'Page.navigatedWithinDocument', event => this._onFrameNavigatedWithinDocument(event.frameId, event.url)), + eventsHelper.addEventListener(this._client, 'Runtime.bindingCalled', event => this._onBindingCalled(event)), + eventsHelper.addEventListener(this._client, 'Runtime.consoleAPICalled', event => this._onConsoleAPI(event)), + eventsHelper.addEventListener(this._client, 'Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails)), + eventsHelper.addEventListener(this._client, 'Runtime.executionContextCreated', event => this._onExecutionContextCreated(event.context)), + eventsHelper.addEventListener(this._client, 'Runtime.executionContextDestroyed', event => this._onExecutionContextDestroyed(event.executionContextId)), + eventsHelper.addEventListener(this._client, 'Runtime.executionContextsCleared', event => this._onExecutionContextsCleared()), + eventsHelper.addEventListener(this._client, 'Target.attachedToTarget', event => this._onAttachedToTarget(event)), + eventsHelper.addEventListener(this._client, 'Target.detachedFromTarget', event => this._onDetachedFromTarget(event)), ]); } private _addBrowserListeners() { this._eventListeners.push(...[ - helper.addEventListener(this._client, 'Inspector.targetCrashed', event => this._onTargetCrashed()), - helper.addEventListener(this._client, 'Page.screencastFrame', event => this._onScreencastFrame(event)), - helper.addEventListener(this._client, 'Page.windowOpen', event => this._onWindowOpen(event)), + eventsHelper.addEventListener(this._client, 'Inspector.targetCrashed', event => this._onTargetCrashed()), + eventsHelper.addEventListener(this._client, 'Page.screencastFrame', event => this._onScreencastFrame(event)), + eventsHelper.addEventListener(this._client, 'Page.windowOpen', event => this._onWindowOpen(event)), ]); } @@ -482,11 +483,11 @@ class FrameSession { // hence we are going to get more lifecycle updates after the actual navigation has // started (even if the target url is about:blank). lifecycleEventsEnabled.catch(e => {}).then(() => { - this._eventListeners.push(helper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event))); + this._eventListeners.push(eventsHelper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event))); }); } else { this._firstNonInitialNavigationCommittedFulfill(); - this._eventListeners.push(helper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event))); + this._eventListeners.push(eventsHelper.addEventListener(this._client, 'Page.lifecycleEvent', event => this._onLifecycleEvent(event))); } }), this._client.send('Log.enable', {}), @@ -538,7 +539,7 @@ class FrameSession { } dispose() { - helper.removeEventListeners(this._eventListeners); + eventsHelper.removeEventListeners(this._eventListeners); this._networkManager.dispose(); this._crPage._sessions.delete(this._targetId); } diff --git a/src/server/chromium/videoRecorder.ts b/src/server/chromium/videoRecorder.ts index 485c7accbd..d07417caa5 100644 --- a/src/server/chromium/videoRecorder.ts +++ b/src/server/chromium/videoRecorder.ts @@ -17,7 +17,7 @@ import { ChildProcess } from 'child_process'; import { assert, monotonicTime } from '../../utils/utils'; import { Page } from '../page'; -import { launchProcess } from '../processLauncher'; +import { launchProcess } from '../../utils/processLauncher'; import { Progress, ProgressController } from '../progress'; import { internalCallMetadata } from '../instrumentation'; import * as types from '../types'; diff --git a/src/server/electron/electron.ts b/src/server/electron/electron.ts index 09f8b3c894..54e87294c3 100644 --- a/src/server/electron/electron.ts +++ b/src/server/electron/electron.ts @@ -24,11 +24,12 @@ import * as js from '../javascript'; import { Page } from '../page'; import { TimeoutSettings } from '../../utils/timeoutSettings'; import { WebSocketTransport } from '../transport'; -import { launchProcess, envArrayToObject } from '../processLauncher'; +import { launchProcess, envArrayToObject } from '../../utils/processLauncher'; import { BrowserContext } from '../browserContext'; import type {BrowserWindow} from 'electron'; import { Progress, ProgressController } from '../progress'; import { helper } from '../helper'; +import { eventsHelper } from '../../utils/eventsHelper'; import { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser'; import * as childProcess from 'child_process'; import * as readline from 'readline'; @@ -196,11 +197,11 @@ function waitForLine(progress: Progress, process: childProcess.ChildProcess, reg const rl = readline.createInterface({ input: process.stderr }); const failError = new Error('Process failed to launch!'); const listeners = [ - helper.addEventListener(rl, 'line', onLine), - helper.addEventListener(rl, 'close', reject.bind(null, failError)), - helper.addEventListener(process, 'exit', reject.bind(null, failError)), + eventsHelper.addEventListener(rl, 'line', onLine), + eventsHelper.addEventListener(rl, 'close', reject.bind(null, failError)), + eventsHelper.addEventListener(process, 'exit', reject.bind(null, failError)), // It is Ok to remove error handler because we did not create process and there is another listener. - helper.addEventListener(process, 'error', reject.bind(null, failError)) + eventsHelper.addEventListener(process, 'error', reject.bind(null, failError)) ]; progress.cleanupWhenAborted(cleanup); @@ -214,7 +215,7 @@ function waitForLine(progress: Progress, process: childProcess.ChildProcess, reg } function cleanup() { - helper.removeEventListeners(listeners); + eventsHelper.removeEventListeners(listeners); } }); } diff --git a/src/server/firefox/ffNetworkManager.ts b/src/server/firefox/ffNetworkManager.ts index ab2ad37fa9..2e6d2d01d0 100644 --- a/src/server/firefox/ffNetworkManager.ts +++ b/src/server/firefox/ffNetworkManager.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { helper, RegisteredListener } from '../helper'; +import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; import { FFSession } from './ffConnection'; import { Page } from '../page'; import * as network from '../network'; @@ -37,15 +37,15 @@ export class FFNetworkManager { this._page = page; this._eventListeners = [ - helper.addEventListener(session, 'Network.requestWillBeSent', this._onRequestWillBeSent.bind(this)), - helper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)), - helper.addEventListener(session, 'Network.requestFinished', this._onRequestFinished.bind(this)), - helper.addEventListener(session, 'Network.requestFailed', this._onRequestFailed.bind(this)), + eventsHelper.addEventListener(session, 'Network.requestWillBeSent', this._onRequestWillBeSent.bind(this)), + eventsHelper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)), + eventsHelper.addEventListener(session, 'Network.requestFinished', this._onRequestFinished.bind(this)), + eventsHelper.addEventListener(session, 'Network.requestFailed', this._onRequestFailed.bind(this)), ]; } dispose() { - helper.removeEventListeners(this._eventListeners); + eventsHelper.removeEventListeners(this._eventListeners); } async setRequestInterception(enabled: boolean) { diff --git a/src/server/firefox/ffPage.ts b/src/server/firefox/ffPage.ts index 31ab4b0f09..825f498ab9 100644 --- a/src/server/firefox/ffPage.ts +++ b/src/server/firefox/ffPage.ts @@ -18,7 +18,7 @@ import * as dialog from '../dialog'; import * as dom from '../dom'; import * as frames from '../frames'; -import { helper, RegisteredListener } from '../helper'; +import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; import { assert } from '../../utils/utils'; import { Page, PageBinding, PageDelegate, Worker } from '../page'; import * as types from '../types'; @@ -67,32 +67,32 @@ export class FFPage implements PageDelegate { 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)), - helper.addEventListener(this._session, 'Page.frameAttached', this._onFrameAttached.bind(this)), - helper.addEventListener(this._session, 'Page.frameDetached', this._onFrameDetached.bind(this)), - helper.addEventListener(this._session, 'Page.navigationAborted', this._onNavigationAborted.bind(this)), - helper.addEventListener(this._session, 'Page.navigationCommitted', this._onNavigationCommitted.bind(this)), - helper.addEventListener(this._session, 'Page.navigationStarted', this._onNavigationStarted.bind(this)), - helper.addEventListener(this._session, 'Page.sameDocumentNavigation', this._onSameDocumentNavigation.bind(this)), - helper.addEventListener(this._session, 'Runtime.executionContextCreated', this._onExecutionContextCreated.bind(this)), - helper.addEventListener(this._session, 'Runtime.executionContextDestroyed', this._onExecutionContextDestroyed.bind(this)), - helper.addEventListener(this._session, 'Page.linkClicked', event => this._onLinkClicked(event.phase)), - helper.addEventListener(this._session, 'Page.uncaughtError', this._onUncaughtError.bind(this)), - helper.addEventListener(this._session, 'Runtime.console', this._onConsole.bind(this)), - helper.addEventListener(this._session, 'Page.dialogOpened', this._onDialogOpened.bind(this)), - helper.addEventListener(this._session, 'Page.bindingCalled', this._onBindingCalled.bind(this)), - helper.addEventListener(this._session, 'Page.fileChooserOpened', this._onFileChooserOpened.bind(this)), - helper.addEventListener(this._session, 'Page.workerCreated', this._onWorkerCreated.bind(this)), - helper.addEventListener(this._session, 'Page.workerDestroyed', this._onWorkerDestroyed.bind(this)), - helper.addEventListener(this._session, 'Page.dispatchMessageFromWorker', this._onDispatchMessageFromWorker.bind(this)), - helper.addEventListener(this._session, 'Page.crashed', this._onCrashed.bind(this)), - helper.addEventListener(this._session, 'Page.videoRecordingStarted', this._onVideoRecordingStarted.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.eventFired', this._onEventFired.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.frameAttached', this._onFrameAttached.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.frameDetached', this._onFrameDetached.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.navigationAborted', this._onNavigationAborted.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.navigationCommitted', this._onNavigationCommitted.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.navigationStarted', this._onNavigationStarted.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.sameDocumentNavigation', this._onSameDocumentNavigation.bind(this)), + eventsHelper.addEventListener(this._session, 'Runtime.executionContextCreated', this._onExecutionContextCreated.bind(this)), + eventsHelper.addEventListener(this._session, 'Runtime.executionContextDestroyed', this._onExecutionContextDestroyed.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.linkClicked', event => this._onLinkClicked(event.phase)), + eventsHelper.addEventListener(this._session, 'Page.uncaughtError', this._onUncaughtError.bind(this)), + eventsHelper.addEventListener(this._session, 'Runtime.console', this._onConsole.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.dialogOpened', this._onDialogOpened.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.bindingCalled', this._onBindingCalled.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.fileChooserOpened', this._onFileChooserOpened.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.workerCreated', this._onWorkerCreated.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.workerDestroyed', this._onWorkerDestroyed.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.dispatchMessageFromWorker', this._onDispatchMessageFromWorker.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.crashed', this._onCrashed.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.videoRecordingStarted', this._onVideoRecordingStarted.bind(this)), - helper.addEventListener(this._session, 'Page.webSocketCreated', this._onWebSocketCreated.bind(this)), - helper.addEventListener(this._session, 'Page.webSocketClosed', this._onWebSocketClosed.bind(this)), - helper.addEventListener(this._session, 'Page.webSocketFrameReceived', this._onWebSocketFrameReceived.bind(this)), - helper.addEventListener(this._session, 'Page.webSocketFrameSent', this._onWebSocketFrameSent.bind(this)), - helper.addEventListener(this._session, 'Page.screencastFrame', this._onScreencastFrame.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.webSocketCreated', this._onWebSocketCreated.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.webSocketClosed', this._onWebSocketClosed.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.webSocketFrameReceived', this._onWebSocketFrameReceived.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.webSocketFrameSent', this._onWebSocketFrameSent.bind(this)), + eventsHelper.addEventListener(this._session, 'Page.screencastFrame', this._onScreencastFrame.bind(this)), ]; this._pagePromise = new Promise(f => this._pageCallback = f); @@ -324,7 +324,7 @@ export class FFPage implements PageDelegate { didClose() { this._session.dispose(); - helper.removeEventListeners(this._eventListeners); + eventsHelper.removeEventListeners(this._eventListeners); this._networkManager.dispose(); this._page._didClose(); } diff --git a/src/server/firefox/firefox.ts b/src/server/firefox/firefox.ts index 183e09ff34..3a9cf96f5f 100644 --- a/src/server/firefox/firefox.ts +++ b/src/server/firefox/firefox.ts @@ -22,7 +22,7 @@ import { assert } from '../../utils/utils'; import { FFBrowser } from './ffBrowser'; import { kBrowserCloseMessageId } from './ffConnection'; import { BrowserType } from '../browserType'; -import { Env } from '../processLauncher'; +import { Env } from '../../utils/processLauncher'; import { ConnectionTransport } from '../transport'; import { BrowserOptions, PlaywrightOptions } from '../browser'; import * as types from '../types'; diff --git a/src/server/frames.ts b/src/server/frames.ts index 5b3e32e5d3..36a4bfc9e0 100644 --- a/src/server/frames.ts +++ b/src/server/frames.ts @@ -18,7 +18,8 @@ import * as channels from '../protocol/channels'; import { ConsoleMessage } from './console'; import * as dom from './dom'; -import { helper, RegisteredListener } from './helper'; +import { helper } from './helper'; +import { eventsHelper, RegisteredListener } from '../utils/eventsHelper'; import * as js from './javascript'; import * as network from './network'; import { Page } from './page'; @@ -916,7 +917,7 @@ export class Frame extends SdkObject { resolve(); }); const errorPromise = new Promise(resolve => { - listeners.push(helper.addEventListener(this._page, Page.Events.Console, (message: ConsoleMessage) => { + listeners.push(eventsHelper.addEventListener(this._page, Page.Events.Console, (message: ConsoleMessage) => { if (message.type() === 'error' && message.text().includes('Content Security Policy')) { cspMessage = message; resolve(); @@ -924,7 +925,7 @@ export class Frame extends SdkObject { })); }); await Promise.race([actionPromise, errorPromise]); - helper.removeEventListeners(listeners); + eventsHelper.removeEventListeners(listeners); if (cspMessage) throw new Error(cspMessage.text()); if (error) diff --git a/src/server/helper.ts b/src/server/helper.ts index fb34204536..6341d18ae0 100644 --- a/src/server/helper.ts +++ b/src/server/helper.ts @@ -19,32 +19,9 @@ import { EventEmitter } from 'events'; import * as types from './types'; import { Progress } from './progress'; import { debugLogger } from '../utils/debugLogger'; - -export type RegisteredListener = { - emitter: EventEmitter; - eventName: (string | symbol); - handler: (...args: any[]) => void; -}; +import { eventsHelper, RegisteredListener } from '../utils/eventsHelper'; class Helper { - static addEventListener( - emitter: EventEmitter, - eventName: (string | symbol), - handler: (...args: any[]) => void): RegisteredListener { - emitter.on(eventName, handler); - return { emitter, eventName, handler }; - } - - static removeEventListeners(listeners: Array<{ - emitter: EventEmitter; - eventName: (string | symbol); - handler: (...args: any[]) => void; - }>) { - for (const listener of listeners) - listener.emitter.removeListener(listener.eventName, listener.handler); - listeners.splice(0, listeners.length); - } - static completeUserURL(urlString: string): string { if (urlString.startsWith('localhost') || urlString.startsWith('127.0.0.1')) urlString = 'http://' + urlString; @@ -76,19 +53,19 @@ class Helper { static waitForEvent(progress: Progress | null, emitter: EventEmitter, event: string | symbol, predicate?: Function): { promise: Promise, dispose: () => void } { const listeners: RegisteredListener[] = []; const promise = new Promise((resolve, reject) => { - listeners.push(helper.addEventListener(emitter, event, eventArg => { + listeners.push(eventsHelper.addEventListener(emitter, event, eventArg => { try { if (predicate && !predicate(eventArg)) return; - helper.removeEventListeners(listeners); + eventsHelper.removeEventListeners(listeners); resolve(eventArg); } catch (e) { - helper.removeEventListeners(listeners); + eventsHelper.removeEventListeners(listeners); reject(e); } })); }); - const dispose = () => helper.removeEventListeners(listeners); + const dispose = () => eventsHelper.removeEventListeners(listeners); if (progress) progress.cleanupWhenAborted(dispose); return { promise, dispose }; diff --git a/src/server/snapshot/inMemorySnapshotter.ts b/src/server/snapshot/inMemorySnapshotter.ts index f04807319b..4ec3d40031 100644 --- a/src/server/snapshot/inMemorySnapshotter.ts +++ b/src/server/snapshot/inMemorySnapshotter.ts @@ -16,7 +16,7 @@ import { HttpServer } from '../../utils/httpServer'; import { BrowserContext } from '../browserContext'; -import { helper } from '../helper'; +import { eventsHelper } from '../../utils/eventsHelper'; import { Page } from '../page'; import { FrameSnapshot, ResourceSnapshot } from './snapshotTypes'; import { SnapshotRenderer } from './snapshotRenderer'; @@ -53,9 +53,9 @@ export class InMemorySnapshotter extends BaseSnapshotStorage implements Snapshot this._snapshotter.captureSnapshot(page, snapshotName, element).catch(() => {}); return new Promise(fulfill => { - const listener = helper.addEventListener(this, 'snapshot', (renderer: SnapshotRenderer) => { + const listener = eventsHelper.addEventListener(this, 'snapshot', (renderer: SnapshotRenderer) => { if (renderer.snapshotName === snapshotName) { - helper.removeEventListeners([listener]); + eventsHelper.removeEventListeners([listener]); fulfill(renderer); } }); diff --git a/src/server/snapshot/snapshotter.ts b/src/server/snapshot/snapshotter.ts index 03e88ac667..313933ceea 100644 --- a/src/server/snapshot/snapshotter.ts +++ b/src/server/snapshot/snapshotter.ts @@ -17,7 +17,7 @@ import { BrowserContext } from '../browserContext'; import { Page } from '../page'; import * as network from '../network'; -import { helper, RegisteredListener } from '../helper'; +import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; import { debugLogger } from '../../utils/debugLogger'; import { Frame } from '../frames'; import { frameSnapshotStreamer, SnapshotData } from './snapshotterInjected'; @@ -79,8 +79,8 @@ export class Snapshotter { for (const page of this._context.pages()) this._onPage(page); this._eventListeners = [ - helper.addEventListener(this._context, BrowserContext.Events.Page, this._onPage.bind(this)), - helper.addEventListener(this._context, BrowserContext.Events.Response, (response: network.Response) => { + eventsHelper.addEventListener(this._context, BrowserContext.Events.Page, this._onPage.bind(this)), + eventsHelper.addEventListener(this._context, BrowserContext.Events.Response, (response: network.Response) => { this._saveResource(response).catch(e => debugLogger.log('error', e)); }), ]; @@ -100,7 +100,7 @@ export class Snapshotter { } dispose() { - helper.removeEventListeners(this._eventListeners); + eventsHelper.removeEventListeners(this._eventListeners); } async captureSnapshot(page: Page, snapshotName: string, element?: ElementHandle): Promise { @@ -151,7 +151,7 @@ export class Snapshotter { // Annotate frame hierarchy so that snapshots could include frame ids. for (const frame of page.frames()) this._annotateFrameHierarchy(frame); - this._eventListeners.push(helper.addEventListener(page, Page.Events.FrameAttached, frame => this._annotateFrameHierarchy(frame))); + this._eventListeners.push(eventsHelper.addEventListener(page, Page.Events.FrameAttached, frame => this._annotateFrameHierarchy(frame))); } private async _saveResource(response: network.Response) { diff --git a/src/server/trace/recorder/tracing.ts b/src/server/trace/recorder/tracing.ts index 3a1879cef2..fe28a4fd9c 100644 --- a/src/server/trace/recorder/tracing.ts +++ b/src/server/trace/recorder/tracing.ts @@ -22,7 +22,7 @@ import { calculateSha1, createGuid, mkdirIfNeeded, monotonicTime } from '../../. import { Artifact } from '../../artifact'; import { BrowserContext } from '../../browserContext'; import { ElementHandle } from '../../dom'; -import { helper, RegisteredListener } from '../../helper'; +import { eventsHelper, RegisteredListener } from '../../../utils/eventsHelper'; import { CallMetadata, InstrumentationListener, SdkObject } from '../../instrumentation'; import { Page } from '../../page'; import * as trace from '../common/traceEvents'; @@ -74,7 +74,7 @@ export class Tracing implements InstrumentationListener { for (const page of this._context.pages()) this._onPage(options.screenshots, page); this._eventListeners.push( - helper.addEventListener(this._context, BrowserContext.Events.Page, this._onPage.bind(this, options.screenshots)), + eventsHelper.addEventListener(this._context, BrowserContext.Events.Page, this._onPage.bind(this, options.screenshots)), ); // context + page must be the first events added, no awaits above this line. @@ -89,7 +89,7 @@ export class Tracing implements InstrumentationListener { if (!this._eventListeners.length) return; this._context.instrumentation.removeListener(this); - helper.removeEventListeners(this._eventListeners); + eventsHelper.removeEventListeners(this._eventListeners); for (const { sdkObject, metadata, beforeSnapshot, actionSnapshot, afterSnapshot } of this._pendingCalls.values()) { await Promise.all([beforeSnapshot, actionSnapshot, afterSnapshot]); if (!afterSnapshot) @@ -182,7 +182,7 @@ export class Tracing implements InstrumentationListener { page.setScreencastOptions({ width: 800, height: 600, quality: 90 }); this._eventListeners.push( - helper.addEventListener(page, Page.Events.ScreencastFrame, params => { + eventsHelper.addEventListener(page, Page.Events.ScreencastFrame, params => { const sha1 = calculateSha1(createGuid()); // no need to compute sha1 for screenshots const event: trace.ScreencastFrameTraceEvent = { type: 'screencast-frame', diff --git a/src/server/webkit/webkit.ts b/src/server/webkit/webkit.ts index dbf7bc13f1..7aadddbade 100644 --- a/src/server/webkit/webkit.ts +++ b/src/server/webkit/webkit.ts @@ -16,7 +16,7 @@ */ import { WKBrowser } from '../webkit/wkBrowser'; -import { Env } from '../processLauncher'; +import { Env } from '../../utils/processLauncher'; import path from 'path'; import { kBrowserCloseMessageId } from './wkConnection'; import { BrowserType } from '../browserType'; diff --git a/src/server/webkit/wkBrowser.ts b/src/server/webkit/wkBrowser.ts index ca73aba131..5bf0ee3cf5 100644 --- a/src/server/webkit/wkBrowser.ts +++ b/src/server/webkit/wkBrowser.ts @@ -17,7 +17,7 @@ import { Browser, BrowserOptions } from '../browser'; import { assertBrowserContextIsNotOwned, BrowserContext, validateBrowserContextOptions, verifyGeolocation } from '../browserContext'; -import { helper, RegisteredListener } from '../helper'; +import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; import { assert } from '../../utils/utils'; import * as network from '../network'; import { Page, PageBinding, PageDelegate } from '../page'; @@ -58,15 +58,15 @@ export class WKBrowser extends Browser { this._connection = new WKConnection(transport, this._onDisconnect.bind(this), options.protocolLogger, options.browserLogsCollector); this._browserSession = this._connection.browserSession; this._eventListeners = [ - helper.addEventListener(this._browserSession, 'Playwright.pageProxyCreated', this._onPageProxyCreated.bind(this)), - helper.addEventListener(this._browserSession, 'Playwright.pageProxyDestroyed', this._onPageProxyDestroyed.bind(this)), - helper.addEventListener(this._browserSession, 'Playwright.provisionalLoadFailed', event => this._onProvisionalLoadFailed(event)), - helper.addEventListener(this._browserSession, 'Playwright.windowOpen', event => this._onWindowOpen(event)), - helper.addEventListener(this._browserSession, 'Playwright.downloadCreated', this._onDownloadCreated.bind(this)), - helper.addEventListener(this._browserSession, 'Playwright.downloadFilenameSuggested', this._onDownloadFilenameSuggested.bind(this)), - helper.addEventListener(this._browserSession, 'Playwright.downloadFinished', this._onDownloadFinished.bind(this)), - helper.addEventListener(this._browserSession, 'Playwright.screencastFinished', this._onScreencastFinished.bind(this)), - helper.addEventListener(this._browserSession, kPageProxyMessageReceived, this._onPageProxyMessageReceived.bind(this)), + eventsHelper.addEventListener(this._browserSession, 'Playwright.pageProxyCreated', this._onPageProxyCreated.bind(this)), + eventsHelper.addEventListener(this._browserSession, 'Playwright.pageProxyDestroyed', this._onPageProxyDestroyed.bind(this)), + eventsHelper.addEventListener(this._browserSession, 'Playwright.provisionalLoadFailed', event => this._onProvisionalLoadFailed(event)), + eventsHelper.addEventListener(this._browserSession, 'Playwright.windowOpen', event => this._onWindowOpen(event)), + eventsHelper.addEventListener(this._browserSession, 'Playwright.downloadCreated', this._onDownloadCreated.bind(this)), + eventsHelper.addEventListener(this._browserSession, 'Playwright.downloadFilenameSuggested', this._onDownloadFilenameSuggested.bind(this)), + eventsHelper.addEventListener(this._browserSession, 'Playwright.downloadFinished', this._onDownloadFinished.bind(this)), + eventsHelper.addEventListener(this._browserSession, 'Playwright.screencastFinished', this._onScreencastFinished.bind(this)), + eventsHelper.addEventListener(this._browserSession, kPageProxyMessageReceived, this._onPageProxyMessageReceived.bind(this)), ]; } diff --git a/src/server/webkit/wkPage.ts b/src/server/webkit/wkPage.ts index 241c7d2bb5..9309e504a7 100644 --- a/src/server/webkit/wkPage.ts +++ b/src/server/webkit/wkPage.ts @@ -25,7 +25,8 @@ import * as accessibility from '../accessibility'; import * as dialog from '../dialog'; import * as dom from '../dom'; import * as frames from '../frames'; -import { helper, RegisteredListener } from '../helper'; +import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; +import { helper } from '../helper'; import { JSHandle, kSwappedOutErrorMessage } from '../javascript'; import * as network from '../network'; import { Page, PageBinding, PageDelegate } from '../page'; @@ -90,11 +91,11 @@ export class WKPage implements PageDelegate { this._browserContext = browserContext; 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)), - helper.addEventListener(this._pageProxySession, 'Target.dispatchMessageFromTarget', this._onDispatchMessageFromTarget.bind(this)), - helper.addEventListener(this._pageProxySession, 'Target.didCommitProvisionalTarget', this._onDidCommitProvisionalTarget.bind(this)), - helper.addEventListener(this._pageProxySession, 'Screencast.screencastFrame', this._onScreencastFrame.bind(this)), + eventsHelper.addEventListener(this._pageProxySession, 'Target.targetCreated', this._onTargetCreated.bind(this)), + eventsHelper.addEventListener(this._pageProxySession, 'Target.targetDestroyed', this._onTargetDestroyed.bind(this)), + eventsHelper.addEventListener(this._pageProxySession, 'Target.dispatchMessageFromTarget', this._onDispatchMessageFromTarget.bind(this)), + eventsHelper.addEventListener(this._pageProxySession, 'Target.didCommitProvisionalTarget', this._onDidCommitProvisionalTarget.bind(this)), + eventsHelper.addEventListener(this._pageProxySession, 'Screencast.screencastFrame', this._onScreencastFrame.bind(this)), ]; this._pagePromise = new Promise(f => this._pagePromiseCallback = f); this._firstNonInitialNavigationCommittedPromise = new Promise((f, r) => { @@ -137,7 +138,7 @@ export class WKPage implements PageDelegate { } private _setSession(session: WKSession) { - helper.removeEventListeners(this._sessionListeners); + eventsHelper.removeEventListeners(this._sessionListeners); this._session = session; this.rawKeyboard.setSession(session); this._addSessionListeners(); @@ -233,7 +234,7 @@ export class WKPage implements PageDelegate { this._provisionalPage = null; } else if (this._session.sessionId === targetId) { this._session.dispose(false); - helper.removeEventListeners(this._sessionListeners); + eventsHelper.removeEventListeners(this._sessionListeners); if (crashed) { this._session.markAsCrashed(); this._page._didCrash(); @@ -247,8 +248,8 @@ export class WKPage implements PageDelegate { dispose(disconnected: boolean) { this._pageProxySession.dispose(disconnected); - helper.removeEventListeners(this._sessionListeners); - helper.removeEventListeners(this._eventListeners); + eventsHelper.removeEventListeners(this._sessionListeners); + eventsHelper.removeEventListeners(this._eventListeners); if (this._session) this._session.dispose(disconnected); if (this._provisionalPage) { @@ -356,32 +357,32 @@ export class WKPage implements PageDelegate { private _addSessionListeners() { // TODO: remove Page.willRequestOpenWindow and Page.didRequestOpenWindow from the protocol. this._sessionListeners = [ - helper.addEventListener(this._session, 'Page.frameNavigated', event => this._onFrameNavigated(event.frame, false)), - helper.addEventListener(this._session, 'Page.navigatedWithinDocument', event => this._onFrameNavigatedWithinDocument(event.frameId, event.url)), - helper.addEventListener(this._session, 'Page.frameAttached', event => this._onFrameAttached(event.frameId, event.parentFrameId)), - helper.addEventListener(this._session, 'Page.frameDetached', event => this._onFrameDetached(event.frameId)), - helper.addEventListener(this._session, 'Page.frameScheduledNavigation', event => this._onFrameScheduledNavigation(event.frameId)), - helper.addEventListener(this._session, 'Page.frameStoppedLoading', event => this._onFrameStoppedLoading(event.frameId)), - helper.addEventListener(this._session, 'Page.loadEventFired', event => this._onLifecycleEvent(event.frameId, 'load')), - helper.addEventListener(this._session, 'Page.domContentEventFired', event => this._onLifecycleEvent(event.frameId, 'domcontentloaded')), - helper.addEventListener(this._session, 'Runtime.executionContextCreated', event => this._onExecutionContextCreated(event.context)), - helper.addEventListener(this._session, 'Console.messageAdded', event => this._onConsoleMessage(event)), - helper.addEventListener(this._session, 'Console.messageRepeatCountUpdated', event => this._onConsoleRepeatCountUpdated(event)), - helper.addEventListener(this._pageProxySession, 'Dialog.javascriptDialogOpening', event => this._onDialog(event)), - helper.addEventListener(this._session, 'Page.fileChooserOpened', event => this._onFileChooserOpened(event)), - helper.addEventListener(this._session, 'Network.requestWillBeSent', e => this._onRequestWillBeSent(this._session, e)), - helper.addEventListener(this._session, 'Network.requestIntercepted', e => this._onRequestIntercepted(this._session, e)), - helper.addEventListener(this._session, 'Network.responseIntercepted', e => this._onResponseIntercepted(this._session, e)), - helper.addEventListener(this._session, 'Network.responseReceived', e => this._onResponseReceived(e)), - helper.addEventListener(this._session, 'Network.loadingFinished', e => this._onLoadingFinished(e)), - helper.addEventListener(this._session, 'Network.loadingFailed', e => this._onLoadingFailed(e)), - helper.addEventListener(this._session, 'Network.webSocketCreated', e => this._page._frameManager.onWebSocketCreated(e.requestId, e.url)), - helper.addEventListener(this._session, 'Network.webSocketWillSendHandshakeRequest', e => this._page._frameManager.onWebSocketRequest(e.requestId)), - helper.addEventListener(this._session, 'Network.webSocketHandshakeResponseReceived', e => this._page._frameManager.onWebSocketResponse(e.requestId, e.response.status, e.response.statusText)), - helper.addEventListener(this._session, 'Network.webSocketFrameSent', e => e.response.payloadData && this._page._frameManager.onWebSocketFrameSent(e.requestId, e.response.opcode, e.response.payloadData)), - helper.addEventListener(this._session, 'Network.webSocketFrameReceived', e => e.response.payloadData && this._page._frameManager.webSocketFrameReceived(e.requestId, e.response.opcode, e.response.payloadData)), - helper.addEventListener(this._session, 'Network.webSocketClosed', e => this._page._frameManager.webSocketClosed(e.requestId)), - helper.addEventListener(this._session, 'Network.webSocketFrameError', e => this._page._frameManager.webSocketError(e.requestId, e.errorMessage)), + eventsHelper.addEventListener(this._session, 'Page.frameNavigated', event => this._onFrameNavigated(event.frame, false)), + eventsHelper.addEventListener(this._session, 'Page.navigatedWithinDocument', event => this._onFrameNavigatedWithinDocument(event.frameId, event.url)), + eventsHelper.addEventListener(this._session, 'Page.frameAttached', event => this._onFrameAttached(event.frameId, event.parentFrameId)), + eventsHelper.addEventListener(this._session, 'Page.frameDetached', event => this._onFrameDetached(event.frameId)), + eventsHelper.addEventListener(this._session, 'Page.frameScheduledNavigation', event => this._onFrameScheduledNavigation(event.frameId)), + eventsHelper.addEventListener(this._session, 'Page.frameStoppedLoading', event => this._onFrameStoppedLoading(event.frameId)), + eventsHelper.addEventListener(this._session, 'Page.loadEventFired', event => this._onLifecycleEvent(event.frameId, 'load')), + eventsHelper.addEventListener(this._session, 'Page.domContentEventFired', event => this._onLifecycleEvent(event.frameId, 'domcontentloaded')), + eventsHelper.addEventListener(this._session, 'Runtime.executionContextCreated', event => this._onExecutionContextCreated(event.context)), + eventsHelper.addEventListener(this._session, 'Console.messageAdded', event => this._onConsoleMessage(event)), + eventsHelper.addEventListener(this._session, 'Console.messageRepeatCountUpdated', event => this._onConsoleRepeatCountUpdated(event)), + eventsHelper.addEventListener(this._pageProxySession, 'Dialog.javascriptDialogOpening', event => this._onDialog(event)), + eventsHelper.addEventListener(this._session, 'Page.fileChooserOpened', event => this._onFileChooserOpened(event)), + eventsHelper.addEventListener(this._session, 'Network.requestWillBeSent', e => this._onRequestWillBeSent(this._session, e)), + eventsHelper.addEventListener(this._session, 'Network.requestIntercepted', e => this._onRequestIntercepted(this._session, e)), + eventsHelper.addEventListener(this._session, 'Network.responseIntercepted', e => this._onResponseIntercepted(this._session, e)), + eventsHelper.addEventListener(this._session, 'Network.responseReceived', e => this._onResponseReceived(e)), + eventsHelper.addEventListener(this._session, 'Network.loadingFinished', e => this._onLoadingFinished(e)), + eventsHelper.addEventListener(this._session, 'Network.loadingFailed', e => this._onLoadingFailed(e)), + eventsHelper.addEventListener(this._session, 'Network.webSocketCreated', e => this._page._frameManager.onWebSocketCreated(e.requestId, e.url)), + eventsHelper.addEventListener(this._session, 'Network.webSocketWillSendHandshakeRequest', e => this._page._frameManager.onWebSocketRequest(e.requestId)), + eventsHelper.addEventListener(this._session, 'Network.webSocketHandshakeResponseReceived', e => this._page._frameManager.onWebSocketResponse(e.requestId, e.response.status, e.response.statusText)), + eventsHelper.addEventListener(this._session, 'Network.webSocketFrameSent', e => e.response.payloadData && this._page._frameManager.onWebSocketFrameSent(e.requestId, e.response.opcode, e.response.payloadData)), + eventsHelper.addEventListener(this._session, 'Network.webSocketFrameReceived', e => e.response.payloadData && this._page._frameManager.webSocketFrameReceived(e.requestId, e.response.opcode, e.response.payloadData)), + eventsHelper.addEventListener(this._session, 'Network.webSocketClosed', e => this._page._frameManager.webSocketClosed(e.requestId)), + eventsHelper.addEventListener(this._session, 'Network.webSocketFrameError', e => this._page._frameManager.webSocketError(e.requestId, e.errorMessage)), ]; } private async _updateState( diff --git a/src/server/webkit/wkProvisionalPage.ts b/src/server/webkit/wkProvisionalPage.ts index db184cd2ff..31e79ee0dd 100644 --- a/src/server/webkit/wkProvisionalPage.ts +++ b/src/server/webkit/wkProvisionalPage.ts @@ -16,7 +16,7 @@ import { WKSession } from './wkConnection'; import { WKPage } from './wkPage'; -import { RegisteredListener, helper } from '../helper'; +import { RegisteredListener, eventsHelper } from '../../utils/eventsHelper'; import { Protocol } from './protocol'; import { assert } from '../../utils/utils'; @@ -42,19 +42,19 @@ export class WKProvisionalPage { const wkPage = this._wkPage; this._sessionListeners = [ - helper.addEventListener(session, 'Network.requestWillBeSent', overrideFrameId(e => wkPage._onRequestWillBeSent(session, e))), - helper.addEventListener(session, 'Network.requestIntercepted', overrideFrameId(e => wkPage._onRequestIntercepted(session, e))), - helper.addEventListener(session, 'Network.responseIntercepted', overrideFrameId(e => wkPage._onResponseIntercepted(session, e))), - helper.addEventListener(session, 'Network.responseReceived', overrideFrameId(e => wkPage._onResponseReceived(e))), - helper.addEventListener(session, 'Network.loadingFinished', overrideFrameId(e => wkPage._onLoadingFinished(e))), - helper.addEventListener(session, 'Network.loadingFailed', overrideFrameId(e => wkPage._onLoadingFailed(e))), + eventsHelper.addEventListener(session, 'Network.requestWillBeSent', overrideFrameId(e => wkPage._onRequestWillBeSent(session, e))), + eventsHelper.addEventListener(session, 'Network.requestIntercepted', overrideFrameId(e => wkPage._onRequestIntercepted(session, e))), + eventsHelper.addEventListener(session, 'Network.responseIntercepted', overrideFrameId(e => wkPage._onResponseIntercepted(session, e))), + eventsHelper.addEventListener(session, 'Network.responseReceived', overrideFrameId(e => wkPage._onResponseReceived(e))), + eventsHelper.addEventListener(session, 'Network.loadingFinished', overrideFrameId(e => wkPage._onLoadingFinished(e))), + eventsHelper.addEventListener(session, 'Network.loadingFailed', overrideFrameId(e => wkPage._onLoadingFailed(e))), ]; this.initializationPromise = this._wkPage._initializeSession(session, true, ({frameTree}) => this._handleFrameTree(frameTree)); } dispose() { - helper.removeEventListeners(this._sessionListeners); + eventsHelper.removeEventListeners(this._sessionListeners); } commit() { diff --git a/src/server/webkit/wkWorkers.ts b/src/server/webkit/wkWorkers.ts index d8ba71f0f6..294813ccdc 100644 --- a/src/server/webkit/wkWorkers.ts +++ b/src/server/webkit/wkWorkers.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { helper, RegisteredListener } from '../helper'; +import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; import { Page, Worker } from '../page'; import { Protocol } from './protocol'; import { WKSession } from './wkConnection'; @@ -31,10 +31,10 @@ export class WKWorkers { } setSession(session: WKSession) { - helper.removeEventListeners(this._sessionListeners); + eventsHelper.removeEventListeners(this._sessionListeners); this.clear(); this._sessionListeners = [ - helper.addEventListener(session, 'Worker.workerCreated', (event: Protocol.Worker.workerCreatedPayload) => { + eventsHelper.addEventListener(session, 'Worker.workerCreated', (event: Protocol.Worker.workerCreatedPayload) => { const worker = new Worker(this._page, event.url); const workerSession = new WKSession(session.connection, event.workerId, 'Most likely the worker has been closed.', (message: any) => { session.send('Worker.sendMessageToWorker', { @@ -57,13 +57,13 @@ export class WKWorkers { this._page._removeWorker(event.workerId); }); }), - helper.addEventListener(session, 'Worker.dispatchMessageFromWorker', (event: Protocol.Worker.dispatchMessageFromWorkerPayload) => { + eventsHelper.addEventListener(session, 'Worker.dispatchMessageFromWorker', (event: Protocol.Worker.dispatchMessageFromWorkerPayload) => { const workerSession = this._workerSessions.get(event.workerId)!; if (!workerSession) return; workerSession.dispatchMessage(JSON.parse(event.message)); }), - helper.addEventListener(session, 'Worker.workerTerminated', (event: Protocol.Worker.workerTerminatedPayload) => { + eventsHelper.addEventListener(session, 'Worker.workerTerminated', (event: Protocol.Worker.workerTerminatedPayload) => { const workerSession = this._workerSessions.get(event.workerId)!; if (!workerSession) return; diff --git a/src/test/webServer.ts b/src/test/webServer.ts index d0b845821a..f1f0a889ac 100644 --- a/src/test/webServer.ts +++ b/src/test/webServer.ts @@ -20,7 +20,7 @@ import os from 'os'; import stream from 'stream'; import { monotonicTime, raceAgainstDeadline } from './util'; import { WebServerConfig } from '../../types/test'; -import { launchProcess } from '../server/processLauncher'; +import { launchProcess } from '../utils/processLauncher'; const DEFAULT_ENVIRONMENT_VARIABLES = { 'BROWSER': 'none', // Disable that create-react-app will open the page in the browser diff --git a/src/utils/eventsHelper.ts b/src/utils/eventsHelper.ts new file mode 100644 index 0000000000..70f5207a88 --- /dev/null +++ b/src/utils/eventsHelper.ts @@ -0,0 +1,46 @@ +/** + * Copyright 2017 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. + */ + +import { EventEmitter } from 'events'; + +export type RegisteredListener = { + emitter: EventEmitter; + eventName: (string | symbol); + handler: (...args: any[]) => void; +}; + +class EventsHelper { + static addEventListener( + emitter: EventEmitter, + eventName: (string | symbol), + handler: (...args: any[]) => void): RegisteredListener { + emitter.on(eventName, handler); + return { emitter, eventName, handler }; + } + + static removeEventListeners(listeners: Array<{ + emitter: EventEmitter; + eventName: (string | symbol); + handler: (...args: any[]) => void; + }>) { + for (const listener of listeners) + listener.emitter.removeListener(listener.eventName, listener.handler); + listeners.splice(0, listeners.length); + } +} + +export const eventsHelper = EventsHelper; diff --git a/src/server/processLauncher.ts b/src/utils/processLauncher.ts similarity index 92% rename from src/server/processLauncher.ts rename to src/utils/processLauncher.ts index 0540d34db2..94780987cf 100644 --- a/src/server/processLauncher.ts +++ b/src/utils/processLauncher.ts @@ -17,9 +17,8 @@ import * as childProcess from 'child_process'; import * as readline from 'readline'; -import { helper } from './helper'; -import * as types from './types'; -import { isUnderTest, removeFolders } from '../utils/utils'; +import { eventsHelper } from './eventsHelper'; +import { isUnderTest, removeFolders } from './utils'; export type Env = {[key: string]: string | number | boolean | undefined}; @@ -117,7 +116,7 @@ export async function launchProcess(options: LaunchProcessOptions): Promise { options.log(`[pid=${spawnedProcess.pid}] `); processClosed = true; - helper.removeEventListeners(listeners); + eventsHelper.removeEventListeners(listeners); gracefullyCloseSet.delete(gracefullyClose); options.onExit(exitCode, signal); fulfillClose(); @@ -125,9 +124,9 @@ export async function launchProcess(options: LaunchProcessOptions): Promise { + listeners.push(eventsHelper.addEventListener(process, 'SIGINT', () => { gracefullyClose().then(() => { // Give tests a chance to dispatch any async calls. if (isUnderTest()) @@ -138,9 +137,9 @@ export async function launchProcess(options: LaunchProcessOptions): Promise`); - helper.removeEventListeners(listeners); + eventsHelper.removeEventListeners(listeners); if (spawnedProcess.pid && !spawnedProcess.killed && !processClosed) { options.log(`[pid=${spawnedProcess.pid}] `); // Force kill the browser. @@ -195,7 +194,7 @@ export async function launchProcess(options: LaunchProcessOptions): Promise { console.error(e && e.stack ? e.stack : e);