feat(Console): Introduce ConsoleMessage type (#909)

This patch introduces ConsoleMessage type and starts dispatching
it for the 'console' event.

BREAKING CHANGE: this breaks the api of the 'console' event.

Fixes #744.
This commit is contained in:
Andrey Lushnikov 2017-09-29 11:27:22 -07:00 committed by GitHub
parent cfece3451d
commit f6255029bd
5 changed files with 59 additions and 18 deletions

View File

@ -153,7 +153,7 @@ Explore the [API documentation](docs/api.md) and [examples](https://github.com/G
This is also handy when debugging code in `page.evaluate()`: This is also handy when debugging code in `page.evaluate()`:
```js ```js
page.on('console', (...args) => console.log('PAGE LOG:', ...args)); page.on('console', msg => console.log('PAGE LOG:', ...msg.args));
await page.evaluate(() => console.log(`url is ${location.href}`)); await page.evaluate(() => console.log(`url is ${location.href}`));
``` ```

View File

@ -99,6 +99,10 @@
+ [dialog.dismiss()](#dialogdismiss) + [dialog.dismiss()](#dialogdismiss)
+ [dialog.message()](#dialogmessage) + [dialog.message()](#dialogmessage)
+ [dialog.type](#dialogtype) + [dialog.type](#dialogtype)
* [class: ConsoleMessage](#class-consolemessage)
+ [consoleMessage.args](#consolemessageargs)
+ [consoleMessage.text](#consolemessagetext)
+ [consoleMessage.type](#consolemessagetype)
* [class: Frame](#class-frame) * [class: Frame](#class-frame)
+ [frame.$(selector)](#frameselector) + [frame.$(selector)](#frameselector)
+ [frame.$$(selector)](#frameselector) + [frame.$$(selector)](#frameselector)
@ -249,7 +253,7 @@ puppeteer.launch().then(async browser => {
``` ```
#### event: 'console' #### event: 'console'
- <[string]> - <[ConsoleMessage]>
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. 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.
@ -257,11 +261,11 @@ The arguments passed into `console.log` appear as arguments on the event handler
An example of handling `console` event: An example of handling `console` event:
```js ```js
page.on('console', (...args) => { page.on('console', msg => {
for (let i = 0; i < args.length; ++i) for (let i = 0; i < msg.args.length; ++i)
console.log(`${i}: ${args[i]}`); console.log(`${i}: ${args[i]}`);
}); });
page.evaluate(() => console.log(5, 'hello', {foo: 'bar'})); page.evaluate(() => console.log('hello', 5, {foo: 'bar'}));
``` ```
#### event: 'dialog' #### event: 'dialog'
@ -514,7 +518,7 @@ const crypto = require('crypto');
puppeteer.launch().then(async browser => { puppeteer.launch().then(async browser => {
const page = await browser.newPage(); const page = await browser.newPage();
page.on('console', console.log); page.on('console', msg => console.log(msg.text));
await page.exposeFunction('md5', text => await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex') crypto.createHash('md5').update(text).digest('hex')
); );
@ -536,7 +540,7 @@ const fs = require('fs');
puppeteer.launch().then(async browser => { puppeteer.launch().then(async browser => {
const page = await browser.newPage(); const page = await browser.newPage();
page.on('console', console.log); page.on('console', msg => console.log(msg.text));
await page.exposeFunction('readfile', async filePath => { await page.exposeFunction('readfile', async filePath => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, text) => { fs.readFile(filePath, 'utf8', (err, text) => {
@ -1093,6 +1097,21 @@ puppeteer.launch().then(async browser => {
Dialog's type, could be one of the `alert`, `beforeunload`, `confirm` and `prompt`. Dialog's type, could be one of the `alert`, `beforeunload`, `confirm` and `prompt`.
### class: ConsoleMessage
[ConsoleMessage] objects are dispatched by page via the ['console'](#event-console) event.
#### consoleMessage.args
- <[Array]<[string]>>
#### consoleMessage.text
- <[string]>
#### consoleMessage.type
- <[string]>
One of the following values: `'log'`, `'debug'`, `'info'`, `'error'`, `'warning'`, `'dir'`, `'dirxml'`, `'table'`, `'trace'`, `'clear'`, `'startGroup'`, `'startGroupCollapsed'`, `'endGroup'`, `'assert'`, `'profile'`, `'profileEnd'`, `'count'`, `'timeEnd'`.
### class: Frame ### class: Frame
At every point of time, page exposes its current frame tree via the [page.mainFrame()](#pagemainframe) and [frame.childFrames()](#framechildframes) methods. At every point of time, page exposes its current frame tree via the [page.mainFrame()](#pagemainframe) and [frame.childFrames()](#framechildframes) methods.
@ -1432,6 +1451,7 @@ Contains the URL of the response.
[stream.Readable]: https://nodejs.org/api/stream.html#stream_class_stream_readable "stream.Readable" [stream.Readable]: https://nodejs.org/api/stream.html#stream_class_stream_readable "stream.Readable"
[Error]: https://nodejs.org/api/errors.html#errors_class_error "Error" [Error]: https://nodejs.org/api/errors.html#errors_class_error "Error"
[Frame]: #class-frame "Frame" [Frame]: #class-frame "Frame"
[ConsoleMessage]: #class-consolemessage "ConsoleMessage"
[iterator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols "Iterator" [iterator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols "Iterator"
[Response]: #class-response "Response" [Response]: #class-response "Response"
[Request]: #class-request "Request" [Request]: #class-request "Request"

View File

@ -313,7 +313,9 @@ class Page extends EventEmitter {
return; return;
} }
const values = await Promise.all(event.args.map(arg => helper.serializeRemoteObject(this._client, arg))); const values = await Promise.all(event.args.map(arg => helper.serializeRemoteObject(this._client, arg)));
this.emit(Page.Events.Console, ...values); const text = values.join(' ');
const message = new ConsoleMessage(event.type, text, values);
this.emit(Page.Events.Console, message);
} }
_onDialog(event) { _onDialog(event) {
@ -875,6 +877,19 @@ Page.Viewport;
* @property {("Strict"|"Lax")=} sameSite * @property {("Strict"|"Lax")=} sameSite
*/ */
class ConsoleMessage {
/**
* @param {string} type
* @param {string} text
* @param {!Array<*>} args
*/
constructor(type, text, args) {
this.type = type;
this.text = text;
this.args = args;
}
}
module.exports = Page; module.exports = Page;
helper.tracePublicAPI(Page); helper.tracePublicAPI(Page);

View File

@ -537,13 +537,15 @@ describe('Page', function() {
describe('Page.Events.Console', function() { describe('Page.Events.Console', function() {
it('should work', SX(async function() { it('should work', SX(async function() {
let commandArgs = []; let message = null;
page.once('console', (...args) => commandArgs = args); page.once('console', m => message = m);
await Promise.all([ await Promise.all([
page.evaluate(() => console.log(5, 'hello', {foo: 'bar'})), page.evaluate(() => console.log('hello', 5, {foo: 'bar'})),
waitForEvents(page, 'console') waitForEvents(page, 'console')
]); ]);
expect(commandArgs).toEqual([5, 'hello', {foo: 'bar'}]); expect(message.text).toEqual('hello 5 [object Object]');
expect(message.type).toEqual('log');
expect(message.args).toEqual(['hello', 5, {foo: 'bar'}]);
})); }));
it('should work for different console API calls', SX(async function() { it('should work for different console API calls', SX(async function() {
const messages = []; const messages = [];
@ -559,11 +561,14 @@ describe('Page', function() {
console.error('calling console.error'); console.error('calling console.error');
console.log(Promise.resolve('should not wait until resolved!')); console.log(Promise.resolve('should not wait until resolved!'));
}), }),
// Wait for 5 events to hit. // Wait for 5 events to hit - console.time is not reported
waitForEvents(page, 'console', 5) waitForEvents(page, 'console', 5)
]); ]);
expect(messages[0]).toContain('calling console.time'); expect(messages.map(msg => msg.type)).toEqual([
expect(messages.slice(1)).toEqual([ 'timeEnd', 'trace', 'dir', 'warning', 'error', 'log'
]);
expect(messages[0].text).toContain('calling console.time');
expect(messages.slice(1).map(msg => msg.text)).toEqual([
'calling console.trace', 'calling console.trace',
'calling console.dir', 'calling console.dir',
'calling console.warn', 'calling console.warn',
@ -572,13 +577,13 @@ describe('Page', function() {
]); ]);
})); }));
it('should not fail for window object', SX(async function() { it('should not fail for window object', SX(async function() {
let windowObj = null; let message = null;
page.once('console', arg => windowObj = arg); page.once('console', msg => message = msg);
await Promise.all([ await Promise.all([
page.evaluate(() => console.error(window)), page.evaluate(() => console.error(window)),
waitForEvents(page, 'console') waitForEvents(page, 'console')
]); ]);
expect(windowObj).toBe('Window'); expect(message.text).toBe('Window');
})); }));
}); });

View File

@ -37,6 +37,7 @@ const EXCLUDE_CLASSES = new Set([
const EXCLUDE_METHODS = new Set([ const EXCLUDE_METHODS = new Set([
'Body.constructor', 'Body.constructor',
'Browser.constructor', 'Browser.constructor',
'ConsoleMessage.constructor',
'Dialog.constructor', 'Dialog.constructor',
'ElementHandle.constructor', 'ElementHandle.constructor',
'Frame.constructor', 'Frame.constructor',