Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] When does page.click resolve in the DOM loading lifecycle? #4020

Closed
katmd opened this issue Sep 30, 2020 · 3 comments
Closed

[Question] When does page.click resolve in the DOM loading lifecycle? #4020

katmd opened this issue Sep 30, 2020 · 3 comments

Comments

@katmd
Copy link

katmd commented Sep 30, 2020

When navigating from another URL, I am using Playwright's page.click on a <div> element with an onclick event handler. However, Playwright will immediately attempt to click on the <div> element's position even if the page is not fully loaded with the assigned click event listener. Playwright will then say the page.click succeeded, but the onclick function will not fire.

My thought was that page.click would wait until the page was fully loaded before attempting the click action. Looking at the debugging logs, 'waiting for scheduled navigations to finish' occurs after the click action is completed, as reflected by step 5 of the page.click operations in the docs. What are these scheduled navigations and when does page.click resolve in the DOM loading lifecycle?

await page.click(selector);
  pw:api => page.click started +0ms
  pw:api waiting for selector "[test-selector="selector-name"]" +1ms
  pw:api   selector resolved to visible <div test-selector="selector-na…>…</div> +9ms
  pw:api attempting click action +4ms
  pw:api   waiting for element to be visible, enabled and not moving +0ms
  pw:api   element is visible, enabled and does not move +10ms
  pw:api   scrolling into view if needed +0ms
  pw:api   done scrolling +1ms
  pw:api   checking that element receives pointer events at (744.48,222) +2ms
  pw:api   element does receive pointer events +4ms
  pw:api   performing click action +0ms
  pw:api   click action done +4ms
  pw:api   waiting for scheduled navigations to finish +0ms
  pw:api   navigations have finished +9ms
  pw:api <= page.click succeeded +1ms
@dgozman
Copy link
Contributor

dgozman commented Oct 1, 2020

There are two cases: page is loading before the click and page is loading after the click.

  • Page is loading after the click.

    This usually happens when you click a link that navigates to another page. In this case "waiting for scheduled navigations to finish" logic kicks in and automatically waits until the new page has started loading. Note that it does not wait for the load to finish, only for the load to start. Also note, that it waits after the click, not before the click.

  • Page is loading before the click.

    This case generally depends on the action before the click.

    For example, if you do page.goto() followed by page.click(), the goto command will wait until the "load" event by default. Depending on your page, this could be before the onclick listener is attached (for example, when it is done from DOMContentLoaded) or after (for example, when it is done after xhr with some data).

    Situation is different if you do two page.click() calls, and the first one triggers some lazy loading and onclick listener attachement. In this case, first page.click() does not wait until the "load" event, so you'd want to do it manually.

    Overall, there are multiple strategies to handle this case:

    1. Use a unique selector that only matches when the element is ready to click, e.g. page.click('button.ready'). You'll have to add some class/attribute after adding onclick listener.
    2. Manually call await page.waitForLoadState("load") to wait for the "load" event. This only works if you attach listeners before the "load" event finishes.
    3. Introduce a signal in the page that it is ready to be clicked.
    // Works if you set up some promise that resolves once everything is loaded.
    await page.evaluate(() => window.readyToBeClickedPromise);
    // Works if you can easily determine whether everything has been loaded.
    await page.waitForFunction(() => window.isEverythingReady());

Does this answer your question?

@katmd
Copy link
Author

katmd commented Oct 2, 2020

Yes, thank you very much for the clarification and types of strategies I can use to handle this situation.

@dgozman
Copy link
Contributor

dgozman commented Oct 3, 2020

You are welcome!

@dgozman dgozman closed this as completed Oct 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants