Teach 'consolemessage' event to send all the arguments

This patch fixes 'consolemessage' event so that it passes
over all the arguments of console API call.
This commit is contained in:
Andrey Lushnikov 2017-07-17 01:57:37 -07:00
parent 117a128b42
commit 1a97d8b3c2
5 changed files with 97 additions and 32 deletions

View File

@ -169,29 +169,7 @@ class FrameManager extends EventEmitter {
let message = await helper.getExceptionMessage(this._client, exceptionDetails); let message = await helper.getExceptionMessage(this._client, exceptionDetails);
throw new Error('Evaluation failed: ' + message); throw new Error('Evaluation failed: ' + message);
} }
if (remoteObject.unserializableValue) { return await helper.serializeRemoteObject(this._client, remoteObject);
switch (remoteObject.unserializableValue) {
case '-0':
return -0;
case 'NaN':
return NaN;
case 'Infinity':
return Infinity;
case '-Infinity':
return -Infinity;
default:
throw new Error('Unsupported unserializable value: ' + remoteObject.unserializableValue);
}
}
if (!remoteObject.objectId)
return remoteObject.value;
let response = await this._client.send('Runtime.callFunctionOn', {
objectId: remoteObject.objectId,
functionDeclaration: 'function() { return this; }',
returnByValue: true,
});
this._client.send('Runtime.releaseObject', {objectId: remoteObject.objectId});
return response.result.value;
} }
/** /**

View File

@ -223,8 +223,8 @@ class Page extends EventEmitter {
} }
return; return;
} }
let values = event.args.map(arg => arg.value || arg.description || ''); let values = await Promise.all(event.args.map(arg => helper.serializeRemoteObject(this._client, arg)));
this.emit(Page.Events.ConsoleMessage, values.join(' ')); this.emit(Page.Events.ConsoleMessage, ...values);
} }
_onDialog(event) { _onDialog(event) {

View File

@ -52,6 +52,37 @@ class Helper {
} }
return message; return message;
} }
/**
* @param {!Connection} client
* @param {!Object} remoteObject
* @return {!Object}
*/
static async serializeRemoteObject(client, remoteObject) {
if (remoteObject.unserializableValue) {
switch (remoteObject.unserializableValue) {
case '-0':
return -0;
case 'NaN':
return NaN;
case 'Infinity':
return Infinity;
case '-Infinity':
return -Infinity;
default:
throw new Error('Unsupported unserializable value: ' + remoteObject.unserializableValue);
}
}
if (!remoteObject.objectId)
return remoteObject.value;
let response = await client.send('Runtime.callFunctionOn', {
objectId: remoteObject.objectId,
functionDeclaration: 'function() { return this; }',
returnByValue: true,
});
client.send('Runtime.releaseObject', {objectId: remoteObject.objectId});
return response.result.value;
}
} }
module.exports = Helper; module.exports = Helper;

View File

@ -62,7 +62,7 @@ class WebPage {
this._pageEvents.on(PageEvents.Response, response => this._onResponseReceived(response)); this._pageEvents.on(PageEvents.Response, response => this._onResponseReceived(response));
this._pageEvents.on(PageEvents.RequestFinished, request => this._onRequestFinished(request)); this._pageEvents.on(PageEvents.RequestFinished, request => this._onRequestFinished(request));
this._pageEvents.on(PageEvents.RequestFailed, event => (this.onResourceError || noop).call(null, event)); this._pageEvents.on(PageEvents.RequestFailed, event => (this.onResourceError || noop).call(null, event));
this._pageEvents.on(PageEvents.ConsoleMessage, msg => (this.onConsoleMessage || noop).call(null, msg)); this._pageEvents.on(PageEvents.ConsoleMessage, (...args) => this._onConsoleMessage(...args));
this._pageEvents.on(PageEvents.Confirm, message => this._onConfirm(message)); this._pageEvents.on(PageEvents.Confirm, message => this._onConfirm(message));
this._pageEvents.on(PageEvents.Alert, message => this._onAlert(message)); this._pageEvents.on(PageEvents.Alert, message => this._onAlert(message));
this._pageEvents.on(PageEvents.Dialog, dialog => this._onDialog(dialog)); this._pageEvents.on(PageEvents.Dialog, dialog => this._onDialog(dialog));
@ -81,6 +81,16 @@ class WebPage {
}; };
} }
/**
* @param {!Array<!Object>} args
*/
_onConsoleMessage(...args) {
if (!this.onConsoleMessage)
return;
const text = args.join(' ');
this.onConsoleMessage(text);
}
/** /**
* @return {string} * @return {string}
*/ */

View File

@ -226,12 +226,37 @@ describe('Puppeteer', function() {
})); }));
}); });
it('Page Events: ConsoleMessage', SX(async function() { describe('Page.Events.ConsoleMessage', function() {
let msgs = []; it('should work', SX(async function() {
page.on('consolemessage', msg => msgs.push(msg)); let commandArgs = [];
await page.evaluate(() => console.log('Message!')); page.once('consolemessage', (...args) => commandArgs = args);
expect(msgs).toEqual(['Message!']); page.evaluate(() => console.log(5, 'hello', {foo: 'bar'}));
await waitForEvents(page, 'consolemessage');
expect(commandArgs).toEqual([5, 'hello', {foo: 'bar'}]);
})); }));
it('should work for different console API calls', SX(async function() {
let messages = [];
page.on('consolemessage', msg => messages.push(msg));
page.evaluate(() => {
// A pair of time/timeEnd generates only one Console API call.
console.time('calling console.time');
console.timeEnd('calling console.time');
console.trace('calling console.trace');
console.dir('calling console.dir');
console.warn('calling console.warn');
console.error('calling console.error');
});
// Wait for 5 events to hit.
await waitForEvents(page, 'consolemessage', 5);
expect(messages[0]).toContain('calling console.time');
expect(messages.slice(1)).toEqual([
'calling console.trace',
'calling console.dir',
'calling console.warn',
'calling console.error',
]);
}));
});
describe('Page.navigate', function() { describe('Page.navigate', function() {
it('should fail when navigating to bad url', SX(async function() { it('should fail when navigating to bad url', SX(async function() {
@ -990,6 +1015,27 @@ describe('Puppeteer', function() {
}); });
}); });
/**
* @param {!EventEmitter} emitter
* @param {string} eventName
* @param {number=} eventCount
* @return {!Promise}
*/
function waitForEvents(emitter, eventName, eventCount = 1) {
let fulfill;
let promise = new Promise(x => fulfill = x);
emitter.on(eventName, onEvent);
return promise;
function onEvent() {
--eventCount;
if (eventCount)
return;
emitter.removeListener(eventName, onEvent);
fulfill();
}
}
// Since Jasmine doesn't like async functions, they should be wrapped // Since Jasmine doesn't like async functions, they should be wrapped
// in a SX function. // in a SX function.
function SX(fun) { function SX(fun) {