Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Puppeteer console.log - How to look inside JSHandle@object?

I have a React/Redux app that I am testing using Puppeteer. Based on the documentation, I am using the following code to show the console outputs:

page.on('console', msg => {
    for(let i = 0; i < msg.args().length; ++i) {
        let text = msg.args()[i];
        console.log(`${i}: ${text}`);
    }
});

However, when the redux-logger logs an object to console (prevState, nextState), Puppeeter shows JSHandle@object in my console outputs instead. How do I see the keys and properties inside this object?

like image 824
aditi Avatar asked Aug 03 '18 15:08

aditi


2 Answers

If you place the consoleMessage.args() directly inside console.log() without enclosing them in template literals, you can print the keys and values of the JSHandles that represent each argument passed to console.log() in the page context:

page.on('console', msg => {
  for (let i = 0; i < msg.args().length; i++) {
    console.log(msg.args()[i]);
  }
});

The beginning of the result will look something like this:

JSHandle {
  _context:
   ExecutionContext {
     _client:
      CDPSession {
        domain: null,
        _events: [Object],
        ...
like image 71
Grant Miller Avatar answered Nov 09 '22 17:11

Grant Miller


You can get args from JSHandle with await for it.

The best way for me was next to describe errors from the browser and catch needed types of console notifications:

import { ConsoleMessage, Page, JSHandle } from 'puppeteer';
const chalk = require('chalk');

export const listenPageErrors = async (page: Page) => {
  // make args accessible
  const describe = (jsHandle) => {
    return jsHandle.executionContext().evaluate((obj) => {
      // serialize |obj| however you want
      return `OBJ: ${typeof obj}, ${obj}`;
    }, jsHandle);
  }

  const colors: any = {
    LOG: chalk.grey, // (text: any) => text,
    ERR: chalk.red,
    WAR: chalk.yellow,
    INF: chalk.cyan,
  };

  // listen to browser console there
  page.on('console', async (message: ConsoleMessage) => {
    const args = await Promise.all(message.args().map(arg => describe(arg)));
    // make ability to paint different console[types]
    const type = message.type().substr(0, 3).toUpperCase();
    const color = colors[type] || chalk.blue;
    let text = '';
    for (let i = 0; i < args.length; ++i) {
      text += `[${i}] ${args[i]} `;
    }
    console.log(color(`CONSOLE.${type}: ${message.text()}\n${text} `));
  });
}

Put it between const page = await browser.newPage(); and page.goto(URL), and it will work as should

const page = await browser.newPage();
await listenPageErrors(page); // <- like there
page.goto(URL)

like image 7
Kurkov Igor Avatar answered Nov 09 '22 18:11

Kurkov Igor