From 8654d630add4c279a47272e9f60a258e44caa89c Mon Sep 17 00:00:00 2001 From: Jack Franklin Date: Thu, 30 Apr 2020 11:15:27 +0100 Subject: [PATCH] chore: migrate src/NetworkManager to TypeScript (#5774) --- src/FrameManager.ts | 14 +- src/LifecycleWatcher.ts | 8 +- src/{NetworkManager.js => NetworkManager.ts} | 429 +++++++------------ src/Page.js | 23 +- src/externs.d.ts | 4 - utils/doclint/check_public_api/index.js | 4 + 6 files changed, 180 insertions(+), 302 deletions(-) rename src/{NetworkManager.js => NetworkManager.ts} (71%) diff --git a/src/FrameManager.ts b/src/FrameManager.ts index 5a09bb60e36bb..fcd25eb7d7bfe 100644 --- a/src/FrameManager.ts +++ b/src/FrameManager.ts @@ -20,7 +20,7 @@ import {Events} from './Events'; import {ExecutionContext, EVALUATION_SCRIPT_URL} from './ExecutionContext'; import {LifecycleWatcher, PuppeteerLifeCycleEvent} from './LifecycleWatcher'; import {DOMWorld, WaitForSelectorOptions} from './DOMWorld'; -import {NetworkManager} from './NetworkManager'; +import {NetworkManager, Response} from './NetworkManager'; import {TimeoutSettings} from './TimeoutSettings'; import {CDPSession} from './Connection'; import {JSHandle, ElementHandle} from './JSHandle'; @@ -31,7 +31,7 @@ const UTILITY_WORLD_NAME = '__puppeteer_utility_world__'; export class FrameManager extends EventEmitter { _client: CDPSession; _page: Puppeteer.Page; - _networkManager: Puppeteer.NetworkManager; + _networkManager: NetworkManager; _timeoutSettings: TimeoutSettings; _frames = new Map(); _contextIdToContext = new Map(); @@ -70,11 +70,11 @@ export class FrameManager extends EventEmitter { ]); } - networkManager(): Puppeteer.NetworkManager { + networkManager(): NetworkManager { return this._networkManager; } - async navigateFrame(frame: Frame, url: string, options: {referer?: string; timeout?: number; waitUntil?: PuppeteerLifeCycleEvent|PuppeteerLifeCycleEvent[]} = {}): Promise { + async navigateFrame(frame: Frame, url: string, options: {referer?: string; timeout?: number; waitUntil?: PuppeteerLifeCycleEvent|PuppeteerLifeCycleEvent[]} = {}): Promise { assertNoLegacyNavigationOptions(options); const { referer = this._networkManager.extraHTTPHeaders()['referer'], @@ -110,7 +110,7 @@ export class FrameManager extends EventEmitter { } } - async waitForFrameNavigation(frame: Frame, options: {timeout?: number; waitUntil?: PuppeteerLifeCycleEvent|PuppeteerLifeCycleEvent[]} = {}): Promise { + async waitForFrameNavigation(frame: Frame, options: {timeout?: number; waitUntil?: PuppeteerLifeCycleEvent|PuppeteerLifeCycleEvent[]} = {}): Promise { assertNoLegacyNavigationOptions(options); const { waitUntil = ['load'], @@ -333,11 +333,11 @@ export class Frame { this._parentFrame._childFrames.add(this); } - async goto(url: string, options: {referer?: string; timeout?: number; waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]}): Promise { + async goto(url: string, options: {referer?: string; timeout?: number; waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[]}): Promise { return await this._frameManager.navigateFrame(this, url, options); } - async waitForNavigation(options: {timeout?: number; waitUntil?: PuppeteerLifeCycleEvent|PuppeteerLifeCycleEvent[]}): Promise { + async waitForNavigation(options: {timeout?: number; waitUntil?: PuppeteerLifeCycleEvent|PuppeteerLifeCycleEvent[]}): Promise { return await this._frameManager.waitForFrameNavigation(this, options); } diff --git a/src/LifecycleWatcher.ts b/src/LifecycleWatcher.ts index 9a7f071b0a7ac..fc35484c94165 100644 --- a/src/LifecycleWatcher.ts +++ b/src/LifecycleWatcher.ts @@ -18,6 +18,7 @@ import {helper, assert, PuppeteerEventListener} from './helper'; import {Events} from './Events'; import {TimeoutError} from './Errors'; import {FrameManager, Frame} from './FrameManager'; +import {Request, Response} from './NetworkManager'; export type PuppeteerLifeCycleEvent = 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'; type ProtocolLifeCycleEvent = 'load' | 'DOMContentLoaded' | 'networkIdle' | 'networkAlmostIdle'; @@ -35,7 +36,7 @@ export class LifecycleWatcher { _frameManager: FrameManager; _frame: Frame; _timeout: number; - _navigationRequest?: Puppeteer.Request; + _navigationRequest?: Request; _eventListeners: PuppeteerEventListener[]; _initialLoaderId: string; @@ -72,7 +73,6 @@ export class LifecycleWatcher { this._frame = frame; this._initialLoaderId = frame._loaderId; this._timeout = timeout; - /** @type {?Puppeteer.Request} */ this._navigationRequest = null; this._eventListeners = [ helper.addEventListener(frameManager._client, Events.CDPSession.Disconnected, () => this._terminate(new Error('Navigation failed because browser has disconnected!'))), @@ -101,7 +101,7 @@ export class LifecycleWatcher { this._checkLifecycleComplete(); } - _onRequest(request: Puppeteer.Request): void { + _onRequest(request: Request): void { if (request.frame() !== this._frame || !request.isNavigationRequest()) return; this._navigationRequest = request; @@ -115,7 +115,7 @@ export class LifecycleWatcher { this._checkLifecycleComplete(); } - navigationResponse(): Puppeteer.Response | null { + navigationResponse(): Response | null { return this._navigationRequest ? this._navigationRequest.response() : null; } diff --git a/src/NetworkManager.js b/src/NetworkManager.ts similarity index 71% rename from src/NetworkManager.js rename to src/NetworkManager.ts index fc062f8af7f28..d1b998a97b830 100644 --- a/src/NetworkManager.js +++ b/src/NetworkManager.ts @@ -13,44 +13,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -const EventEmitter = require('events'); -const {helper, assert, debugError} = require('./helper'); -const {Events} = require('./Events'); -// CDPSession is used only as a typedef -// eslint-disable-next-line no-unused-vars -const {CDPSession} = require('./Connection'); -// used only as a typedef -// eslint-disable-next-line no-unused-vars -const {Frame, FrameManager} = require('./FrameManager'); - -class NetworkManager extends EventEmitter { - /** - * @param {!CDPSession} client - * @param {!FrameManager} frameManager - */ - constructor(client, ignoreHTTPSErrors, frameManager) { +import * as EventEmitter from 'events'; +import {helper, assert, debugError} from './helper'; +import {Events} from './Events'; +import {CDPSession} from './Connection'; +import {FrameManager, Frame} from './FrameManager'; + +interface Credentials { + username: string; + password: string; +} + +export class NetworkManager extends EventEmitter { + _client: CDPSession; + _ignoreHTTPSErrors: boolean; + _frameManager: FrameManager; + _requestIdToRequest = new Map(); + _requestIdToRequestWillBeSentEvent = new Map(); + _extraHTTPHeaders: Record = {}; + _offline = false; + _credentials?: Credentials = null; + _attemptedAuthentications = new Set(); + _userRequestInterceptionEnabled = false; + _protocolRequestInterceptionEnabled = false; + _userCacheDisabled = false; + _requestIdToInterceptionId = new Map(); + + constructor(client: CDPSession, ignoreHTTPSErrors: boolean, frameManager: FrameManager) { super(); this._client = client; this._ignoreHTTPSErrors = ignoreHTTPSErrors; this._frameManager = frameManager; - /** @type {!Map} */ - this._requestIdToRequest = new Map(); - /** @type {!Map} */ - this._requestIdToRequestWillBeSentEvent = new Map(); - /** @type {!Object} */ - this._extraHTTPHeaders = {}; - - this._offline = false; - - /** @type {?{username: string, password: string}} */ - this._credentials = null; - /** @type {!Set} */ - this._attemptedAuthentications = new Set(); - this._userRequestInterceptionEnabled = false; - this._protocolRequestInterceptionEnabled = false; - this._userCacheDisabled = false; - /** @type {!Map} */ - this._requestIdToInterceptionId = new Map(); this._client.on('Fetch.requestPaused', this._onRequestPaused.bind(this)); this._client.on('Fetch.authRequired', this._onAuthRequired.bind(this)); @@ -61,24 +54,18 @@ class NetworkManager extends EventEmitter { this._client.on('Network.loadingFailed', this._onLoadingFailed.bind(this)); } - async initialize() { + async initialize(): Promise { await this._client.send('Network.enable'); if (this._ignoreHTTPSErrors) await this._client.send('Security.setIgnoreCertificateErrors', {ignore: true}); } - /** - * @param {?{username: string, password: string}} credentials - */ - async authenticate(credentials) { + async authenticate(credentials?: Credentials): Promise { this._credentials = credentials; await this._updateProtocolRequestInterception(); } - /** - * @param {!Object} extraHTTPHeaders - */ - async setExtraHTTPHeaders(extraHTTPHeaders) { + async setExtraHTTPHeaders(extraHTTPHeaders: Record): Promise { this._extraHTTPHeaders = {}; for (const key of Object.keys(extraHTTPHeaders)) { const value = extraHTTPHeaders[key]; @@ -88,17 +75,11 @@ class NetworkManager extends EventEmitter { await this._client.send('Network.setExtraHTTPHeaders', {headers: this._extraHTTPHeaders}); } - /** - * @return {!Object} - */ - extraHTTPHeaders() { + extraHTTPHeaders(): Record { return Object.assign({}, this._extraHTTPHeaders); } - /** - * @param {boolean} value - */ - async setOfflineMode(value) { + async setOfflineMode(value: boolean): Promise { if (this._offline === value) return; this._offline = value; @@ -111,30 +92,21 @@ class NetworkManager extends EventEmitter { }); } - /** - * @param {string} userAgent - */ - async setUserAgent(userAgent) { + async setUserAgent(userAgent: string): Promise { await this._client.send('Network.setUserAgentOverride', {userAgent}); } - /** - * @param {boolean} enabled - */ - async setCacheEnabled(enabled) { + async setCacheEnabled(enabled: boolean): Promise { this._userCacheDisabled = !enabled; await this._updateProtocolCacheDisabled(); } - /** - * @param {boolean} value - */ - async setRequestInterception(value) { + async setRequestInterception(value: boolean): Promise { this._userRequestInterceptionEnabled = value; await this._updateProtocolRequestInterception(); } - async _updateProtocolRequestInterception() { + async _updateProtocolRequestInterception(): Promise { const enabled = this._userRequestInterceptionEnabled || !!this._credentials; if (enabled === this._protocolRequestInterceptionEnabled) return; @@ -155,16 +127,13 @@ class NetworkManager extends EventEmitter { } } - async _updateProtocolCacheDisabled() { + async _updateProtocolCacheDisabled(): Promise { await this._client.send('Network.setCacheDisabled', { cacheDisabled: this._userCacheDisabled || this._protocolRequestInterceptionEnabled }); } - /** - * @param {!Protocol.Network.requestWillBeSentPayload} event - */ - _onRequestWillBeSent(event) { + _onRequestWillBeSent(event: Protocol.Network.requestWillBeSentPayload): void { // Request interception doesn't happen for data URLs with Network Service. if (this._protocolRequestInterceptionEnabled && !event.request.url.startsWith('data:')) { const requestId = event.requestId; @@ -183,9 +152,12 @@ class NetworkManager extends EventEmitter { /** * @param {!Protocol.Fetch.authRequiredPayload} event */ - _onAuthRequired(event) { - /** @type {"Default"|"CancelAuth"|"ProvideCredentials"} */ - let response = 'Default'; + _onAuthRequired(event: Protocol.Fetch.authRequiredPayload): void { + /* TODO(jacktfranklin): This is defined in protocol.d.ts but not + * in an easily referrable way - we should look at exposing it. + */ + type AuthResponse = 'Default'|'CancelAuth'|'ProvideCredentials'; + let response: AuthResponse = 'Default'; if (this._attemptedAuthentications.has(event.requestId)) { response = 'CancelAuth'; } else if (this._credentials) { @@ -199,10 +171,7 @@ class NetworkManager extends EventEmitter { }).catch(debugError); } - /** - * @param {!Protocol.Fetch.requestPausedPayload} event - */ - _onRequestPaused(event) { + _onRequestPaused(event: Protocol.Fetch.requestPausedPayload): void { if (!this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) { this._client.send('Fetch.continueRequest', { requestId: event.requestId @@ -220,11 +189,7 @@ class NetworkManager extends EventEmitter { } } - /** - * @param {!Protocol.Network.requestWillBeSentPayload} event - * @param {?string} interceptionId - */ - _onRequest(event, interceptionId) { + _onRequest(event: Protocol.Network.requestWillBeSentPayload, interceptionId?: string): void { let redirectChain = []; if (event.redirectResponse) { const request = this._requestIdToRequest.get(event.requestId); @@ -240,21 +205,13 @@ class NetworkManager extends EventEmitter { this.emit(Events.NetworkManager.Request, request); } - - /** - * @param {!Protocol.Network.requestServedFromCachePayload} event - */ - _onRequestServedFromCache(event) { + _onRequestServedFromCache(event: Protocol.Network.requestServedFromCachePayload): void { const request = this._requestIdToRequest.get(event.requestId); if (request) request._fromMemoryCache = true; } - /** - * @param {!Request} request - * @param {!Protocol.Network.Response} responsePayload - */ - _handleRequestRedirect(request, responsePayload) { + _handleRequestRedirect(request: Request, responsePayload: Protocol.Network.Response): void { const response = new Response(this._client, request, responsePayload); request._response = response; request._redirectChain.push(request); @@ -265,10 +222,7 @@ class NetworkManager extends EventEmitter { this.emit(Events.NetworkManager.RequestFinished, request); } - /** - * @param {!Protocol.Network.responseReceivedPayload} event - */ - _onResponseReceived(event) { + _onResponseReceived(event: Protocol.Network.responseReceivedPayload): void { const request = this._requestIdToRequest.get(event.requestId); // FileUpload sends a response without a matching request. if (!request) @@ -278,10 +232,7 @@ class NetworkManager extends EventEmitter { this.emit(Events.NetworkManager.Response, response); } - /** - * @param {!Protocol.Network.loadingFinishedPayload} event - */ - _onLoadingFinished(event) { + _onLoadingFinished(event: Protocol.Network.loadingFinishedPayload): void { const request = this._requestIdToRequest.get(event.requestId); // For certain requestIds we never receive requestWillBeSent event. // @see https://crbug.com/750469 @@ -297,10 +248,7 @@ class NetworkManager extends EventEmitter { this.emit(Events.NetworkManager.RequestFinished, request); } - /** - * @param {!Protocol.Network.loadingFailedPayload} event - */ - _onLoadingFailed(event) { + _onLoadingFailed(event: Protocol.Network.loadingFailedPayload): void { const request = this._requestIdToRequest.get(event.requestId); // For certain requestIds we never receive requestWillBeSent event. // @see https://crbug.com/750469 @@ -316,105 +264,83 @@ class NetworkManager extends EventEmitter { } } -class Request { - /** - * @param {!CDPSession} client - * @param {?Frame} frame - * @param {string} interceptionId - * @param {boolean} allowInterception - * @param {!Protocol.Network.requestWillBeSentPayload} event - * @param {!Array} redirectChain - */ - constructor(client, frame, interceptionId, allowInterception, event, redirectChain) { +export class Request { + _client: CDPSession; + _requestId: string; + _isNavigationRequest: boolean; + _interceptionId: string; + _allowInterception: boolean; + _interceptionHandled = false; + _response: Response | null = null; + _failureText = null; + _url: string; + _resourceType: string; + + _method: string; + _postData?: string; + _headers: Record = {}; + _frame: Frame; + + _redirectChain: Request[]; + _fromMemoryCache = false; + + constructor(client: CDPSession, frame: Frame, interceptionId: string, allowInterception: boolean, event: Protocol.Network.requestWillBeSentPayload, redirectChain: Request[]) { this._client = client; this._requestId = event.requestId; this._isNavigationRequest = event.requestId === event.loaderId && event.type === 'Document'; this._interceptionId = interceptionId; this._allowInterception = allowInterception; - this._interceptionHandled = false; - this._response = null; - this._failureText = null; - this._url = event.request.url; this._resourceType = event.type.toLowerCase(); this._method = event.request.method; this._postData = event.request.postData; - this._headers = {}; this._frame = frame; this._redirectChain = redirectChain; + for (const key of Object.keys(event.request.headers)) this._headers[key.toLowerCase()] = event.request.headers[key]; - - this._fromMemoryCache = false; } - /** - * @return {string} - */ - url() { + url(): string { return this._url; } - /** - * @return {string} - */ - resourceType() { + resourceType(): string { return this._resourceType; } - /** - * @return {string} - */ - method() { + method(): string { return this._method; } - /** - * @return {string|undefined} - */ - postData() { + postData(): string | undefined { return this._postData; } - /** - * @return {!Object} - */ - headers() { + headers(): Record { return this._headers; } - /** - * @return {?Response} - */ - response() { + response(): Response | null { return this._response; } - /** - * @return {?Frame} - */ - frame() { + frame(): Frame | null { return this._frame; } - /** - * @return {boolean} - */ - isNavigationRequest() { + isNavigationRequest(): boolean { return this._isNavigationRequest; } - /** - * @return {!Array} - */ - redirectChain() { + redirectChain(): Request[] { return this._redirectChain.slice(); } /** * @return {?{errorText: string}} */ - failure() { + failure(): {errorText: string} | null { if (!this._failureText) return null; return { @@ -422,10 +348,7 @@ class Request { }; } - /** - * @param {!{url?: string, method?:string, postData?: string, headers?: !Object}} overrides - */ - async continue(overrides = {}) { + async continue(overrides: {url?: string; method?: string; postData?: string; headers?: Record} = {}): Promise { // Request interception is not supported for data: urls. if (this._url.startsWith('data:')) return; @@ -451,10 +374,12 @@ class Request { }); } - /** - * @param {!{status: number, headers: Object, contentType: string, body: (string|Buffer)}} response - */ - async respond(response) { + async respond(response: { + status: number; + headers: Record; + contentType: string; + body: string|Buffer; + }): Promise { // Mocking responses for dataURL requests is not currently supported. if (this._url.startsWith('data:')) return; @@ -462,10 +387,9 @@ class Request { assert(!this._interceptionHandled, 'Request is already handled!'); this._interceptionHandled = true; - const responseBody = response.body && helper.isString(response.body) ? Buffer.from(/** @type {string} */(response.body)) : /** @type {?Buffer} */(response.body || null); + const responseBody: Buffer | null = response.body && helper.isString(response.body) ? Buffer.from(response.body) : response.body as Buffer || null; - /** @type {!Object} */ - const responseHeaders = {}; + const responseHeaders: Record = {}; if (response.headers) { for (const header of Object.keys(response.headers)) responseHeaders[header.toLowerCase()] = response.headers[header]; @@ -488,10 +412,7 @@ class Request { }); } - /** - * @param {string=} errorCode - */ - async abort(errorCode = 'failed') { + async abort(errorCode: ErrorCode = 'failed'): Promise { // Request interception is not supported for data: urls. if (this._url.startsWith('data:')) return; @@ -511,7 +432,9 @@ class Request { } } -const errorReasons = { +type ErrorCode = 'aborted' | 'accessdenied' | 'addressunreachable' | 'blockedbyclient' | 'blockedbyresponse' | 'connectionaborted' | 'connectionclosed' | 'connectionfailed' | 'connectionrefused' | 'connectionreset' | 'internetdisconnected' | 'namenotresolved' | 'timedout' | 'failed'; + +const errorReasons: Record = { 'aborted': 'Aborted', 'accessdenied': 'AccessDenied', 'addressunreachable': 'AddressUnreachable', @@ -526,18 +449,31 @@ const errorReasons = { 'namenotresolved': 'NameNotResolved', 'timedout': 'TimedOut', 'failed': 'Failed', -}; +} as const; -class Response { - /** - * @param {!CDPSession} client - * @param {!Request} request - * @param {!Protocol.Network.Response} responsePayload - */ - constructor(client, request, responsePayload) { +interface RemoteAddress { + ip: string; + port: number; +} + +export class Response { + _client: CDPSession; + _request: Request; + _contentPromise: Promise | null = null; + _bodyLoadedPromise: Promise; + _bodyLoadedPromiseFulfill: (x: boolean) => void; + _remoteAddress: RemoteAddress; + _status: number; + _statusText: string; + _url: string; + _fromDiskCache: boolean; + _fromServiceWorker: boolean; + _headers: Record = {}; + _securityDetails: SecurityDetails | null; + + constructor(client: CDPSession, request: Request, responsePayload: Protocol.Network.Response) { this._client = client; this._request = request; - this._contentPromise = null; this._bodyLoadedPromise = new Promise(fulfill => { this._bodyLoadedPromiseFulfill = fulfill; @@ -552,65 +488,40 @@ class Response { this._url = request.url(); this._fromDiskCache = !!responsePayload.fromDiskCache; this._fromServiceWorker = !!responsePayload.fromServiceWorker; - this._headers = {}; for (const key of Object.keys(responsePayload.headers)) this._headers[key.toLowerCase()] = responsePayload.headers[key]; this._securityDetails = responsePayload.securityDetails ? new SecurityDetails(responsePayload.securityDetails) : null; } - /** - * @return {{ip: string, port: number}} - */ - remoteAddress() { + remoteAddress(): RemoteAddress { return this._remoteAddress; } - /** - * @return {string} - */ - url() { + url(): string { return this._url; } - /** - * @return {boolean} - */ - ok() { + ok(): boolean { return this._status === 0 || (this._status >= 200 && this._status <= 299); } - /** - * @return {number} - */ - status() { + status(): number { return this._status; } - /** - * @return {string} - */ - statusText() { + statusText(): string { return this._statusText; } - /** - * @return {!Object} - */ - headers() { + headers(): Record { return this._headers; } - /** - * @return {?SecurityDetails} - */ - securityDetails() { + securityDetails(): SecurityDetails | null { return this._securityDetails; } - /** - * @return {!Promise} - */ - buffer() { + buffer(): Promise { if (!this._contentPromise) { this._contentPromise = this._bodyLoadedPromise.then(async error => { if (error) @@ -624,104 +535,70 @@ class Response { return this._contentPromise; } - /** - * @return {!Promise} - */ - async text() { + async text(): Promise { const content = await this.buffer(); return content.toString('utf8'); } - /** - * @return {!Promise} - */ - async json() { + async json(): Promise { const content = await this.text(); return JSON.parse(content); } - /** - * @return {!Request} - */ - request() { + request(): Request { return this._request; } - /** - * @return {boolean} - */ - fromCache() { + fromCache(): boolean { return this._fromDiskCache || this._request._fromMemoryCache; } - /** - * @return {boolean} - */ - fromServiceWorker() { + fromServiceWorker(): boolean { return this._fromServiceWorker; } - /** - * @return {?Frame} - */ - frame() { + frame(): Frame | null { return this._request.frame(); } } -class SecurityDetails { - /** - * @param {!Protocol.Network.SecurityDetails} securityPayload - */ - constructor(securityPayload) { - this._subjectName = securityPayload['subjectName']; - this._issuer = securityPayload['issuer']; - this._validFrom = securityPayload['validFrom']; - this._validTo = securityPayload['validTo']; - this._protocol = securityPayload['protocol']; +export class SecurityDetails { + _subjectName: string; + _issuer: string; + _validFrom: number; + _validTo: number; + _protocol: string; + + constructor(securityPayload: Protocol.Network.SecurityDetails) { + this._subjectName = securityPayload.subjectName; + this._issuer = securityPayload.issuer; + this._validFrom = securityPayload.validFrom; + this._validTo = securityPayload.validTo; + this._protocol = securityPayload.protocol; } - /** - * @return {string} - */ - subjectName() { + subjectName(): string { return this._subjectName; } - /** - * @return {string} - */ - issuer() { + issuer(): string { return this._issuer; } - /** - * @return {number} - */ - validFrom() { + validFrom(): number { return this._validFrom; } - /** - * @return {number} - */ - validTo() { + validTo(): number { return this._validTo; } - /** - * @return {string} - */ - protocol() { + protocol(): string { return this._protocol; } } -/** - * @param {Object} headers - * @return {!Array<{name: string, value: string}>} - */ -function headersArray(headers) { +function headersArray(headers: Record): Array<{name: string; value: string}> { const result = []; for (const name in headers) { if (!Object.is(headers[name], undefined)) @@ -795,6 +672,4 @@ const STATUS_TEXTS = { '508': 'Loop Detected', '510': 'Not Extended', '511': 'Network Authentication Required', -}; - -module.exports = {Request, Response, NetworkManager, SecurityDetails}; +} as const; diff --git a/src/Page.js b/src/Page.js index b8bbb3478db51..2b69916cb63da 100644 --- a/src/Page.js +++ b/src/Page.js @@ -40,6 +40,9 @@ const {Target} = require('./Target'); // Import used as typedef // eslint-disable-next-line no-unused-vars const {createJSHandle, JSHandle, ElementHandle} = require('./JSHandle'); +// Import used as typedef +// eslint-disable-next-line no-unused-vars +const {Request: PuppeteerRequest, Response: PuppeteerResponse} = require('./NetworkManager'); const {Accessibility} = require('./Accessibility'); const {TimeoutSettings} = require('./TimeoutSettings'); @@ -692,7 +695,7 @@ class Page extends EventEmitter { /** * @param {string} url * @param {!{referer?: string, timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options - * @return {!Promise} + * @return {!Promise} */ async goto(url, options) { return await this._frameManager.mainFrame().goto(url, options); @@ -700,7 +703,7 @@ class Page extends EventEmitter { /** * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options - * @return {!Promise} + * @return {!Promise} */ async reload(options) { const result = await Promise.all([ @@ -708,13 +711,13 @@ class Page extends EventEmitter { this._client.send('Page.reload') ]); - const response = /** @type Puppeteer.Response */ (result[0]); + const response = /** @type PuppeteerResponse */ (result[0]); return response; } /** * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options - * @return {!Promise} + * @return {!Promise} */ async waitForNavigation(options = {}) { return await this._frameManager.mainFrame().waitForNavigation(options); @@ -729,7 +732,7 @@ class Page extends EventEmitter { /** * @param {(string|Function)} urlOrPredicate * @param {!{timeout?: number}=} options - * @return {!Promise} + * @return {!Promise} */ async waitForRequest(urlOrPredicate, options = {}) { const { @@ -747,7 +750,7 @@ class Page extends EventEmitter { /** * @param {(string|Function)} urlOrPredicate * @param {!{timeout?: number}=} options - * @return {!Promise} + * @return {!Promise} */ async waitForResponse(urlOrPredicate, options = {}) { const { @@ -764,7 +767,7 @@ class Page extends EventEmitter { /** * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options - * @return {!Promise} + * @return {!Promise} */ async goBack(options) { return this._go(-1, options); @@ -772,7 +775,7 @@ class Page extends EventEmitter { /** * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options - * @return {!Promise} + * @return {!Promise} */ async goForward(options) { return this._go(+1, options); @@ -780,7 +783,7 @@ class Page extends EventEmitter { /** * @param {!{timeout?: number, waitUntil?: !Puppeteer.PuppeteerLifeCycleEvent|!Array}=} options - * @return {!Promise} + * @return {!Promise} */ async _go(delta, options) { const history = await this._client.send('Page.getNavigationHistory'); @@ -791,7 +794,7 @@ class Page extends EventEmitter { this.waitForNavigation(options), this._client.send('Page.navigateToHistoryEntry', {entryId: entry.id}), ]); - const response = /** @type Puppeteer.Response */ (result[0]); + const response = /** @type PuppeteerResponse */ (result[0]); return response; } diff --git a/src/externs.d.ts b/src/externs.d.ts index 5a7feb6f2e63d..842b3032cd74f 100644 --- a/src/externs.d.ts +++ b/src/externs.d.ts @@ -1,12 +1,8 @@ import {Page as RealPage} from './Page.js'; -import { NetworkManager as RealNetworkManager, Request as RealRequest, Response as RealResponse } from './NetworkManager.js'; import * as child_process from 'child_process'; declare global { module Puppeteer { - export class NetworkManager extends RealNetworkManager {} export class Page extends RealPage { } - export class Response extends RealResponse { } - export class Request extends RealRequest { } /* TODO(jacktfranklin@): once DOMWorld, Page, and FrameManager are in TS diff --git a/utils/doclint/check_public_api/index.js b/utils/doclint/check_public_api/index.js index 1df371919f4a4..28f1199704478 100644 --- a/utils/doclint/check_public_api/index.js +++ b/utils/doclint/check_public_api/index.js @@ -307,6 +307,10 @@ function compareDocumentations(actual, expected) { actualName: 'Object', expectedName: 'WaitForSelectorOptions' }], + ['Method Request.abort() errorCode', { + actualName: 'string', + expectedName: 'ErrorCode' + }], ['Method Frame.goto() options.waitUntil', { actualName: '"load"|"domcontentloaded"|"networkidle0"|"networkidle2"|Array', expectedName: '"load"|"domcontentloaded"|"networkidle0"|"networkidle2"|Array'