refactor: consolidate all events in Events.js (#3772)

This will allow us to break all dependency cycles that were forcing
us to put many things in a single file (e.g. ExecutionContext and
ElementHandle).
This commit is contained in:
Andrey Lushnikov 2019-01-14 19:57:05 -08:00 committed by GitHub
parent 71edfc779b
commit 4e9e3bc614
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 181 additions and 151 deletions

View File

@ -18,7 +18,7 @@ const { helper, assert } = require('./helper');
const {Target} = require('./Target'); const {Target} = require('./Target');
const EventEmitter = require('events'); const EventEmitter = require('events');
const {TaskQueue} = require('./TaskQueue'); const {TaskQueue} = require('./TaskQueue');
const {Connection} = require('./Connection'); const {Events} = require('./Events');
class Browser extends EventEmitter { class Browser extends EventEmitter {
/** /**
@ -46,7 +46,7 @@ class Browser extends EventEmitter {
/** @type {Map<string, Target>} */ /** @type {Map<string, Target>} */
this._targets = new Map(); this._targets = new Map();
this._connection.on(Connection.Events.Disconnected, () => this.emit(Browser.Events.Disconnected)); this._connection.on(Events.Connection.Disconnected, () => this.emit(Events.Browser.Disconnected));
this._connection.on('Target.targetCreated', this._targetCreated.bind(this)); this._connection.on('Target.targetCreated', this._targetCreated.bind(this));
this._connection.on('Target.targetDestroyed', this._targetDestroyed.bind(this)); this._connection.on('Target.targetDestroyed', this._targetDestroyed.bind(this));
this._connection.on('Target.targetInfoChanged', this._targetInfoChanged.bind(this)); this._connection.on('Target.targetInfoChanged', this._targetInfoChanged.bind(this));
@ -118,8 +118,8 @@ class Browser extends EventEmitter {
this._targets.set(event.targetInfo.targetId, target); this._targets.set(event.targetInfo.targetId, target);
if (await target._initializedPromise) { if (await target._initializedPromise) {
this.emit(Browser.Events.TargetCreated, target); this.emit(Events.Browser.TargetCreated, target);
context.emit(BrowserContext.Events.TargetCreated, target); context.emit(Events.BrowserContext.TargetCreated, target);
} }
} }
@ -132,8 +132,8 @@ class Browser extends EventEmitter {
this._targets.delete(event.targetId); this._targets.delete(event.targetId);
target._closedCallback(); target._closedCallback();
if (await target._initializedPromise) { if (await target._initializedPromise) {
this.emit(Browser.Events.TargetDestroyed, target); this.emit(Events.Browser.TargetDestroyed, target);
target.browserContext().emit(BrowserContext.Events.TargetDestroyed, target); target.browserContext().emit(Events.BrowserContext.TargetDestroyed, target);
} }
} }
@ -147,8 +147,8 @@ class Browser extends EventEmitter {
const wasInitialized = target._isInitialized; const wasInitialized = target._isInitialized;
target._targetInfoChanged(event.targetInfo); target._targetInfoChanged(event.targetInfo);
if (wasInitialized && previousURL !== target.url()) { if (wasInitialized && previousURL !== target.url()) {
this.emit(Browser.Events.TargetChanged, target); this.emit(Events.Browser.TargetChanged, target);
target.browserContext().emit(BrowserContext.Events.TargetChanged, target); target.browserContext().emit(Events.BrowserContext.TargetChanged, target);
} }
} }
@ -206,15 +206,15 @@ class Browser extends EventEmitter {
return existingTarget; return existingTarget;
let resolve; let resolve;
const targetPromise = new Promise(x => resolve = x); const targetPromise = new Promise(x => resolve = x);
this.on(Browser.Events.TargetCreated, check); this.on(Events.Browser.TargetCreated, check);
this.on(Browser.Events.TargetChanged, check); this.on(Events.Browser.TargetChanged, check);
try { try {
if (!timeout) if (!timeout)
return await targetPromise; return await targetPromise;
return await helper.waitWithTimeout(targetPromise, 'target', timeout); return await helper.waitWithTimeout(targetPromise, 'target', timeout);
} finally { } finally {
this.removeListener(Browser.Events.TargetCreated, check); this.removeListener(Events.Browser.TargetCreated, check);
this.removeListener(Browser.Events.TargetChanged, check); this.removeListener(Events.Browser.TargetChanged, check);
} }
/** /**
@ -268,14 +268,6 @@ class Browser extends EventEmitter {
} }
} }
/** @enum {string} */
Browser.Events = {
TargetCreated: 'targetcreated',
TargetDestroyed: 'targetdestroyed',
TargetChanged: 'targetchanged',
Disconnected: 'disconnected'
};
class BrowserContext extends EventEmitter { class BrowserContext extends EventEmitter {
/** /**
* @param {!Puppeteer.Connection} connection * @param {!Puppeteer.Connection} connection
@ -381,13 +373,6 @@ class BrowserContext extends EventEmitter {
} }
} }
/** @enum {string} */
BrowserContext.Events = {
TargetCreated: 'targetcreated',
TargetDestroyed: 'targetdestroyed',
TargetChanged: 'targetchanged',
};
helper.tracePublicAPI(BrowserContext); helper.tracePublicAPI(BrowserContext);
helper.tracePublicAPI(Browser); helper.tracePublicAPI(Browser);

View File

@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
const {helper, assert} = require('./helper'); const {helper, assert} = require('./helper');
const {Events} = require('./Events');
const debugProtocol = require('debug')('puppeteer:protocol'); const debugProtocol = require('debug')('puppeteer:protocol');
const debugSession = require('debug')('puppeteer:session'); const debugSession = require('debug')('puppeteer:session');
const EventEmitter = require('events'); const EventEmitter = require('events');
@ -120,7 +121,7 @@ class Connection extends EventEmitter {
for (const session of this._sessions.values()) for (const session of this._sessions.values())
session._onClosed(); session._onClosed();
this._sessions.clear(); this._sessions.clear();
this.emit(Connection.Events.Disconnected); this.emit(Events.Connection.Disconnected);
} }
dispose() { dispose() {
@ -140,10 +141,6 @@ class Connection extends EventEmitter {
} }
} }
Connection.Events = {
Disconnected: Symbol('Connection.Events.Disconnected'),
};
class CDPSession extends EventEmitter { class CDPSession extends EventEmitter {
/** /**
* @param {!Connection|!CDPSession} connection * @param {!Connection|!CDPSession} connection
@ -228,7 +225,7 @@ class CDPSession extends EventEmitter {
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`)); callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
this._callbacks.clear(); this._callbacks.clear();
this._connection = null; this._connection = null;
this.emit(CDPSession.Events.Disconnected); this.emit(Events.CDPSession.Disconnected);
} }
/** /**
@ -242,10 +239,6 @@ class CDPSession extends EventEmitter {
} }
} }
CDPSession.Events = {
Disconnected: Symbol('CDPSession.Events.Disconnected'),
};
helper.tracePublicAPI(CDPSession); helper.tracePublicAPI(CDPSession);
/** /**

80
lib/Events.js Normal file
View File

@ -0,0 +1,80 @@
/**
* Copyright 2019 Google Inc. All rights reserved.
*
* 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.
*/
const Events = {
Page: {
Close: 'close',
Console: 'console',
Dialog: 'dialog',
DOMContentLoaded: 'domcontentloaded',
Error: 'error',
// 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',
Metrics: 'metrics',
Popup: 'popup',
WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed',
},
Browser: {
TargetCreated: 'targetcreated',
TargetDestroyed: 'targetdestroyed',
TargetChanged: 'targetchanged',
Disconnected: 'disconnected'
},
BrowserContext: {
TargetCreated: 'targetcreated',
TargetDestroyed: 'targetdestroyed',
TargetChanged: 'targetchanged',
},
NetworkManager: {
Request: Symbol('Events.NetworkManager.Request'),
Response: Symbol('Events.NetworkManager.Response'),
RequestFailed: Symbol('Events.NetworkManager.RequestFailed'),
RequestFinished: Symbol('Events.NetworkManager.RequestFinished'),
},
FrameManager: {
FrameAttached: Symbol('Events.FrameManager.FrameAttached'),
FrameNavigated: Symbol('Events.FrameManager.FrameNavigated'),
FrameDetached: Symbol('Events.FrameManager.FrameDetached'),
LifecycleEvent: Symbol('Events.FrameManager.LifecycleEvent'),
FrameNavigatedWithinDocument: Symbol('Events.FrameManager.FrameNavigatedWithinDocument'),
ExecutionContextCreated: Symbol('Events.FrameManager.ExecutionContextCreated'),
ExecutionContextDestroyed: Symbol('Events.FrameManager.ExecutionContextDestroyed'),
},
Connection: {
Disconnected: Symbol('Events.Connection.Disconnected'),
},
CDPSession: {
Disconnected: Symbol('Events.CDPSession.Disconnected'),
},
};
module.exports = { Events };

View File

@ -17,10 +17,9 @@
const fs = require('fs'); const fs = require('fs');
const EventEmitter = require('events'); const EventEmitter = require('events');
const {helper, assert} = require('./helper'); const {helper, assert} = require('./helper');
const {Events} = require('./Events');
const {ExecutionContext} = require('./ExecutionContext'); const {ExecutionContext} = require('./ExecutionContext');
const {TimeoutError} = require('./Errors'); const {TimeoutError} = require('./Errors');
const {NetworkManager} = require('./NetworkManager');
const {CDPSession} = require('./Connection');
const readFileAsync = helper.promisify(fs.readFile); const readFileAsync = helper.promisify(fs.readFile);
@ -142,7 +141,7 @@ class FrameManager extends EventEmitter {
if (!frame) if (!frame)
return; return;
frame._onLifecycleEvent(event.loaderId, event.name); frame._onLifecycleEvent(event.loaderId, event.name);
this.emit(FrameManager.Events.LifecycleEvent, frame); this.emit(Events.FrameManager.LifecycleEvent, frame);
} }
/** /**
@ -153,7 +152,7 @@ class FrameManager extends EventEmitter {
if (!frame) if (!frame)
return; return;
frame._onLoadingStopped(); frame._onLoadingStopped();
this.emit(FrameManager.Events.LifecycleEvent, frame); this.emit(Events.FrameManager.LifecycleEvent, frame);
} }
/** /**
@ -210,7 +209,7 @@ class FrameManager extends EventEmitter {
const parentFrame = this._frames.get(parentFrameId); const parentFrame = this._frames.get(parentFrameId);
const frame = new Frame(this, this._client, parentFrame, frameId); const frame = new Frame(this, this._client, parentFrame, frameId);
this._frames.set(frame._id, frame); this._frames.set(frame._id, frame);
this.emit(FrameManager.Events.FrameAttached, frame); this.emit(Events.FrameManager.FrameAttached, frame);
} }
/** /**
@ -244,7 +243,7 @@ class FrameManager extends EventEmitter {
// Update frame payload. // Update frame payload.
frame._navigated(framePayload); frame._navigated(framePayload);
this.emit(FrameManager.Events.FrameNavigated, frame); this.emit(Events.FrameManager.FrameNavigated, frame);
} }
/** /**
@ -256,8 +255,8 @@ class FrameManager extends EventEmitter {
if (!frame) if (!frame)
return; return;
frame._navigatedWithinDocument(url); frame._navigatedWithinDocument(url);
this.emit(FrameManager.Events.FrameNavigatedWithinDocument, frame); this.emit(Events.FrameManager.FrameNavigatedWithinDocument, frame);
this.emit(FrameManager.Events.FrameNavigated, frame); this.emit(Events.FrameManager.FrameNavigated, frame);
} }
/** /**
@ -317,21 +316,10 @@ class FrameManager extends EventEmitter {
this._removeFramesRecursively(child); this._removeFramesRecursively(child);
frame._detach(); frame._detach();
this._frames.delete(frame._id); this._frames.delete(frame._id);
this.emit(FrameManager.Events.FrameDetached, frame); this.emit(Events.FrameManager.FrameDetached, frame);
} }
} }
/** @enum {string} */
FrameManager.Events = {
FrameAttached: 'frameattached',
FrameNavigated: 'framenavigated',
FrameDetached: 'framedetached',
LifecycleEvent: 'lifecycleevent',
FrameNavigatedWithinDocument: 'framenavigatedwithindocument',
ExecutionContextCreated: 'executioncontextcreated',
ExecutionContextDestroyed: 'executioncontextdestroyed',
};
/** /**
* @unrestricted * @unrestricted
*/ */
@ -1180,11 +1168,11 @@ class LifecycleWatcher {
/** @type {?Puppeteer.Request} */ /** @type {?Puppeteer.Request} */
this._navigationRequest = null; this._navigationRequest = null;
this._eventListeners = [ this._eventListeners = [
helper.addEventListener(frameManager._client, CDPSession.Events.Disconnected, () => this._terminate(new Error('Navigation failed because browser has disconnected!'))), helper.addEventListener(frameManager._client, Events.CDPSession.Disconnected, () => this._terminate(new Error('Navigation failed because browser has disconnected!'))),
helper.addEventListener(this._frameManager, FrameManager.Events.LifecycleEvent, this._checkLifecycleComplete.bind(this)), helper.addEventListener(this._frameManager, Events.FrameManager.LifecycleEvent, this._checkLifecycleComplete.bind(this)),
helper.addEventListener(this._frameManager, FrameManager.Events.FrameNavigatedWithinDocument, this._navigatedWithinDocument.bind(this)), helper.addEventListener(this._frameManager, Events.FrameManager.FrameNavigatedWithinDocument, this._navigatedWithinDocument.bind(this)),
helper.addEventListener(this._frameManager, FrameManager.Events.FrameDetached, this._onFrameDetached.bind(this)), helper.addEventListener(this._frameManager, Events.FrameManager.FrameDetached, this._onFrameDetached.bind(this)),
helper.addEventListener(this._networkManager, NetworkManager.Events.Request, this._onRequest.bind(this)), helper.addEventListener(this._networkManager, Events.NetworkManager.Request, this._onRequest.bind(this)),
]; ];
this._sameDocumentNavigationPromise = new Promise(fulfill => { this._sameDocumentNavigationPromise = new Promise(fulfill => {

View File

@ -15,6 +15,7 @@
*/ */
const EventEmitter = require('events'); const EventEmitter = require('events');
const {helper, assert, debugError} = require('./helper'); const {helper, assert, debugError} = require('./helper');
const {Events} = require('./Events');
const Multimap = require('./Multimap'); const Multimap = require('./Multimap');
class NetworkManager extends EventEmitter { class NetworkManager extends EventEmitter {
@ -206,7 +207,7 @@ class NetworkManager extends EventEmitter {
const frame = event.frameId && this._frameManager ? this._frameManager.frame(event.frameId) : null; const frame = event.frameId && this._frameManager ? this._frameManager.frame(event.frameId) : null;
const request = new Request(this._client, frame, interceptionId, this._userRequestInterceptionEnabled, event, redirectChain); const request = new Request(this._client, frame, interceptionId, this._userRequestInterceptionEnabled, event, redirectChain);
this._requestIdToRequest.set(event.requestId, request); this._requestIdToRequest.set(event.requestId, request);
this.emit(NetworkManager.Events.Request, request); this.emit(Events.NetworkManager.Request, request);
} }
@ -230,8 +231,8 @@ class NetworkManager extends EventEmitter {
response._bodyLoadedPromiseFulfill.call(null, new Error('Response body is unavailable for redirect responses')); response._bodyLoadedPromiseFulfill.call(null, new Error('Response body is unavailable for redirect responses'));
this._requestIdToRequest.delete(request._requestId); this._requestIdToRequest.delete(request._requestId);
this._attemptedAuthentications.delete(request._interceptionId); this._attemptedAuthentications.delete(request._interceptionId);
this.emit(NetworkManager.Events.Response, response); this.emit(Events.NetworkManager.Response, response);
this.emit(NetworkManager.Events.RequestFinished, request); this.emit(Events.NetworkManager.RequestFinished, request);
} }
/** /**
@ -244,7 +245,7 @@ class NetworkManager extends EventEmitter {
return; return;
const response = new Response(this._client, request, event.response); const response = new Response(this._client, request, event.response);
request._response = response; request._response = response;
this.emit(NetworkManager.Events.Response, response); this.emit(Events.NetworkManager.Response, response);
} }
/** /**
@ -263,7 +264,7 @@ class NetworkManager extends EventEmitter {
request.response()._bodyLoadedPromiseFulfill.call(null); request.response()._bodyLoadedPromiseFulfill.call(null);
this._requestIdToRequest.delete(request._requestId); this._requestIdToRequest.delete(request._requestId);
this._attemptedAuthentications.delete(request._interceptionId); this._attemptedAuthentications.delete(request._interceptionId);
this.emit(NetworkManager.Events.RequestFinished, request); this.emit(Events.NetworkManager.RequestFinished, request);
} }
/** /**
@ -281,7 +282,7 @@ class NetworkManager extends EventEmitter {
response._bodyLoadedPromiseFulfill.call(null); response._bodyLoadedPromiseFulfill.call(null);
this._requestIdToRequest.delete(request._requestId); this._requestIdToRequest.delete(request._requestId);
this._attemptedAuthentications.delete(request._interceptionId); this._attemptedAuthentications.delete(request._interceptionId);
this.emit(NetworkManager.Events.RequestFailed, request); this.emit(Events.NetworkManager.RequestFailed, request);
} }
} }
@ -732,13 +733,6 @@ class SecurityDetails {
} }
} }
NetworkManager.Events = {
Request: 'request',
Response: 'response',
RequestFailed: 'requestfailed',
RequestFinished: 'requestfinished',
};
const statusTexts = { const statusTexts = {
'100': 'Continue', '100': 'Continue',
'101': 'Switching Protocols', '101': 'Switching Protocols',

View File

@ -17,6 +17,7 @@
const fs = require('fs'); const fs = require('fs');
const EventEmitter = require('events'); const EventEmitter = require('events');
const mime = require('mime'); const mime = require('mime');
const {Events} = require('./Events');
const {NetworkManager} = require('./NetworkManager'); const {NetworkManager} = require('./NetworkManager');
const {Dialog} = require('./Dialog'); const {Dialog} = require('./Dialog');
const {EmulationManager} = require('./EmulationManager'); const {EmulationManager} = require('./EmulationManager');
@ -108,28 +109,28 @@ class Page extends EventEmitter {
const session = client._createSession(event.targetInfo.type, event.sessionId); const session = client._createSession(event.targetInfo.type, event.sessionId);
const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this)); const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this));
this._workers.set(event.sessionId, worker); this._workers.set(event.sessionId, worker);
this.emit(Page.Events.WorkerCreated, worker); this.emit(Events.Page.WorkerCreated, worker);
}); });
client.on('Target.detachedFromTarget', event => { client.on('Target.detachedFromTarget', event => {
const worker = this._workers.get(event.sessionId); const worker = this._workers.get(event.sessionId);
if (!worker) if (!worker)
return; return;
this.emit(Page.Events.WorkerDestroyed, worker); this.emit(Events.Page.WorkerDestroyed, worker);
this._workers.delete(event.sessionId); this._workers.delete(event.sessionId);
}); });
this._frameManager.on(FrameManager.Events.FrameAttached, event => this.emit(Page.Events.FrameAttached, event)); this._frameManager.on(Events.FrameManager.FrameAttached, event => this.emit(Events.Page.FrameAttached, event));
this._frameManager.on(FrameManager.Events.FrameDetached, event => this.emit(Page.Events.FrameDetached, event)); this._frameManager.on(Events.FrameManager.FrameDetached, event => this.emit(Events.Page.FrameDetached, event));
this._frameManager.on(FrameManager.Events.FrameNavigated, event => this.emit(Page.Events.FrameNavigated, event)); this._frameManager.on(Events.FrameManager.FrameNavigated, event => this.emit(Events.Page.FrameNavigated, event));
this._networkManager.on(NetworkManager.Events.Request, event => this.emit(Page.Events.Request, event)); this._networkManager.on(Events.NetworkManager.Request, event => this.emit(Events.Page.Request, event));
this._networkManager.on(NetworkManager.Events.Response, event => this.emit(Page.Events.Response, event)); this._networkManager.on(Events.NetworkManager.Response, event => this.emit(Events.Page.Response, event));
this._networkManager.on(NetworkManager.Events.RequestFailed, event => this.emit(Page.Events.RequestFailed, event)); this._networkManager.on(Events.NetworkManager.RequestFailed, event => this.emit(Events.Page.RequestFailed, event));
this._networkManager.on(NetworkManager.Events.RequestFinished, event => this.emit(Page.Events.RequestFinished, event)); this._networkManager.on(Events.NetworkManager.RequestFinished, event => this.emit(Events.Page.RequestFinished, event));
client.on('Page.domContentEventFired', event => this.emit(Page.Events.DOMContentLoaded)); client.on('Page.domContentEventFired', event => this.emit(Events.Page.DOMContentLoaded));
client.on('Page.loadEventFired', event => this.emit(Page.Events.Load)); client.on('Page.loadEventFired', event => this.emit(Events.Page.Load));
client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event)); client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
client.on('Runtime.bindingCalled', event => this._onBindingCalled(event)); client.on('Runtime.bindingCalled', event => this._onBindingCalled(event));
client.on('Page.javascriptDialogOpening', event => this._onDialog(event)); client.on('Page.javascriptDialogOpening', event => this._onDialog(event));
@ -139,7 +140,7 @@ class Page extends EventEmitter {
client.on('Performance.metrics', event => this._emitMetrics(event)); client.on('Performance.metrics', event => this._emitMetrics(event));
client.on('Log.entryAdded', event => this._onLogEntryAdded(event)); client.on('Log.entryAdded', event => this._onLogEntryAdded(event));
this._target._isClosedPromise.then(() => { this._target._isClosedPromise.then(() => {
this.emit(Page.Events.Close); this.emit(Events.Page.Close);
this._closed = true; this._closed = true;
}); });
} }
@ -191,7 +192,7 @@ class Page extends EventEmitter {
if (args) if (args)
args.map(arg => helper.releaseObject(this._client, arg)); args.map(arg => helper.releaseObject(this._client, arg));
if (source !== 'worker') if (source !== 'worker')
this.emit(Page.Events.Console, new ConsoleMessage(level, text, [], {url, lineNumber})); this.emit(Events.Page.Console, new ConsoleMessage(level, text, [], {url, lineNumber}));
} }
/** /**
@ -475,7 +476,7 @@ class Page extends EventEmitter {
* @param {!Protocol.Performance.metricsPayload} event * @param {!Protocol.Performance.metricsPayload} event
*/ */
_emitMetrics(event) { _emitMetrics(event) {
this.emit(Page.Events.Metrics, { this.emit(Events.Page.Metrics, {
title: event.title, title: event.title,
metrics: this._buildMetricsObject(event.metrics) metrics: this._buildMetricsObject(event.metrics)
}); });
@ -501,7 +502,7 @@ class Page extends EventEmitter {
const message = helper.getExceptionMessage(exceptionDetails); const message = helper.getExceptionMessage(exceptionDetails);
const err = new Error(message); const err = new Error(message);
err.stack = ''; // Don't report clientside error with a node stack attached err.stack = ''; // Don't report clientside error with a node stack attached
this.emit(Page.Events.PageError, err); this.emit(Events.Page.PageError, err);
} }
/** /**
@ -570,7 +571,7 @@ class Page extends EventEmitter {
* @param {Protocol.Runtime.StackTrace=} stackTrace * @param {Protocol.Runtime.StackTrace=} stackTrace
*/ */
_addConsoleMessage(type, args, stackTrace) { _addConsoleMessage(type, args, stackTrace) {
if (!this.listenerCount(Page.Events.Console)) { if (!this.listenerCount(Events.Page.Console)) {
args.forEach(arg => arg.dispose()); args.forEach(arg => arg.dispose());
return; return;
} }
@ -588,7 +589,7 @@ class Page extends EventEmitter {
columnNumber: stackTrace.callFrames[0].columnNumber, columnNumber: stackTrace.callFrames[0].columnNumber,
} : {}; } : {};
const message = new ConsoleMessage(type, textTokens.join(' '), args, location); const message = new ConsoleMessage(type, textTokens.join(' '), args, location);
this.emit(Page.Events.Console, message); this.emit(Events.Page.Console, message);
} }
_onDialog(event) { _onDialog(event) {
@ -603,7 +604,7 @@ class Page extends EventEmitter {
dialogType = Dialog.Type.BeforeUnload; dialogType = Dialog.Type.BeforeUnload;
assert(dialogType, 'Unknown javascript dialog type: ' + event.type); assert(dialogType, 'Unknown javascript dialog type: ' + event.type);
const dialog = new Dialog(this._client, dialogType, event.message, event.defaultPrompt); const dialog = new Dialog(this._client, dialogType, event.message, event.defaultPrompt);
this.emit(Page.Events.Dialog, dialog); this.emit(Events.Page.Dialog, dialog);
} }
/** /**
@ -666,7 +667,7 @@ class Page extends EventEmitter {
const { const {
timeout = 30000 timeout = 30000
} = options; } = options;
return helper.waitForEvent(this._networkManager, NetworkManager.Events.Request, request => { return helper.waitForEvent(this._networkManager, Events.NetworkManager.Request, request => {
if (helper.isString(urlOrPredicate)) if (helper.isString(urlOrPredicate))
return (urlOrPredicate === request.url()); return (urlOrPredicate === request.url());
if (typeof urlOrPredicate === 'function') if (typeof urlOrPredicate === 'function')
@ -684,7 +685,7 @@ class Page extends EventEmitter {
const { const {
timeout = 30000 timeout = 30000
} = options; } = options;
return helper.waitForEvent(this._networkManager, NetworkManager.Events.Response, response => { return helper.waitForEvent(this._networkManager, Events.NetworkManager.Response, response => {
if (helper.isString(urlOrPredicate)) if (helper.isString(urlOrPredicate))
return (urlOrPredicate === response.url()); return (urlOrPredicate === response.url());
if (typeof urlOrPredicate === 'function') if (typeof urlOrPredicate === 'function')
@ -1182,30 +1183,6 @@ function convertPrintParameterToInches(parameter) {
return pixels / 96; return pixels / 96;
} }
Page.Events = {
Close: 'close',
Console: 'console',
Dialog: 'dialog',
DOMContentLoaded: 'domcontentloaded',
Error: 'error',
// 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',
Metrics: 'metrics',
Popup: 'popup',
WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed',
};
/** /**
* @typedef {Object} Network.Cookie * @typedef {Object} Network.Cookie
* @property {string} name * @property {string} name

View File

@ -1,3 +1,4 @@
const {Events} = require('./Events');
const {Page} = require('./Page'); const {Page} = require('./Page');
const {helper} = require('./helper'); const {helper} = require('./helper');
@ -27,10 +28,10 @@ class Target {
if (!opener || !opener._pagePromise || this.type() !== 'page') if (!opener || !opener._pagePromise || this.type() !== 'page')
return true; return true;
const openerPage = await opener._pagePromise; const openerPage = await opener._pagePromise;
if (!openerPage.listenerCount(Page.Events.Popup)) if (!openerPage.listenerCount(Events.Page.Popup))
return true; return true;
const popupPage = await this.page(); const popupPage = await this.page();
openerPage.emit(Page.Events.Popup, popupPage); openerPage.emit(Events.Page.Popup, popupPage);
return true; return true;
}); });
this._isClosedPromise = new Promise(fulfill => this._closedCallback = fulfill); this._isClosedPromise = new Promise(fulfill => this._closedCallback = fulfill);

View File

@ -220,7 +220,7 @@ class Helper {
/** /**
* @param {!NodeJS.EventEmitter} emitter * @param {!NodeJS.EventEmitter} emitter
* @param {string} eventName * @param {(string|symbol)} eventName
* @param {function} predicate * @param {function} predicate
* @return {!Promise} * @return {!Promise}
*/ */

View File

@ -7,6 +7,15 @@ module.exports = checkSources;
* @param {!Array<!import('../Source')>} sources * @param {!Array<!import('../Source')>} sources
*/ */
function checkSources(sources) { function checkSources(sources) {
// special treatment for Events.js
const classEvents = new Map();
const eventsSource = sources.find(source => source.name() === 'Events.js');
if (eventsSource) {
const {Events} = require(eventsSource.filePath());
for (const [className, events] of Object.entries(Events))
classEvents.set(className, Array.from(Object.values(events)).filter(e => typeof e === 'string').map(e => Documentation.Member.createEvent(e)));
}
const excludeClasses = new Set([]); const excludeClasses = new Set([]);
const program = ts.createProgram({ const program = ts.createProgram({
options: { options: {
@ -24,6 +33,7 @@ function checkSources(sources) {
sourceFiles.filter(x => !x.fileName.includes('node_modules')).map(x => visit(x)); sourceFiles.filter(x => !x.fileName.includes('node_modules')).map(x => visit(x));
const errors = []; const errors = [];
const documentation = new Documentation(recreateClassesWithInheritance(classes, inheritance)); const documentation = new Documentation(recreateClassesWithInheritance(classes, inheritance));
return {errors, documentation}; return {errors, documentation};
/** /**
@ -158,17 +168,7 @@ function checkSources(sources) {
*/ */
function serializeClass(className, symbol, node) { function serializeClass(className, symbol, node) {
/** @type {!Array<!Documentation.Member>} */ /** @type {!Array<!Documentation.Member>} */
const members = []; const members = classEvents.get(className) || [];
const type = checker.getTypeOfSymbolAtLocation(symbol, node);
const events = type.getProperty('Events');
if (events) {
const eventType = checker.getTypeAtLocation(events.valueDeclaration);
for (const property of eventType.getProperties()) {
if (property.valueDeclaration.initializer.text)
members.push(Documentation.Member.createEvent(property.valueDeclaration.initializer.text));
}
}
for (const [name, member] of symbol.members || []) { for (const [name, member] of symbol.members || []) {
if (name.startsWith('_')) if (name.startsWith('_'))

View File

@ -0,0 +1,8 @@
const Events = {
Foo: {
a: 'a',
b: 'b',
c: 'c',
},
};
module.exports = {Events};

View File

@ -10,8 +10,3 @@ class Foo {
ccc() {} ccc() {}
} }
Foo.Events = {
a: 'a',
b: 'b',
c: 'c'
}

View File

@ -0,0 +1,8 @@
const Events = {
Foo: {
Start: 'start',
Finish: 'finish',
},
};
module.exports = {Events};

View File

@ -1,7 +1,3 @@
class Foo { class Foo {
} }
Foo.Events = {
Start: 'start',
Finish: 'finish',
};

View File

@ -0,0 +1,6 @@
const Events = {
A: {
AnEvent: 'anevent'
},
};
module.exports = { Events };

View File

@ -11,7 +11,3 @@ class A {
async method(foo, bar) { async method(foo, bar) {
} }
} }
A.Events = {
AnEvent: 'anevent'
};

View File

@ -0,0 +1,8 @@
const Events = {
B: {
// Event with the same name as a super class method.
foo: 'foo',
},
};
module.exports = {Events};

View File

@ -13,8 +13,3 @@ class B extends A {
bar(override) { bar(override) {
} }
} }
B.Events = {
// Event with the same name as a super class method.
foo: 'foo'
};