Reputation: 4707
Trying puppeteer for the first time and it is amazing. I need to wait for a page to fetch and render new data after a button click. This does not cause a navigation (the url is the same) so the following code does not work (it gives timeout exception):
await Promise.all([
myButton.click()
page.waitForNavigation()
])
What's the correct way to wait for the page to fetch/render async data on click?
Upvotes: 7
Views: 10432
Reputation: 2818
Assuming the DOM changes in some way, you can wait for a specific element or selector.
Maybe an image appears.
await myButton.click();
await page.waitForSelector('img.success');
Maybe some element with an ID attribute is inserted into the DOM.
await myButton.click();
await page.waitForSelector('#newElementThatAppeared');
If you're unfamiliar with DOM selectors, you can read up here and here. They're powerful and easy to use.
Update - Custom wait predicate.
If we always know the length...
await myButton.click();
await page.waitFor(() => document.querySelectorAll('ul.specialList li').length > 5);
If we know the length will increase
const listSize = await page.evaluate(() => document.querySelectorAll('ul.specialList li').length);
await myButton.click();
await page.waitFor(() => document.querySelectorAll('ul.specialList li').length > listSize);
Upvotes: 9
Reputation: 4707
Well, kind of an hack but didn't find any better solution for now. Basically I am comparing the number of specific li elements before and after the button click to verify when new data has been loaded.
const wait = time => new Promise(resolve => setTimeout(resolve, time))
let data = await page.evaluate(_ => document.querySelectorAll("li.className").length)
let isDataLoaded = false
await page.click("#myButton")
while(!isDataLoaded) {
if (data.length !== await.page.evaluate(_ => document.querySelectorAll("li.className").length)) {
isDataLoaded = true
}
await wait(100)
}
// new data should be loaded and rendered now in the page
// [...]
Upvotes: 0
Reputation: 1225
First of all await Promise.all
some kind of concurrency and if you need click and then wait split this with
await page.click('#selector');
const finalResponse = await page.waitForResponse(response => response.url() === 'https://example.com' && response.status() === 200);
return finalResponse.ok();
And be noted:
This resolves when the page navigates to a new URL or reloads.
Upvotes: 0