15

I open a website, then wait for all redirects to be done. Then I capture a captcha image, and send it via nodejs to a user. Then I recive the typed captcha:

    const browser = await puppeteer.launch({headless: false});
    const page = await browser.newPage();

    await page.goto('http://localhost/p1.php' );
    await page.waitForNavigation();

    const captcha_image = await page.$eval('#security', e => e.getAttribute('src'));

    io.emit('send_captcha_to_client' , {text : captcha_image });

    var captcha = await captchaPromise;

After I receive the typed value of the capthca, I put it in the field and click the login button:

    await page.$eval('#W_CAPTCHA', (el , _captcha) => el.value = _captcha.W_CAPTCHA , captcha );

    await page.click('#login-btn');

Now after clicking the button, an ajax request will be sent to the server. Lets say http://example.com/login.php - if the captcha is right, I will get redirected to my dashboard, but if the ajax call returns lets say {status:er}

And there is <span id="alert"></span> in the page it'll add .Error class to it and put the error text in there. How can I intercept the ajax call and check if the login was successful or not?

I can check the result of the ajax call or wait and check the document for div.Error. But I am not sure how can I do any of them. Here is my failed attempt:

await page.waitForNavigation();

page.waitForSelector('.Error');
const error  = await page.$eval('.Error', e => e.value );

console.log(error);

browser.close();
peterh
  • 11,875
  • 18
  • 85
  • 108
hretic
  • 999
  • 9
  • 36
  • 78
  • Maybe this packages can help you to achieve this: https://github.com/jtassin/pending-xhr-puppeteer ref: https://github.com/GoogleChrome/puppeteer/issues/2615 – Ravinder Kumar Mar 29 '19 at 06:43

2 Answers2

24

You can wait on both simultaneously and handle whichever occurs first:

await Promise.race([
  page.waitForNavigation({ waitUntil: "networkidle0" }),
  page.waitForSelector(".Error")
]);

if (await page.$(".Error")) {
  // there was an error
} else {
  // the page changed
}
Aankhen
  • 2,198
  • 11
  • 19
  • 1
    How would this technique work when the button / input fields are within an `iframe`? I've posted a followup question [here](https://stackoverflow.com/questions/56995841/how-to-avoid-frame-got-detached-error-async-validation-or-redirect-with-puppet) for more detail. – Dalie Jul 11 '19 at 19:14
6

The accepted answer isn't waiting for a request but waiting for a selector. That kind of hacky-way wasn't doing it for me.

Waiting a promise resolution coupled with the request response status is the easiest way to achieve it.

await Promise.all( [

  page.click( selector ), // ... action

  page.waitForResponse( response => response.status() === 200 ), // ... wait for network

] );

HTTP response status codes

Response Description
200 OK The HTTP 200 OK success status response code indicates that the request has succeeded. A 200 response is cacheable by default.
amarinediary
  • 4,930
  • 4
  • 27
  • 45