Fix the "not wrapped in act(...)" warning with Jest fake timers

Kent C. Dodds
InstructorKent C. Dodds

Share this video with your friends

Send Tweet
Published 2 years ago
Updated a year ago

There aren't many places you need to manually use act if you're using React Testing Library's async utilities, but if you're using fake timers, you need to manually use act to avoid missing bugs in your code.

In this lesson you'll learn how to identify the cause of act warnings and how to resolve them.

This is based on my blog post: Fix the "not wrapped in act(...)" warning

Kent Dodds: [0:00] Here we have an OrderStatus component that is running an effect on every 1,000 milliseconds, so that's one second, to check the status of an order by its ID. If that request is successful, then we'll update the status to be fulfilled with the data.

[0:15] Otherwise, we'll update the status to be rejected with the error. We have a clean up to clear the interval and make sure that the request that's returned is the current one. Then we render out our JSX to render the order status based on whether the current promise status is idle or pending, that will get a dot, dot, dot.

[0:33] If it's an error, then we'll render the error message. Otherwise, if it's fulfilled then we'll render the order status. We have a test for this and we're mocking the API module so that we can provide a mock implementation of checkStatus.

[0:46] In here we're using jest fake timers because we don't want to have to wait for a full second for this tick to happen because that would make our test run very slowly, and in general, will be less reliable. Then here we have our orderID and an OrderStatus. That's what we're mocking our checkStatus function to resolve to. We render that OrderStatus with that orderID. We make sure that the dot, dot, dot appears and that checkStatus is not called initially.

[1:12] Then we advance the timers by 1,000 milliseconds, so we get to that first tick function call to check the status. Then we want to wait until the OrderStatus appears on the screen and verify that checkStatus was called with the orderID and that it was called only one time.

[1:28] Our test is getting this warning that an update to OrderStatus inside our test was not wrapped in act. The specific update that it's complaining about is the update that happens when we advance our timer time.

[1:41] Specifically, when we advance our timer time, this tick function's going to get called, which triggers a set state. Because that's happening outside of the React call stack, React doesn't know when it's time to flush all the state updates, run all of the effects based on those state updates, and ensure that our DOM is in a stable state, so we can continue with our test.

[1:59] To fix this one, it's actually pretty simple. This is the line of code that's triggering that state update, and so this is the line of code that needs to be wrapped in act. To wrap it in act, we can come up here to our import of testing-library-react, which re-exports ReactDOMTestUtils act.

[2:16] We're going to grab that function from react-testing-library, and then we'll wrap this line in a function call to act. With that, our test now is warning-free, and our DOM is stable for us to start making assertions on the next line.

[2:32] In review, the reason we were getting this warning is because we were making a state update in a component outside of the React call stack by using this interval for every one second. To sidestep this issue, because we're using Jest fake timers, we wrap this advance timers by time in an act function call. That got rid of our warning.