Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UnhandledPromiseRejectionWarning: Error: Page crashed! While using puppeteer

So I used a while loop so my test will run in a constant loop until my back-end will crash. I've implemented a try and catch(error) so any front-end crash the automation will refresh and keep running

while(true){
try{
    await page.waitFor(selector)
    await page.click(selector)    
}
catch(error){
    console.log("FE crashed with\n\n" + error + "\n\nRefreshing page and continuing profile switching")
    await page.reload(page);
    continue;
}}

So indeed any timeout error the automation refreshes the page and continuing the loop. but Im recieving a different crash error

(node:6535) UnhandledPromiseRejectionWarning: Error: Page crashed!
at Page._onTargetCrashed (/home/raymond/node_modules/puppeteer/lib/Page.js:170:24)
at CDPSession.Page.client.on.event (/home/raymond/node_modules/puppeteer/lib/Page.js:125:56)
at CDPSession.emit (events.js:182:13)
at CDPSession._onMessage (/home/raymond/node_modules/puppeteer/lib/Connection.js:200:12)
at Connection._onMessage (/home/raymond/node_modules/puppeteer/lib/Connection.js:112:17)
at _tickCallback (internal/process/next_tick.js:43:7)
at listOnTimeout (timers.js:294:7)
at processTimers (timers.js:268:5)
(node:6535) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)

How can I handle this error?, if I refresh the page manually everything works fine. Thanks

like image 877
Dan Raymond Avatar asked Sep 16 '19 12:09

Dan Raymond


People also ask

What browser does puppeteer use?

Puppeteer Supported Browsers Puppeteer Supports Chromium-Based Browsers and Firefox.

Does puppeteer require Chrome?

Puppeteer is a Node. js library developed by Google that lets you control headless Chrome through the DevTools Protocol. It is a tool for automating testing in your application using headless Chrome or Chromebit devices, without requiring any browser extensions like Selenium Webdriver or PhantomJS.

What is puppeteer headless?

Puppeteer is a Node library which provides a high-level API to control headless Chrome or Chromium over the DevTools Protocol. It can also be configured to use full (non-headless) Chrome or Chromium.


2 Answers

You are assuming, that the error happened because the page navigation failed. This might be the case, but it could also be a different error like a Protocol error. In a case like that, you cannot just reuse the page object, but you first have to restart the browser.

Some time ago, I crawled roughly 400k pages for testing purposes. In total, I experienced 34 of these puppeteer crashes, where some unexpected error crashes the whole browser. To harden your code against these kind of crashes, you need a robust way to restart the browser.

Code Sample

let browser = await puppeteer.launch(/* .. */);
let page = await browser.newPage();

while(true) {
    try {
        // your code that might crash
    } catch (err) {
        try {
            await page.reload(); // soft fix
        } catch (recoveringErr) {
            // unable to reload the page, hard fix
            try {
                await browser.close();
            } catch (err) { // browser close was not necessary
                // you might want to log this error
            }
            browser = await puppeteer.launch(/* .. */);
            page = await browser.newPage();
        }
    }
}

Although this code might look horrendous with three nested try..catch blocks, it does a good job of keeping your code running.

First, your original code is executed. If the initial problem happens, a page.reload call is tried to fix the problem. In case this works, the loop will continue running. If that does not work, the browser will be restarted.

For restarting the browser, I recommend to first try to close the old browser. Although, this might likely fail, it clears all memory and correctly disposes the browser object. Depending on your use case, you might want to log the error or simply ignore it. After disposing the old browser object, you can restart the browser and the loop may continue.

Alternative

As an alternative, you could use my library puppeteer-cluster which has error handling build in. The library automatically restarts the browser in cases in which the page is not usable anymore. In addition, the library can run multiple pages in parallel (as you are trying to stress-test the server I'm assuming).

like image 56
Thomas Dondorf Avatar answered Sep 28 '22 10:09

Thomas Dondorf


As per the official documentation, an 'error' event is emitted when the page crashes which can be used to do certain stuff basis the application.

page.on('error', err => { /*custom logic to handle the crash*/ });

For the above specific use case, you could go about doing something like this:

let browser = await puppeteer.launch();
let page = await getNewPage(browser);

while(true){
        try{
            if (page.isClosed()) {
              page = await getNewPage(browser);
            }
            await page.waitFor(selector)
            await page.click(selector)    
        }
        catch(error){
            console.log("FE error with\n\n" + error + "\n\nRefreshing page and continuing profile switching")
            await page.reload();
            continue;
        }}


async function getNewPage(browser) {
    let page = await browser.newPage();
    page.on('error', err => {
        if (!page.isClosed()) {
            //Close page if not closed already
            page.close();
        }
    }
    return page;
}

Reference: page.on('error')

like image 30
Kunal Kukreja Avatar answered Sep 28 '22 11:09

Kunal Kukreja