Search code examples
javascriptasynchronouspuppeteerheadless

Puppeteer evaluate function on load to show alert


I am a newbie in puppeteer and I can't understand why the following code cannot work. any explanation would be appreciated.

const puppeteer=require("puppeteer");
(async () => {
    const browser = await puppeteer.launch({headless:false});
    const page = await browser.newPage();
    await page.goto('https://bet254.com');
    await page.evaluate(async ()=> {
        window.addEventListener("load",(event)=>{
            document.alert("Loaded!");
        })
    });

})(); 

I was expecting an alert after loading. But nothing happened! How can I add a listener to show an alert on page load?


Solution

  • page.goto already waits for the page to load, so by the time your evalute runs, you can't re-wait for the page to load, so the load event will never fire.

    Another problem is that document.alert isn't a function. You may be thinking of document.write or window.alert. In any case, neither function is particularly useful for debugging, so I suggest sticking to console.log unless you have a very compelling reason not to.

    When working with Puppeteer, it's important to isolate problems by running your evaluate code by hand in the browser without Puppeteer, otherwise you might have no idea whether it's Puppeteer or the browser code that's failing.

    Anything logged in evaluate won't be shown in your Node stdout or stderr, so you'll probably want to monitor that with a log listener. You'll need to look at both Node and the browser console for errors.

    Depending on what you're trying to accomplish, page.evaluateOnNewDocument(pageFunction[, ...args]) will let you attach code to evaluate whenever you navigate, which might be what you're trying for here.

    Here's an example of alerting headfully:

    const puppeteer = require("puppeteer"); // ^19.6.3
    
    let browser;
    (async () => {
      browser = await puppeteer.launch({headless: false});
      const [page] = await browser.pages();
      await page.evaluateOnNewDocument(() => {
        window.addEventListener("load", event => {
          alert("Loaded!");
        });
      });
      await page.goto("https://www.example.com", {waitUntil: "load"});
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close());
    

    Using console.log headlessly, with the log redirected to Node:

    const puppeteer = require("puppeteer");
    
    const onPageConsole = msg =>
      Promise.all(msg.args().map(e => e.jsonValue()))
        .then(args => console.log(...args));
    
    let browser;
    (async () => {
      browser = await puppeteer.launch();
      const [page] = await browser.pages();
      page.on("console", onPageConsole);
      await page.evaluateOnNewDocument(() => {
        window.addEventListener("load", event => {
          console.log("Loaded!");
        });
      });
      await page.goto("https://www.example.com", {waitUntil: "load"});
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close());
    

    If all you're trying to do is run some code in the browser after load, then you might not even need to attach a listener to the load event at all:

    const onPageConsole = msg =>
      Promise.all(msg.args().map(e => e.jsonValue()))
        .then(args => console.log(...args));
    
    let browser;
    (async () => {
      browser = await puppeteer.launch();
      const [page] = await browser.pages();
      page.on("console", onPageConsole);
      await page.goto("https://www.example.com", {waitUntil: "load"});
      await page.evaluate(() => console.log("Loaded!"));
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close());
    

    Or if the code you want to run is purely Node just use normal control flow:

    let browser;
    (async () => {
      browser = await puppeteer.launch();
      const [page] = await browser.pages();
      await page.goto("https://www.example.com", {waitUntil: "load"});
      console.log("Loaded!");
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close());
    

    By the way, there's no need to make a function async unless you have await in it somewhere.

    See also Puppeteer wait until page is completely loaded.