From 7af3d543169a5e2553d1b55971f7b6f65aa652e4 Mon Sep 17 00:00:00 2001 From: Jack Franklin Date: Thu, 23 Apr 2020 16:22:15 +0100 Subject: [PATCH] chore: migrate src/LifecycleWatcher --- src/DOMWorld.js | 2 +- src/FrameManager.js | 10 +- ...ifecycleWatcher.js => LifecycleWatcher.ts} | 122 ++++++++---------- src/Page.js | 14 +- src/externs.d.ts | 6 + 5 files changed, 76 insertions(+), 78 deletions(-) rename src/{LifecycleWatcher.js => LifecycleWatcher.ts} (68%) diff --git a/src/DOMWorld.js b/src/DOMWorld.js index 33c093d251aa2..4058054624ec4 100644 --- a/src/DOMWorld.js +++ b/src/DOMWorld.js @@ -205,7 +205,7 @@ class DOMWorld { /** * @param {string} html - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options */ async setContent(html, options = {}) { const { diff --git a/src/FrameManager.js b/src/FrameManager.js index dd9ae1db325e8..35ebbda0dead0 100644 --- a/src/FrameManager.js +++ b/src/FrameManager.js @@ -89,7 +89,7 @@ class FrameManager extends EventEmitter { /** * @param {!Puppeteer.Frame} frame * @param {string} url - * @param {!{referer?: string, timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{referer?: string, timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async navigateFrame(frame, url, options = {}) { @@ -137,7 +137,7 @@ class FrameManager extends EventEmitter { /** * @param {!Puppeteer.Frame} frame - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async waitForFrameNavigation(frame, options = {}) { @@ -410,7 +410,7 @@ class Frame { /** * @param {string} url - * @param {!{referer?: string, timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{referer?: string, timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async goto(url, options) { @@ -418,7 +418,7 @@ class Frame { } /** - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async waitForNavigation(options) { @@ -503,7 +503,7 @@ class Frame { /** * @param {string} html - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options */ async setContent(html, options = {}) { return this._secondaryWorld.setContent(html, options); diff --git a/src/LifecycleWatcher.js b/src/LifecycleWatcher.ts similarity index 68% rename from src/LifecycleWatcher.js rename to src/LifecycleWatcher.ts index ab997e5996a82..d830ba1b55d1c 100644 --- a/src/LifecycleWatcher.js +++ b/src/LifecycleWatcher.ts @@ -14,18 +14,49 @@ * limitations under the License. */ -const {helper, assert} = require('./helper'); -const {Events} = require('./Events'); -const {TimeoutError} = require('./Errors'); - -class LifecycleWatcher { - /** - * @param {!Puppeteer.FrameManager} frameManager - * @param {!Puppeteer.Frame} frame - * @param {string|!Array} waitUntil - * @param {number} timeout - */ - constructor(frameManager, frame, waitUntil, timeout) { +import {helper, assert, PuppeteerEventListener} from './helper'; +import {Events} from './Events'; +import {TimeoutError} from './Errors'; + +type PuppeteerLifeCycleEvent = 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'; +type ProtocolLifeCycleEvent = 'load' | 'DOMContentLoaded' | 'networkIdle' | 'networkAlmostIdle'; + +const puppeteerToProtocolLifecycle = new Map([ + ['load', 'load'], + ['domcontentloaded', 'DOMContentLoaded'], + ['networkidle0', 'networkIdle'], + ['networkidle2', 'networkAlmostIdle'], +]); + + +export class LifecycleWatcher { + _expectedLifecycle: ProtocolLifeCycleEvent[]; + _frameManager: Puppeteer.FrameManager; + _frame: Puppeteer.Frame; + _timeout: number; + _navigationRequest?: Puppeteer.Request; + _eventListeners: PuppeteerEventListener[]; + _initialLoaderId: string; + + + _sameDocumentNavigationPromise: Promise; + _sameDocumentNavigationCompleteCallback: (x?: Error) => void; + + _lifecyclePromise: Promise; + _lifecycleCallback: () => void; + + _newDocumentNavigationPromise: Promise; + _newDocumentNavigationCompleteCallback: (x?: Error) => void; + + _terminationPromise: Promise; + _terminationCallback: (x?: Error) => void; + + _timeoutPromise: Promise; + + _maximumTimer?: NodeJS.Timeout; + _hasSameDocumentNavigation?: boolean; + + constructor(frameManager: Puppeteer.FrameManager, frame: Puppeteer.Frame, waitUntil: PuppeteerLifeCycleEvent|PuppeteerLifeCycleEvent[], timeout: number) { if (Array.isArray(waitUntil)) waitUntil = waitUntil.slice(); else if (typeof waitUntil === 'string') @@ -50,7 +81,7 @@ class LifecycleWatcher { helper.addEventListener(this._frameManager.networkManager(), Events.NetworkManager.Request, this._onRequest.bind(this)), ]; - this._sameDocumentNavigationPromise = new Promise(fulfill => { + this._sameDocumentNavigationPromise = new Promise(fulfill => { this._sameDocumentNavigationCompleteCallback = fulfill; }); @@ -69,19 +100,13 @@ class LifecycleWatcher { this._checkLifecycleComplete(); } - /** - * @param {!Puppeteer.Request} request - */ - _onRequest(request) { + _onRequest(request: Puppeteer.Request): void { if (request.frame() !== this._frame || !request.isNavigationRequest()) return; this._navigationRequest = request; } - /** - * @param {!Puppeteer.Frame} frame - */ - _onFrameDetached(frame) { + _onFrameDetached(frame: Puppeteer.Frame): void { if (this._frame === frame) { this._terminationCallback.call(null, new Error('Navigating frame was detached')); return; @@ -89,52 +114,31 @@ class LifecycleWatcher { this._checkLifecycleComplete(); } - /** - * @return {?Puppeteer.Response} - */ - navigationResponse() { + navigationResponse(): Puppeteer.Response | null { return this._navigationRequest ? this._navigationRequest.response() : null; } - /** - * @param {!Error} error - */ - _terminate(error) { + _terminate(error: Error): void { this._terminationCallback.call(null, error); } - /** - * @return {!Promise} - */ - sameDocumentNavigationPromise() { + sameDocumentNavigationPromise(): Promise { return this._sameDocumentNavigationPromise; } - /** - * @return {!Promise} - */ - newDocumentNavigationPromise() { + newDocumentNavigationPromise(): Promise { return this._newDocumentNavigationPromise; } - /** - * @return {!Promise} - */ - lifecyclePromise() { + lifecyclePromise(): Promise { return this._lifecyclePromise; } - /** - * @return {!Promise} - */ - timeoutOrTerminationPromise() { + timeoutOrTerminationPromise(): Promise { return Promise.race([this._timeoutPromise, this._terminationPromise]); } - /** - * @return {!Promise} - */ - _createTimeoutPromise() { + _createTimeoutPromise(): Promise { if (!this._timeout) return new Promise(() => {}); const errorMessage = 'Navigation timeout of ' + this._timeout + ' ms exceeded'; @@ -142,17 +146,14 @@ class LifecycleWatcher { .then(() => new TimeoutError(errorMessage)); } - /** - * @param {!Puppeteer.Frame} frame - */ - _navigatedWithinDocument(frame) { + _navigatedWithinDocument(frame: Puppeteer.Frame): void { if (frame !== this._frame) return; this._hasSameDocumentNavigation = true; this._checkLifecycleComplete(); } - _checkLifecycleComplete() { + _checkLifecycleComplete(): void { // We expect navigation to commit. if (!checkLifecycle(this._frame, this._expectedLifecycle)) return; @@ -169,7 +170,7 @@ class LifecycleWatcher { * @param {!Array} expectedLifecycle * @return {boolean} */ - function checkLifecycle(frame, expectedLifecycle) { + function checkLifecycle(frame: Puppeteer.Frame, expectedLifecycle: ProtocolLifeCycleEvent[]): boolean { for (const event of expectedLifecycle) { if (!frame._lifecycleEvents.has(event)) return false; @@ -182,17 +183,8 @@ class LifecycleWatcher { } } - dispose() { + dispose(): void { helper.removeEventListeners(this._eventListeners); clearTimeout(this._maximumTimer); } } - -const puppeteerToProtocolLifecycle = new Map([ - ['load', 'load'], - ['domcontentloaded', 'DOMContentLoaded'], - ['networkidle0', 'networkIdle'], - ['networkidle2', 'networkAlmostIdle'], -]); - -module.exports = {LifecycleWatcher}; diff --git a/src/Page.js b/src/Page.js index 77e0e564a2a3e..f1382a5b3d7d3 100644 --- a/src/Page.js +++ b/src/Page.js @@ -675,7 +675,7 @@ class Page extends EventEmitter { /** * @param {string} html - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options */ async setContent(html, options) { await this._frameManager.mainFrame().setContent(html, options); @@ -683,7 +683,7 @@ class Page extends EventEmitter { /** * @param {string} url - * @param {!{referer?: string, timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{referer?: string, timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async goto(url, options) { @@ -691,7 +691,7 @@ class Page extends EventEmitter { } /** - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async reload(options) { @@ -705,7 +705,7 @@ class Page extends EventEmitter { } /** - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async waitForNavigation(options = {}) { @@ -755,7 +755,7 @@ class Page extends EventEmitter { } /** - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async goBack(options) { @@ -763,7 +763,7 @@ class Page extends EventEmitter { } /** - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async goForward(options) { @@ -771,7 +771,7 @@ class Page extends EventEmitter { } /** - * @param {!{timeout?: number, waitUntil?: string|!Array}=} options + * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options * @return {!Promise} */ async _go(delta, options) { diff --git a/src/externs.d.ts b/src/externs.d.ts index 78ee12ea0a0d0..0fa4f3c515eea 100644 --- a/src/externs.d.ts +++ b/src/externs.d.ts @@ -18,6 +18,12 @@ declare global { export class Response extends RealResponse { } export class Request extends RealRequest { } + + /* TODO(jacktfranklin@): once DOMWorld, Page, and FrameManager are in TS + * we can remove this and instead use the type defined in LifeCycleWatcher + */ + export type PuppeteerLifeCycleEvent = 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'; + export interface ConnectionTransport { send(string); close();