Instead of:
test('Some interactive component', async () => {
await page.goto('http://localhost:3000/')
// Using a timeout of 1 second, to wait the hydration to finish. (E.g. the
// client attaching an event handler to <button>.)
await page.evaluate(() => setTimeout(() => window.__ready = true, 1000))
await page.waitForFunction(() => window.__ready)
await page.click('button')
/* ... */
})
Is there a way to do this:
test('Some interactive component', async () => {
await page.goto('http://localhost:3000/')
await waitForJavascriptExecution()
await page.click('button')
/* ... */
})
function waitForJavascriptExecution() {
// TODO: how can we check whether the JavaScript finished executing?
// - There doesn't seem to be a way to check whether the JavaScript event queue
// is empty
// - `setTimeout(() => window.__ready = true, 0)` doesn't work (although
// it should?)
}
I've tried numerous approaches but none of them worked. None of the related Stack Overflow Q&As provide any reliable answer.
Using any kind of timeout isn't an acceptable solution as 1. it considerably slows down tests, 2. tests occasionally fail, and 3. fiddling around to find the right timeout amount isn't particularly fun.
Instead of fiddling around with the timeout, you can wait for the page to load properly, including the element to be visible.
await page.goto(url, {waitUntil: 'networkidle'})
Bear in mind, this is discouraged according to playwright documentation, but we should see which works for our case and which one does not.
If we want to wait for the element to be visible properly, use waitForSelector method which by default waits till the element is visible properly (many reactjs pages do not add the elements to the dom on page load, until a good amount of js have been executed.)
await page.waitForSelector(selector)
Most of the time this is all you will need.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With