react-hooks-testing-library version: 3.4.1react-test-renderer version: 16.13.1react version: 16.13.1node version: 12.11.1npm (or yarn) version: 6.14.4_Using unstated-next hook pattern_
When using a hook that has a useEffect that awaits and (doesn't await) the waitForNextUpdate times out. See codesandbox link below.
function useMyHook() {
const [data, setData] = useState()
uesEffect(() => {
async function someAsync() {
if (doAsync) {
await doAsyncFn()
setData() // waitForNextUpdate resolves
} else {
setData() // waitForNextUpdate times out
}
}
}, [])
}
https://codesandbox.io/s/react-testing-library-demo-forked-o5z6t?file=/src/__tests__/hello.js
Add a nextTick hack
function useMyHook() {
const [data, setData] = useState()
uesEffect(() => {
async function someAsync() {
if (doAsync) {
await doAsyncFn()
setData() // waitForNextUpdate resolves
} else {
// Next tick hack
await new Promise((resolve) => resolve())
setData() // waitForNextUpdate resolves
}
}
}, [])
}
Is there something you want us to implement to help with this situation? We've had it raised before and the reality is there is very little we can do from the outside of your hook to know whether there will be an update coming or not. If you have any ideas, I'm happy to hear them.
I looked over previous issues and had a hard time finding this issue. I was putting it here more for documentation, ideally I don't need to be adding this hack to my production code and instead use a hack in my tests.
Can you point me to issues where you've described this issue? Is it that the update happens here and occurs before the wait takes place?
If this is the case could we attach a listener to the renderHook via options to catch this?
This is the issue I was referring to.
The problem is that renderHook just calls the function and when the async happens inside an effect, there is nothing in the result that we can intercept to know what is going in inside it. The async call might trigger a render afterwards, or not. There might not be an async call at all. To renderHook it's just a function.
Similarly, waitForNextUpdate simply waits for the next update. It triggers when react renders the component again. It has no way of knowing if this update will ever actually come or not. If might be really soon, or it might take a while. It might never come. To waitForNextUpdate, it's just the next render, regardless of the cause.
I'd love to continue, but I'm on 1% battery, so I'll stop now and come back to it in the morning. Let me know if you have any thoughts.
Just a small addition from my phone. In your example, if data was returned from your hook, you could probably do something with the waitFor utility instead of waitForNextUpdate. Something like
await waitFor(() => result.current.data === expectedData)
This will resolve as soon as the data matches what you want it to, even if it is already that value when the waiting starts.
But again, this relies on there being something external to the hook that you can use in your test.
@mpeyper awesome I'll give that a try. In addition, I'll add a PR for FAQ to prevent these issues in the future. Should this go in the Readme or the docs?
Docs and a link in the readme. Thanks.
I'll close this now, but if there is more discussion to be had, I'm happy to reopen it.