react-hooks-testing-library version: 7.0.0
react version: 17.0.2
react-dom version: 17.0.2
node version: 14.16.0
npm version: 7.10.0
Problem
When using waitFor when Jest has been configured to use fake timers then the waitFor will not work and only "polls" once. After that the test just hangs until Jest comes in and fails the test with that the test exceeds the timeout time. Below is some code that showcases the problem.
import { renderHook } from '@testing-library/react-hooks'
it('does not work', async () => {
jest.useFakeTimers()
const { waitFor } = renderHook(() => {})
await waitFor(() => {
console.log('poll') // Is printed just once
expect(false).toBe(true)
}, { timeout: 25, interval: 10 })
// Fails with Exceeded timeout of 5000 ms for a test.
})
Basically the waitFor from @testing-library/react-hooks is using the faked setTimeout or setInterval which prevents it from working correctly.
There is a workaround (see suggested solution) but I recommend providing a nice error message when waitFor is used together with faked timers or maybe change the implemenation so it will work with fake timers.
Suggested solution
I found this issue and it seems that person has already been fixed in @testing-library/dom. From my perspective I can suggest maybe reuse that function instead of implementing it yourselves but I don't really know the internal structure / code.
But after finding that issue and realizing that is has been fixed there, then I use the following code as a workaround which works fine.
import { waitFor } from '@testing-library/react'
it('works', async () => {
jest.useFakeTimers()
await waitFor(() => {
console.log('poll') // Is printed twice
expect(false).toBe(true)
}, { timeout: 25, interval: 10 })
// Fails with false is not equal to true
})
A more real world scenario
If curios on the actual problem I'm facing is to test the following hook:
function useSomething({ onSuccess }) {
const poll = useCallback(async () => {
const result = await fetch(/* ... */)
if (result.ok) onSuccess()
}, [onSuccess])
useEffect(() => {
const id = setInterval(() => { poll() }, 2000)
return () => clearInterval(id)
}, [poll])
}
What I want to do is test that it invokes the onSuccess function on a successfull poll.
it('invokes the `onSuccess` on successfull poll', async () => {
const onSuccess = jest.fn()
jest.useFakeTimers()
const { waitFor } = renderHook(() => useSomething({ onSuccess }))
jest.runOnlyPendingTimers()
await waitFor(() => expect(onSuccess).toHaveBeenCalled())
})
react-hooks-testing-libraryversion: 7.0.0reactversion: 17.0.2react-domversion: 17.0.2nodeversion: 14.16.0npmversion: 7.10.0Problem
When using
waitForwhen Jest has been configured to use fake timers then thewaitForwill not work and only "polls" once. After that the test just hangs until Jest comes in and fails the test with that the test exceeds the timeout time. Below is some code that showcases the problem.Basically the
waitForfrom@testing-library/react-hooksis using the fakedsetTimeoutorsetIntervalwhich prevents it from working correctly.There is a workaround (see suggested solution) but I recommend providing a nice error message when
waitForis used together with faked timers or maybe change the implemenation so it will work with fake timers.Suggested solution
I found this issue and it seems that person has already been fixed in
@testing-library/dom. From my perspective I can suggest maybe reuse that function instead of implementing it yourselves but I don't really know the internal structure / code.But after finding that issue and realizing that is has been fixed there, then I use the following code as a workaround which works fine.
A more real world scenario
If curios on the actual problem I'm facing is to test the following hook:
What I want to do is test that it invokes the
onSuccessfunction on a successfull poll.