24

I wonder if there's a similar way as in Selenium to wait for text to appear for a particular element. I've tried something like this, but it doesn't seem to wait:

await page.waitForSelector('.count', {visible: true});
ggorlen
  • 44,755
  • 7
  • 76
  • 106
elena
  • 3,740
  • 5
  • 27
  • 38
  • For reference, there's an open issue when using `{visible: true}` with a non-specific selector - i.e. one that might match multiple elements: it only checks visibility of the first matched element: https://github.com/GoogleChrome/puppeteer/issues/4356 – blindfish May 24 '19 at 13:19

6 Answers6

17

You can use waitForFunction. See https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitforfunctionpagefunction-options-args

Including @elena's solution for completeness of the answer:

await page.waitForFunction('document.querySelector(".count").inner‌​Text.length == 7');
nilobarp
  • 3,806
  • 2
  • 29
  • 37
  • I've used `await page.waitForFunction('document.querySelector(".count").innerText.length == 7');` – elena Oct 19 '17 at 08:37
  • What about waiting to see text anywhere in the screen? – bernatfortet Aug 07 '18 at 00:49
  • You can use `page.waitFor` and pass a function that looks up the text content from DOM. [Docs here](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitforselectororfunctionortimeout-options-args) – nilobarp Aug 07 '18 at 02:21
  • Although it's use-case dependent, I find I almost always `.trim()` my `.textContent` on `waitForFunction` callbacks to make sure a space-only element doesn't pass the predicate. – ggorlen Mar 16 '22 at 03:21
15

Apart from the method presented in the answer from nilobarp, there are two more ways to do this:

page.waitForSelector

Using the pseudo selector :empty it is possible to find elements that contain no child nodes or text. Combining this with the :not selector, we can use page.waitForSelector to query for a selector which is not empty:

await page.waitForSelector('.count:not(:empty)');

XPath expression

If you not only want to make sure that the element is not empty, but also want to check for the text it contains, you can use an XPath expression using page.waitForXPath:

await page.waitForXPath("//*[@class='count' and contains(., 'Expected text')]");

This line will only resolve after there is an element on the page which has the attribute class="count" and contains the text Expected text.

David Morales
  • 17,816
  • 12
  • 77
  • 105
Thomas Dondorf
  • 23,416
  • 6
  • 84
  • 105
8

The best solution you can do using waitForFunction() (avoid weird function as string):

const selector = '.count';
await page.waitForFunction(
    selector => document.querySelector(selector).value.length > 0,
    {},
    selector
);

Depends of the type of the text, replace value by innerText.

Check puppeteer API

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
1

page.waitFor()

You can also just simply use page.waitFor() to pass a function or CSS selector for which to wait.

Wait for Function

If the element is an input field, we can check that the .count element exists before checking that a value is present to avoid potential errors:

await page.waitFor(() => {
  const count = document.querySelector('.count');
  return count && count.value.length;
});

If the element is not an input field, we can check that the .count element exists before checking that innerText is present to avoid potential errors:

await page.waitFor(() => {
  const count = document.querySelector('.count');
  return count && count.innerText.length;
});

Wait for CSS Selector

If the element is an input field that contains a placeholder, and you want to check if a value currently exists, you can use :not(:placeholder-shown):

await page.waitFor('.count:not(:placeholder-shown)');

If the element is an input field that does not contain a placeholder, and you want to check if the value attribute contains a string, you can use :not([value=""]):

await page.waitFor('.count:not([value=""])');

If the element is not an input field that does not have any child element nodes, we can use :not(:empty) to wait for the element to contain text:

await page.waitFor('.count:not(:empty)');

page.waitForXPath()

Wait for XPath

Otherwise, you can use page.waitForXPath() to wait for an XPath expression to locate element(s) on the page.

The following XPath expressions will work even if there are additional classes present on the element other than count. In other words, it will work like .count, rather than [class="count"].

If the element is an input field, you can use the following expression to wait for the value attribute to contain a string:

await page.waitForXPath('//*[contains(concat(" ", normalize-space(@class), " "), " test ") and string-length(@value) > 0]')

If the element is not an input field, you can use the following expression to wait for the element to contain text:

await page.waitForXPath('//*[contains(concat(" ", normalize-space(@class), " "), " count ") and string-length(text()) > 0]');
Grant Miller
  • 27,532
  • 16
  • 147
  • 165
  • [`waitFor` is deprecated](https://github.com/puppeteer/puppeteer/find/main#pagewaitforselectororfunctionortimeout-options-args) – ggorlen Mar 16 '22 at 02:54
-1
await page.waitFor((name) => {
 return document.querySelector('.top .name')?.textContent == name;
}, {timeout: 60000}, test_client2.name);
CyberT33N
  • 78
  • 5
-1

waitForXPath is simple and works well for finding an element with specific text.

const el = await page.waitForXPath('//*[contains(text(), "Text to check")]');
ggorlen
  • 44,755
  • 7
  • 76
  • 106