Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make Playwright wait for JavaScript execution to finish (reliably!)

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.

like image 388
brillout Avatar asked Jul 02 '26 11:07

brillout


1 Answers

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.

like image 140
Md. Abu Taher Avatar answered Jul 04 '26 01:07

Md. Abu Taher