Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

waitFor should work with fake timers #661

Closed
kentcdodds opened this issue Jun 23, 2020 · 6 comments · Fixed by #662
Closed

waitFor should work with fake timers #661

kentcdodds opened this issue Jun 23, 2020 · 6 comments · Fixed by #662
Labels

Comments

@kentcdodds
Copy link
Member

kentcdodds commented Jun 23, 2020

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
Copy link

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
Copy link
Member Author

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

@kentcdodds
Copy link
Member Author

Got it! I'm pretty happy with it: #662

@ValentinH
Copy link

ValentinH commented Jun 23, 2020

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

@kentcdodds
Copy link
Member Author

🎉 This issue has been resolved in version 7.17.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@prashantjainlacework
Copy link

prashantjainlacework commented Feb 5, 2022

+1

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
4 participants