testing-library / dom-testing-library

🐙 Simple and complete DOM testing utilities that encourage good testing practices.
https://testing-library.com/dom
MIT License
3.27k stars 466 forks source link

waitFor should work with fake timers #661

Closed kentcdodds closed 4 years ago

kentcdodds commented 4 years ago

Relevant code or config:

const {waitFor} = require('@testing-library/dom')

beforeEach(() => jest.useFakeTimers())
afterEach(() => jest.useRealTimers())

test('example', async () => {
  const doAsyncThing = () =>
    new Promise((r) => setTimeout(() => r('data'), 300))
  let result
  doAsyncThing().then((r) => (result = r))

  await waitFor(() => expect(result).toBe('data'))
})

What you did:

I expected waitFor to work even with jest fake timers enabled

What happened:

It times out because there's nothing telling jest to advance timers

Reproduction:

https://github.com/kentcdodds/testing-library-fake-timers

Problem description:

When enabling fake timers with DOM Testing Library, the waitFor utility doesn't work (so none of the other async utils will either). The reason for this is there's nothing telling the clock to advance the timers.

Suggested solution:

I'm pretty sure we actually do want the async utils to work seamlessly when fake timers are enabled.

Here's a waitFor function that will work only if fake timers are enabled. Maybe we can detect fake timers (we already have a function for this) and if they're enabled, then we could do this instead?

async function waitForWithFakeTimers(cb) {
  let waiting = true
  while (waiting) {
    await act(() =>
      Promise.resolve()
        .then(() => jest.runAllTimers())
        .then(() => new Promise(resolve => setImmediate(resolve))),
    )
    try {
      cb()
      waiting = false
    } catch {}
  }
}

It's pretty basic, it doesn't support timeout etc. But it's a good start.

Mostly, I'm looking for feedback. Should we do something like this if fake timers are enabled? Or is there another approach we can take?

tannerlinsley commented 4 years ago

I think this is absolutely better than the test failing incorrectly. So I vote yes detect and use this. Improvements can be made incrementally.

kentcdodds commented 4 years ago

I've got another idea that I think will work better. Working on it now: https://kcd.im/discord

kentcdodds commented 4 years ago

Got it! I'm pretty happy with it: https://github.com/testing-library/dom-testing-library/pull/662

ValentinH commented 4 years ago

Really cool idea. I spent quite some time yesterday to help a colleague debug a test exactly because of this!

kentcdodds commented 4 years ago

:tada: This issue has been resolved in version 7.17.0 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

prashantjainlacework commented 2 years ago

+1

I also noticed that jest uses sinon fake timers. Is that true?