When writing RTL tests one of the things that confuse developers the most are cryptic act() function errors logged into the console. ACT function is a big headache when it comes to testing.
In the following image, you can see an example that occurs after executing a test.
Usually, you don’t want to follow the advice of the warning.
Unexpected state updates in tests are bad.
Let’s imagine that we are trying to test a very simple component. The goal of this component is to show a button, and whenever a user clicks on that button, we want to make a network request to go and fetch some data, maybe get a list of users, and then show those users on the screen.
We’ll have two different pieces of state. One could be called ‘ShouldLoad’. Another might be the list of users that we are intending to eventually fetch.
Whenever a user clicks on the button, we will update ‘ShouldLoad’ to be true. That will cause the use effect function to run. Inside there we’re going to verify and make sure that ShouldLoad is true. And if it is, we’ll go and fetch some data. So we’re going to call this imaginary fetchUsers function and when we get back some data, we’re going to use it to update the user’s piece of state.
Now, if we try to write out a very simple test around this component, I can almost guarantee you we would probably get a warning around that act function very similar to the one we just got (You can see it in the image that we show at the top of the screen).
So the problem here is that after we click on that button, we’re then going to immediately go down to the next line of code and try to find all the different users that presumably we have fetched and rendered out on the screen. And then, our data fetching request is still pending. We’re still waiting on it to resolve. So there probably would not be any users and our test would probably fail.
Then after our test failed a very short amount of time later, that fake data request might end up finishing. We would update our state and then the users would be visible on the screen.
So the point here is that because we did not wait for that state update because we didn’t wait for the data requests to be finished (asynchronous operation), our state updated after the test already failed. And so we kind of had an unexpected state update.
The act function defines a window in time where state updates can (and should) occur
The ACT function is a function that is implemented by React DOM. It defines a window in time where a state update can and should occur inside one of our tests.
Pay attention, we are not using the React Testing Library. Here you can see more clearly the window in time that we mentioned above.
If any state update occurs in that period of time, React is going to be happy and we’re not going to see any warnings. If we ever update our state outside of these little windows, we will end up seeing the warning that we just saw in our terminal because it’s a sign that our state updated when we weren’t really ready for it.
React Testing Library uses ‘act’ behind the secenes for you!
React Testing library is going to automatically use the ACT function for you totally behind the scenes. You do not have to call ACT.
We have learned about different query functions like findBy and findAllBy. And the entire point of these findBy functions is that they are asynchronous in nature. They give us a period of by default one second where React testing library is going to watch our output from our component and see if some element appears is not visible or whatever else it is that we are looking for.
There’s another very similar function called waitFor. waitFor is going to kind of open up a span of by default one second and allow us to check for some condition inside of our components. We also get the userKeyboard and userClick functions. Those are synchronous functions. They’re not asynchronous.
All these different functions are going to automatically behind the scenes call act for you. So whenever we are using React Testing library, this is the preferred way of using ACT. We do not use the ACT function directly. Instead, we try to use these different functions and they kind of give us this window where our state can safely change.
To solve act warnings, you should use a ‘finBy’.
Usually, you don’t want to follow the advice of the warning. So any time that we start to see these act warnings, we are not going to do what our terminal says.
This is extraordinarily misleading because you’re going to read this warning and you’re probably going to do a Google search to figure out what the warning is trying to tell you. And you might come across some blog post or some article that says, Oh yeah, right, some code looks like this, or you might just read the terminal directly and say clearly, I need to call the act function.
Whenever you are writing your tests while using React Testing library, you almost always do not. Don’t. You don’t want to add a call to the ACT function inside of your test, even though the message says that you should. Instead, we should be using one of react testing libraries functions. And we are referring to asynchronous functions (findBy, findAllBy, or waitFor).
React Testing Library: Act Function
Options For Solving Act Warnings (from best to worst)