From ba7624a6df9c1cb24c7c9bb5fb48e27deaaf3098 Mon Sep 17 00:00:00 2001 From: Jack Franklin Date: Mon, 6 Jul 2020 11:34:55 +0100 Subject: [PATCH] chore(docs): migrate & document all Page events (#6154) * chore(docs): migrate & document all Page events Rather than a generic `Events.ts` file we can instead document events as an enum within each individual class. It's easier to document and work with, and it's clearer where events originate from. --- new-docs/puppeteer.md | 2 +- new-docs/puppeteer.page.md | 4 +- new-docs/puppeteer.pageemittedevents.md | 17 +++ src/common/Page.ts | 166 ++++++++++++++++++++---- src/common/Target.ts | 7 +- 5 files changed, 168 insertions(+), 28 deletions(-) diff --git a/new-docs/puppeteer.md b/new-docs/puppeteer.md index 4f955cbd..64bee969 100644 --- a/new-docs/puppeteer.md +++ b/new-docs/puppeteer.md @@ -27,7 +27,7 @@ | [JSHandle](./puppeteer.jshandle.md) | Represents an in-page JavaScript object. JSHandles can be created with the [page.evaluateHandle](./puppeteer.page.evaluatehandle.md) method. | | [Keyboard](./puppeteer.keyboard.md) | Keyboard provides an api for managing a virtual keyboard. The high level api is [Keyboard.type()](./puppeteer.keyboard.type.md), which takes raw characters and generates proper keydown, keypress/input, and keyup events on your page. | | [Mouse](./puppeteer.mouse.md) | The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport. | -| [Page](./puppeteer.page.md) | Page provides methods to interact with a single tab or \[extension background page\](https://developer.chrome.com/extensions/background\_pages) in Chromium. One \[Browser\] instance might have multiple \[Page\] instances. | +| [Page](./puppeteer.page.md) | Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. | | [Puppeteer](./puppeteer.puppeteer.md) | The main Puppeteer class Puppeteer module provides a method to launch a browser instance. | | [SecurityDetails](./puppeteer.securitydetails.md) | The SecurityDetails class represents the security details of a response that was received over a secure connection. | | [Target](./puppeteer.target.md) | | diff --git a/new-docs/puppeteer.page.md b/new-docs/puppeteer.page.md index d8a945ef..2e4705d0 100644 --- a/new-docs/puppeteer.page.md +++ b/new-docs/puppeteer.page.md @@ -4,7 +4,7 @@ ## Page class -Page provides methods to interact with a single tab or \[extension background page\](https://developer.chrome.com/extensions/background\_pages) in Chromium. One \[Browser\] instance might have multiple \[Page\] instances. +Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. Signature: @@ -15,6 +15,8 @@ export declare class Page extends EventEmitter ## Remarks +One Browser instance might have multiple Page instances. + The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `Page` class. ## Example 1 diff --git a/new-docs/puppeteer.pageemittedevents.md b/new-docs/puppeteer.pageemittedevents.md index 56c6c2f5..5dce135c 100644 --- a/new-docs/puppeteer.pageemittedevents.md +++ b/new-docs/puppeteer.pageemittedevents.md @@ -16,5 +16,22 @@ export declare const enum PageEmittedEvents | Member | Value | Description | | --- | --- | --- | +| Close | "close" | Emitted when the page closes. | +| Console | "console" | Emitted when JavaScript within the page calls one of console API methods, e.g. console.log or console.dir. Also emitted if the page throws an error or a warning. | +| Dialog | "dialog" | Emitted when a JavaScript dialog appears, such as alert, prompt, confirm or beforeunload. Puppeteer can respond to the dialog via [Dialog.accept()](./puppeteer.dialog.accept.md) or [Dialog.dismiss()](./puppeteer.dialog.dismiss.md). | +| DOMContentLoaded | "domcontentloaded" | Emitted when the JavaScript [DOMContentLoaded](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) event is dispatched. | +| Error | "error" | Emitted when the page crashes. Will contain an Error. | +| FrameAttached | "frameattached" | Emitted when a frame is attached. Will contain a [Frame](./puppeteer.frame.md). | +| FrameDetached | "framedetached" | Emitted when a frame is detached. Will contain a [Frame](./puppeteer.frame.md). | +| FrameNavigated | "framenavigated" | Emitted when a frame is navigated to a new URL. Will contain a [Frame](./puppeteer.frame.md). | +| Load | "load" | Emitted when the JavaScript [load](https://developer.mozilla.org/en-US/docs/Web/Events/load) event is dispatched. | +| Metrics | "metrics" | Emitted when the JavaScript code makes a call to console.timeStamp. For the list of metrics see [page.metrics](./puppeteer.page.metrics.md). | +| PageError | "pageerror" | Emitted when an uncaught exception happens within the page. Contains an Error. | +| Popup | "popup" | Emitted when the page opens a new tab or window.Contains a [Page](./puppeteer.page.md) corresponding to the popup window. | +| Request | "request" | Emitted when a page issues a request and contains a [HTTPRequest](./puppeteer.httprequest.md). | +| RequestFailed | "requestfailed" | Emitted when a request fails, for example by timing out.Contains a [HTTPRequest](./puppeteer.httprequest.md). | +| RequestFinished | "requestfinished" | Emitted when a request finishes successfully. Contains a [HTTPRequest](./puppeteer.httprequest.md). | +| Response | "response" | Emitted when a response is received. Contains a [HTTPResponse](./puppeteer.httpresponse.md). | | WorkerCreated | "workercreated" | Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned by the page. | +| WorkerDestroyed | "workerdestroyed" | Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is destroyed by the page. | diff --git a/src/common/Page.ts b/src/common/Page.ts index 6e3cc49b..10237ea7 100644 --- a/src/common/Page.ts +++ b/src/common/Page.ts @@ -197,13 +197,134 @@ type VisionDeficiency = * @public */ export const enum PageEmittedEvents { + /** Emitted when the page closes. */ + Close = 'close', + /** + * Emitted when JavaScript within the page calls one of console API methods, + * e.g. `console.log` or `console.dir`. Also emitted if the page throws an + * error or a warning. + * + * @remarks + * + * A `console` event provides a {@link ConsoleMessage} representing the + * console message that was logged. + * + * @example + * An example of handling `console` event: + * ```js + * page.on('console', msg => { + * for (let i = 0; i < msg.args().length; ++i) + * console.log(`${i}: ${msg.args()[i]}`); + * }); + * page.evaluate(() => console.log('hello', 5, {foo: 'bar'})); + * ``` + */ + Console = 'console', + /** + * Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, + * `confirm` or `beforeunload`. Puppeteer can respond to the dialog via + * {@link Dialog.accept} or {@link Dialog.dismiss}. + */ + Dialog = 'dialog', + /** + * Emitted when the JavaScript + * {@link https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded | DOMContentLoaded } event is dispatched. + */ + DOMContentLoaded = 'domcontentloaded', + /** + * Emitted when the page crashes. Will contain an `Error`. + */ + Error = 'error', + /** Emitted when a frame is attached. Will contain a {@link Frame}. */ + FrameAttached = 'frameattached', + /** Emitted when a frame is detached. Will contain a {@link Frame}. */ + FrameDetached = 'framedetached', + /** Emitted when a frame is navigated to a new URL. Will contain a {@link Frame}. */ + FrameNavigated = 'framenavigated', + /** + * Emitted when the JavaScript + * {@link https://developer.mozilla.org/en-US/docs/Web/Events/load | load} + * event is dispatched. + */ + Load = 'load', + /** + * Emitted when the JavaScript code makes a call to `console.timeStamp`. For + * the list of metrics see {@link Page.metrics | page.metrics}. + * + * @remarks + * Contains an object with two properties: + * - `title`: the title passed to `console.timeStamp` + * - `metrics`: objec containing metrics as key/value pairs. The values will + * be `number`s. + */ + Metrics = 'metrics', + /** + * Emitted when an uncaught exception happens within the page. + * Contains an `Error`. + */ + PageError = 'pageerror', + /** + * Emitted when the page opens a new tab or window. + * + * Contains a {@link Page} corresponding to the popup window. + * + * @example + * + * ```js + * const [popup] = await Promise.all([ + * new Promise(resolve => page.once('popup', resolve)), + * page.click('a[target=_blank]'), + * ]); + * ``` + * + * ```js + * const [popup] = await Promise.all([ + * new Promise(resolve => page.once('popup', resolve)), + * page.evaluate(() => window.open('https://example.com')), + * ]); + * ``` + */ + Popup = 'popup', + /** + * Emitted when a page issues a request and contains a {@link HTTPRequest}. + * + * @remarks + * The object is readonly. See {@Page.setRequestInterception} for intercepting + * and mutating requests. + */ + Request = 'request', + /** + * Emitted when a request fails, for example by timing out. + * + * Contains a {@link HTTPRequest}. + * + * @remarks + * + * NOTE: HTTP Error responses, such as 404 or 503, are still successful + * responses from HTTP standpoint, so request will complete with + * `requestfinished` event and not with `requestfailed`. + */ + RequestFailed = 'requestfailed', + /** + * Emitted when a request finishes successfully. Contains a {@link HTTPRequest}. + */ + RequestFinished = 'requestfinished', + /** + * Emitted when a response is received. Contains a {@link HTTPResponse}. + */ + Response = 'response', /** * Emitted when a dedicated * {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API | WebWorker} * is spawned by the page. - * @eventProperty */ WorkerCreated = 'workercreated', + /** + * Emitted when a dedicated + * {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API | WebWorker} + * is destroyed by the page. + */ + WorkerDestroyed = 'workerdestroyed', } class ScreenshotTaskQueue { @@ -223,12 +344,13 @@ class ScreenshotTaskQueue { } /** - * Page provides methods to interact with a single tab or [extension background - * page](https://developer.chrome.com/extensions/background_pages) in Chromium. - * One [Browser] instance might have multiple [Page] instances. + * Page provides methods to interact with a single tab or + * {@link https://developer.chrome.com/extensions/background_pages | extension background page} in Chromium. * * @remarks * + * One Browser instance might have multiple Page instances. + * * @example * This example creates a page, navigates it to a URL, and then * saves a screenshot: * ```js @@ -243,7 +365,7 @@ class ScreenshotTaskQueue { * })(); * ``` * - * The Page class extends from Puppeteer's {@link EventEmitter } class and will + * The Page class extends from Puppeteer's {@link EventEmitter} class and will * emit various events which are documented in the {@link PageEmittedEvents} enum. * * @example @@ -349,39 +471,39 @@ export class Page extends EventEmitter { client.on('Target.detachedFromTarget', (event) => { const worker = this._workers.get(event.sessionId); if (!worker) return; - this.emit(Events.Page.WorkerDestroyed, worker); + this.emit(PageEmittedEvents.WorkerDestroyed, worker); this._workers.delete(event.sessionId); }); this._frameManager.on(Events.FrameManager.FrameAttached, (event) => - this.emit(Events.Page.FrameAttached, event) + this.emit(PageEmittedEvents.FrameAttached, event) ); this._frameManager.on(Events.FrameManager.FrameDetached, (event) => - this.emit(Events.Page.FrameDetached, event) + this.emit(PageEmittedEvents.FrameDetached, event) ); this._frameManager.on(Events.FrameManager.FrameNavigated, (event) => - this.emit(Events.Page.FrameNavigated, event) + this.emit(PageEmittedEvents.FrameNavigated, event) ); const networkManager = this._frameManager.networkManager(); networkManager.on(Events.NetworkManager.Request, (event) => - this.emit(Events.Page.Request, event) + this.emit(PageEmittedEvents.Request, event) ); networkManager.on(Events.NetworkManager.Response, (event) => - this.emit(Events.Page.Response, event) + this.emit(PageEmittedEvents.Response, event) ); networkManager.on(Events.NetworkManager.RequestFailed, (event) => - this.emit(Events.Page.RequestFailed, event) + this.emit(PageEmittedEvents.RequestFailed, event) ); networkManager.on(Events.NetworkManager.RequestFinished, (event) => - this.emit(Events.Page.RequestFinished, event) + this.emit(PageEmittedEvents.RequestFinished, event) ); this._fileChooserInterceptors = new Set(); client.on('Page.domContentEventFired', () => - this.emit(Events.Page.DOMContentLoaded) + this.emit(PageEmittedEvents.DOMContentLoaded) ); - client.on('Page.loadEventFired', () => this.emit(Events.Page.Load)); + client.on('Page.loadEventFired', () => this.emit(PageEmittedEvents.Load)); client.on('Runtime.consoleAPICalled', (event) => this._onConsoleAPI(event)); client.on('Runtime.bindingCalled', (event) => this._onBindingCalled(event)); client.on('Page.javascriptDialogOpening', (event) => this._onDialog(event)); @@ -393,7 +515,7 @@ export class Page extends EventEmitter { client.on('Log.entryAdded', (event) => this._onLogEntryAdded(event)); client.on('Page.fileChooserOpened', (event) => this._onFileChooser(event)); this._target._isClosedPromise.then(() => { - this.emit(Events.Page.Close); + this.emit(PageEmittedEvents.Close); this._closed = true; }); } @@ -522,7 +644,7 @@ export class Page extends EventEmitter { if (args) args.map((arg) => helper.releaseObject(this._client, arg)); if (source !== 'worker') this.emit( - Events.Page.Console, + PageEmittedEvents.Console, new ConsoleMessage(level, text, [], { url, lineNumber }) ); } @@ -1001,7 +1123,7 @@ export class Page extends EventEmitter { } private _emitMetrics(event: Protocol.Performance.metricsPayload): void { - this.emit(Events.Page.Metrics, { + this.emit(PageEmittedEvents.Metrics, { title: event.title, metrics: this._buildMetricsObject(event.metrics), }); @@ -1023,7 +1145,7 @@ export class Page extends EventEmitter { const message = helper.getExceptionMessage(exceptionDetails); const err = new Error(message); err.stack = ''; // Don't report clientside error with a node stack attached - this.emit(Events.Page.PageError, err); + this.emit(PageEmittedEvents.PageError, err); } private async _onConsoleAPI( @@ -1116,7 +1238,7 @@ export class Page extends EventEmitter { args: JSHandle[], stackTrace?: Protocol.Runtime.StackTrace ): void { - if (!this.listenerCount(Events.Page.Console)) { + if (!this.listenerCount(PageEmittedEvents.Console)) { args.forEach((arg) => arg.dispose()); return; } @@ -1140,7 +1262,7 @@ export class Page extends EventEmitter { args, location ); - this.emit(Events.Page.Console, message); + this.emit(PageEmittedEvents.Console, message); } private _onDialog(event: Protocol.Page.javascriptDialogOpeningPayload): void { @@ -1163,7 +1285,7 @@ export class Page extends EventEmitter { event.message, event.defaultPrompt ); - this.emit(Events.Page.Dialog, dialog); + this.emit(PageEmittedEvents.Dialog, dialog); } url(): string { diff --git a/src/common/Target.ts b/src/common/Target.ts index 1a280a2b..7d6988c0 100644 --- a/src/common/Target.ts +++ b/src/common/Target.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { Events } from './Events'; -import { Page } from './Page'; +import { Page, PageEmittedEvents } from './Page'; import { WebWorker } from './WebWorker'; import { CDPSession } from './Connection'; import { Browser, BrowserContext } from './Browser'; @@ -87,9 +86,9 @@ export class Target { if (!opener || !opener._pagePromise || this.type() !== 'page') return true; const openerPage = await opener._pagePromise; - if (!openerPage.listenerCount(Events.Page.Popup)) return true; + if (!openerPage.listenerCount(PageEmittedEvents.Popup)) return true; const popupPage = await this.page(); - openerPage.emit(Events.Page.Popup, popupPage); + openerPage.emit(PageEmittedEvents.Popup, popupPage); return true; }); this._isClosedPromise = new Promise(