3

I have this ES6 code in Puppeteer:

async function waitForSelectorReversed(page, selector) {
  await page.waitFor(() => !document.querySelector(selector));
}

When I call this code I get the error Evaluation failed: ReferenceError: selector is not defined. I understand that this error is caused by the fact that the code inside the closure can't access the variable from the outer scope. What is a way of getting this to work?

SebastianR
  • 1,683
  • 2
  • 17
  • 33
  • Does this answer your question? [Puppeteer: pass variable in .evaluate()](https://stackoverflow.com/questions/46088351/puppeteer-pass-variable-in-evaluate) – Bergi Jul 26 '20 at 19:37
  • Yes, but the question was already answered in 2018 to my satisfaction. – SebastianR Jul 29 '20 at 05:14

1 Answers1

2

You need to explicitly pass outer scope variables into into page.waitFor for it to work. As the documentation states:

To pass arguments from node.js to the predicate of page.waitFor function:

const selector = '.foo';
await page.waitFor(selector => !document.querySelector(selector), {}, selector);

For your code, all you need to do is remove the first line, since selector is already defined.

This isn't so much a plain Javascript thing or an ES6 thing, it's a quirk of how Puppeteer (and Puppeteer-like tools) work when interacting with the page.

Community
  • 1
  • 1
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 1
    Is the code getting compiled to something else behind the scenes? Because that would be entirely valid Javascript in any other context with any other function call, no? – deceze Oct 29 '18 at 07:48
  • Indeed, it looks oddly unnecessary in pretty much any other context, even when one has broad experience with JS. I don't really know *why* it's necessary, just that it is with Puppeteer. It must be doing *something* odd for ordinary scoping rules not to work. – CertainPerformance Oct 29 '18 at 07:53
  • @deceze: Maybe the function gets converted to a string and is reevaluated in the new page context (just a thought, I have never worked with this tool). But that would explain where `document` is coming from. – Felix Kling Oct 29 '18 at 07:53
  • @deceze Perhaps it's being reevaluated somewhere else or the function context is explicitely changed in the function itself. Not sure how CertainPerformance guessed that here, but that's the only reasonable situation where the above code would not work as expected. – briosheje Oct 29 '18 at 07:58
  • Even a *context change* (`this`) should do nothing here. That is very non-standard Javascript behaviour. – deceze Oct 29 '18 at 08:03
  • Thanks for pointing out this weird behavior of Puppeteer here! I have changed the line to await page.waitFor((selector) => !document.querySelector(selector), {}, selector); and now it even works in a generalized way. – SebastianR Oct 29 '18 at 08:05