Playwright: [Feature] Auto-wait in page.$eval?

Created on 2 Mar 2020  路  7Comments  路  Source: microsoft/playwright

While debugging @mynar7's issue on slack, I noticed that the page.waitForNavigation was not a reliable way to ensure that the #catalog-title is visible. Replacing it with a page.waitForSelector fixed it.

However, since we are moving towards auto-waits in API calls that refer to element selectors, I was wondering if the page.$eval method could auto-wait for the element, thereby eliminating the need to waitForSelector.

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

(async() => {
    const browser = await firefox.launch();
    const page = await browser.newPage();
    await page.goto('https://realtruck.com/?disableIntegration=all');

    await Promise.all([
        page.click('text=Tonneau Covers'),
        page.waitForSelector('#catalog-title') // was earlier using page.waitForNavigation()
    ]);

    const header = await page.$eval('#catalog-title', el => el.textContent);
    assert(header, "Tonneau Covers");
    await browser.close();
})();

Most helpful comment

Should that one not wait for the selector to appear?

@thernstig yes, it does not wait for selector to appear. The semantic is the same as the $ in devtools console, or in jquery - they just fetch element from the page.

If you want to wait for a selector, you should use page.waitfor("foo")

All 7 comments

since we are moving towards auto-waits in API calls that refer to element selectors

We keep thinking in this direction, but there are a few concerns particularly regarding page.$eval:

  • technical: waitForSelector has some interesting options and might get more in future; and there's no good shape for page.$eval to accept these options.
  • aesthetics: so far we think that it's nice to have all waiting methods prefixed with waitFor.. - it self-explains the API for non-experienced users.

So we'll keep thinking about this! For now, I think I can re-write your snippet in a slightly nicer way:

await page.goto('https://realtruck.com/?disableIntegration=all');
await page.click('text=Tonneau Covers');
const catalog = await page.waitForSelector('#catalog-title');
const header = await catalog.evaluate(el => el.textContent);
assert(header, "Tonneau Covers");

Should this work const handle = await page.$('"foo"'); shown here? Should that one not wait for the selector to appear? Because I just tested this and it does not. It would maybe then mean page.$wait() is unecessary, but I am sure I am missing something?

Should that one not wait for the selector to appear?

@thernstig yes, it does not wait for selector to appear. The semantic is the same as the $ in devtools console, or in jquery - they just fetch element from the page.

If you want to wait for a selector, you should use page.waitfor("foo")

@aslushnikov page.$wait and page.waitForSelector returns an ElementHandle whereas page.waitfor returns a JSHandle, is that intentional?

@thernstig page.waitFor will return an ElementHandle once called with a string as an argument. (cc @JoelEinbinder - can we actually signify this in our .d.ts types?)

@thernstig page.waitFor will return an ElementHandle once called with a string as an argument. (cc @JoelEinbinder - can we actually signify this in our .d.ts types?)

Yes, I'll add it to #6.

Closing this for now. We will use the guide to outline the difference in how "actions" like click, fill, etc work, versus the $ and $eval.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shirshak55 picture shirshak55  路  3Comments

TrySound picture TrySound  路  4Comments

osmenia picture osmenia  路  4Comments

arjunattam picture arjunattam  路  4Comments

andyricchuiti picture andyricchuiti  路  4Comments