Alex Arvanitidis
Alex Arvanitidis

Reputation: 4464

Puppeteer log inside page.evaluate

How can I console.log something inside the page.evaluate, passing it to node and using it during the evaluation of the page?

I actually want to log the progress of the page.evaluate to the console and show some results to the user.

Upvotes: 71

Views: 38298

Answers (15)

hamhamdamn
hamhamdamn

Reputation: 1

Here is what worked for me:

page.on('this is what the console says', message => console.log(`From the browser console: ${message.type(): ${message.text()}`));
        

so puppeteer allows you to use page.on to print the messsage.type (error,warning, log etc) and the message.text (what the browser says)

Upvotes: 0

Swell_boy
Swell_boy

Reputation: 31

Update for puppeteer 12, adapted from the current documentation:

Work on Playwright the last version too. In the previous version of this answer, if the number is dynamic "hello" is logged without the number "5". The number logs some rows below.

Example:

firstHello
secondHello
thirdHello
...
1
2
3
page.on('console', async (msg) => {
        const msgArgs = msg.args();
        const logValues = await Promise.all(msgArgs.map(async arg => await arg.jsonValue()));
        console.log(...logValues);
    });

await page.evaluate(() => console.log('hello', 5));
await page.evaluate(() => console.log({ foo: 'bar' }));
await page.evaluate(() => console.log([1, 2, 3, 4, 5]));

Shows the following results:

hello 5  
{ foo: 'bar' }  
[ 1, 2, 3, 4, 5 ]  

Upvotes: 1

Darkosphere
Darkosphere

Reputation: 161

This one isn't featured yet:

// expose the function "logInNodeJs" for use from inside page context 
await page.exposeFunction('logInNodeJs', (value) => console.log(value));

// Now you can call logInNodeJs(value) from inside page context like below
await page.$eval('selector', (el) => {
    logInNodeJs('some test value'); // calls the exposed function from page context
});

Upvotes: 2

Vaviloff
Vaviloff

Reputation: 16838

Update for puppeteer 12, adapted from the current documentation:

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

await page.evaluate(() => console.log('hello', 5));
await page.evaluate(() => console.log({ foo: 'bar' }));
await page.evaluate(() => console.log([1, 2, 3, 4, 5]));

Shows the following results:

hello  
5  
{ foo: 'bar' }  
[ 1, 2, 3, 4, 5 ]  

Upvotes: 113

Igor Kurkov
Igor Kurkov

Reputation: 5040

Today in 2021 with puppeteer 8.x.x the main answer not show us the full description of the console object. For example, you can't get all the error stack trace text, message.text() contain just a few information about the js errors.

My best way to do this in another comment here https://stackoverflow.com/a/66801550/9026103

Upvotes: 0

Tomas Giro
Tomas Giro

Reputation: 4267

await page.evaluate(()=>{
      var string = 'I want to print this';
      return string;
}).then(console.log);
        

Upvotes: 1

Changdae Park
Changdae Park

Reputation: 1079

I share this solution for future readers who would more like to know how to get the returned value of an evaluation instead.

const element = await page.$("a selector");
const text = await page.evaluate(element => element.textContent);

Upvotes: 2

I am trying to share my workaround if it helps anybody in future.

  1. Print all the console outputs to stdout including warning, error, log:

    page = await browser.newPage();
    page.on("console", (consoleObj) => console.log(consoleObj.text()));
    
  2. Print everything except warning:

    page.on('console', consoleObj => {
        if (consoleObj.type() !== 'warning') {
            console.log(consoleObj.text());
        }
    })
    
  3. Print only logs (Ex: console.logs).

    page.on('console', consoleObj => {
        if (consoleObj.type() === 'log') {
            console.log(consoleObj.text());
        }
    })
    

The last one helped me more to debug efficiently.

Upvotes: 4

Hyung Doe
Hyung Doe

Reputation: 51

const page = await browser.newPage();
page.on("console", msg => {
for (let i = 0; i < msg.args().length; ++i)
console.log(`${i}: ${msg.args()[i]}`);
});

try this one if none of the above works. shows no error logs but only the log I created.

Upvotes: 3

raphaeli
raphaeli

Reputation: 59

Update for version 1.15.x and above - Jan 2020

In the latest version args has been replaced with _args.

So when you are using page.evaluate() or page.evaluateHandle() and you want to get the console.log() text from the browser context back to node, use the following code and make sure to set the listener before any console.log() calls:

Code:

    // First we register our listener.
    page.on('console', msg => {
    for (let i = 0; i < msg._args.length; ++i)
        console.log(`${i}: ${msg._args[i]}`);
    });

    // Then we call the log.
    page.evaluate(() => console.log('Hello World'));

Explanation:

You can't see the console.log() text in your node console or set node breakpoints inside page.evaluate() or page.evaluateHandle(), because the code inside those functions is running only in the browser context. If you would launch puppeteer in none headless mode you would see the console.log() message showing in the browser.

Sidenote:

In most cases you don't really need to log inside the browser context and you can do the same work in the 'Console' tab of your browser 'Developer tools' section.

Upvotes: 5

Nicolas Bouvrette
Nicolas Bouvrette

Reputation: 4757

A lot of the answers provided previously no longer work today. Also one thing that can be very annoying on some pages, is the "warning" messages which pollutes the output. One way to fix that is to filter for the type of the message. The following code helps reduce the noise and works with current versions of Puppeteer:

const browser = await puppeteer.launch();
const page = await browser.newPage();
page.on('console', consoleMessageObject => function (consoleMessageObject) {
    if (consoleMessageObject._type !== 'warning') {
        console.debug(consoleMessageObject._text)
    }
});

await page.goto('https://google.com');
const result = await page.evaluate(() => {
    console.log('Browser scope.');
    return 'Normal scope.';
});
console.log(result)

Upvotes: 11

Clay Risser
Clay Risser

Reputation: 3570

The easiest way to get it to work exactly like you'd expect

const page = await browser.newPage();
page.on('console', (log) => console[log._type](log._text));

Upvotes: 20

E. Fortes
E. Fortes

Reputation: 1338

const page = await browser.newPage();
page.on('console', ConsoleMessage => console.log(ConsoleMessage.text));

Upvotes: -2

John Vandivier
John Vandivier

Reputation: 2426

I like @Vaviloff's answer, but you will log the whole ConsoleMessage object when you may just want the text. Thus, I personally use the below:

const EOL = require('os').EOL;
const _page = await browser.newPage();

_page.on('console', _fCleanLog);

function _fCleanLog(ConsoleMessage) {
    console.log(ConsoleMessage.text + EOL);
}

Upvotes: 4

Paul
Paul

Reputation: 605

Implement the notifyUi function in this code sample:

const page = await browser.newPage();
page.on('console', (...args) => {
    this.notifyUi('[chrome] ' + args[0]);
});
await page.goto(url);
const result = await page.evaluate(() => {
    console.log('I am alive');
    return Promise.resolve(true);
});
this.notifyUi('Evaluation returned with ' + result);

Upvotes: 3

Related Questions