question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] Calling waitForNavigation twice doesn't work

See original GitHub issue

Context:

  • Playwright Version: 0.11.1
  • Operating System: macOS
  • Extra: Node 12.14.1

Code Snippet Here’s a minimal repro of the behavior I’m seeing.

const { chromium, webkit, firefox } = require('playwright');

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

  await page.goto('https://www.behance.net/search');
  // await page.waitForNavigation({ waitUntil: 'networkidle0' });

  // temporary - to ensure JS bindings are installed so that the history API will always be used for the second navigation
  await page.waitFor(2000);

  await Promise.all([
    page.click('[data-ut="moodboards-tab"]'),
    page.waitForNavigation({ waitUntil: 'networkidle0' }),
  ]);

  await page.screenshot({path: 'repro.png'});

  await browser.close();
})();

Describe the bug

This is a follow-up to https://github.com/microsoft/playwright/issues/996.

It seems that when I call waitForNavigation twice in the same context, the second call doesn’t work. In this case the second call is a history API navigation event, so that could be part of the reason too.

When I go to a page without any extra waiting, then click a link to navigate and wait for that navigation, everything works fine. But when I also try to wait for the first navigation, the second wait resolves immediately without the page being fully loaded. I’ve tried a couple of variations of this, including passing waitUntil: 'networkidle0' } into page.goto instead of calling waitForNavigation, and using a Promise.all for the first navigation too. All of these produce the same result.

Perhaps there’s something I’m misunderstanding about how waitForNavigation works? The docs seem to indicate that history API changes are considered relevant navigation events too.

When I don’t waitForNavigation as part of the first page.goto, the wait for the second navigation works correctly: repro1

When I do waitForNavigation as part of the first page.goto, the wait for the second navigation doesn’t work: repro2

Thanks for taking a look!

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:11 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
dgozmancommented, Jun 28, 2020

We decided that current behavior is fine. The right way to use “network idle” in this case is to ensure that all requests started after the action has been finished. There needs to be some wrapper that listens to request, requestfinished and requestfailed events during the action. Something along these lines:

async function wrapWithNetworkIdle(page, action) {
  let networkSettledCallback;
  const networkSettledPromise = new Promise(f => networkSettledCallback = f);

  let requestCounter = 0;
  const onRequest = () => ++requestCounter;
  const onRequestDone =() => {
    // Let the page handle responses asynchronously (via setTimeout(0)).
    const evaluate = page.evaluate(() => new Promise(f => setTimeout(f, 0)));
    evaluate.catch(e => null).then(() => {
      if (!--requestCounter)
        networkSettledCallback();
    });
  };

  page.on('request', onRequest);
  page.on('requestfinished', onRequestDone);
  page.on('requestfailed', onRequestDone);

  const result = await action();
  await networkSettledPromise;
  
  page.removeListener('request', onRequest);
  page.removeListener('requestfinished', onRequestDone);
  page.removeListener('requestfailed', onRequestDone);

  return result;
}

We’ll experiment with this later.

1reaction
dgozmancommented, May 5, 2020

I think the issue here is that pushState does not reset networkidle detection, and so the second waitForNavigation call just resolves immediately after the pushState. That sounds like a bug.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Puppeteer page.waitForNavigation() timeout error handling
The question is: how to handle the error, so if it throw a timeout error, i can catch it and call another function?...
Read more >
Navigating & waiting - Checkly
The initial load of the page. ... Run this example as follows: ... waitForNavigation() method here to explicitly wait for this event to...
Read more >
Browser - MarketSquare
When a New Page is called without an open browser, New Browser and New ... If keyword finds one element, keyword does not...
Read more >
Locator - Grafana k6
Locator · Helps with writing robust tests by finding an element even if the underlying frame navigates. · Makes it easier to work...
Read more >
Playwright - CodeceptJS
Usually it should be run from a custom helper after call of _startBrowser ... Don't confuse popups with modal windows, as created by...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found