0

When I call a function normally, it works, but when I call it in page.evaluate(), the function is not defined. Here's a demo:

const puppeteer = require('puppeteer');
(async () => {
    const browser = await puppeteer.launch()
    const page = await browser.newPage()

    page.on('console', msg => console.log(msg.text())) // so console.log() works in page.evaluate()
    const test = () => console.log('works')
    await test() // it runs

    await page.evaluate(() => test()) // ReferenceError: test is not defined
})()
Alex
  • 13
  • 3
  • 1
    This is expected. `evaluate`'s callback [runs in the browser](https://stackoverflow.com/questions/47304665/how-to-pass-a-function-in-puppeteers-evaluate-method), so it doesn't have access to your Node state. What are you trying to achieve here (I assume something more interesting than logging "works")? – ggorlen Sep 14 '22 at 01:28
  • It depends. Please read the dupe thoroughly because it should cover most/all use cases. The question is, do you want the func you invoke to run in the browser console or in Node? If the former, then you can use `addScriptTag` or use a previous (or the same) `evaluate` to attach functions to the window. That's what I'd do for your delay example (although [delaying is bad](https://serpapi.com/blog/puppeteer-antipatterns/#overusing-waitfortimeout)). if you want to trigger Node code, use `exposeFunction`. – ggorlen Sep 14 '22 at 01:38
  • [How do I expose an object with a bunch of functional definitions (or methods) to puppeteer?](https://stackoverflow.com/questions/72156753/how-do-i-expose-an-object-with-a-bunch-of-functional-definitions-or-methods-to/72157472#72157472) may also help here. – ggorlen Sep 14 '22 at 01:39

1 Answers1

1

The page context that Puppeteer spawns (in its virtual browser) is not the same as the Node context that you write the implementation code in. When page.evaluate is passed a function, that function is serialized, then passed to the browser, and deserialized and evaluated (in that different context). Here, the page context doesn't have access to test, because that variable is only defined in Node, not on the page.

You can put a function into the page if you want, though, by defining it in the page context.

await page.evaluate(() => {
  window.test = () => console.log('works');
});
await page.evaluate(() => test())

or

await page.evaluate(() => {
  const test = () => console.log('works');
  test();
});
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320