11 Aug 2019
One challenge of writing React tests is knowing where you are in the component lifecycle. Is the component mounted? In the middle of a state update? Has it received props? Answering these questions determines what the tester should assert. Through a colleague at work, I recently found React
16.9 includes an
act function that can take an
act itself, however - which stands for the Arrange-Act-Assert testing pattern existed far before
16.9, and allows you to guarantee all state updates have completed before making assertions on a component. From the docs:
When writing UI tests, tasks like rendering, user events, or data fetching can be considered as “units” of interaction with a user interface. React provides a helper called act() that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions…
I recommend the aforementioned testing recipes page for a full walkthrough of
act examples as well as Sunil Pai’s examples - Sunil originally authored the PR that acted
act. For this blog post, I want to walk through a simple example that will show the potential value of this testing utility.
Note - all examples below can be found in this CodeSandbox
Let’s start with a sync
act. Consider a component with just a
useEffect call that sets a value on the component:
The difference between using
act and not using
act is the test waiting on the callback inside
async act - again, newly released in React
16.9 - allows you to wait on promises to resolve and state updates to complete.
Here’s what an async component might look like…
…and the differences between sync and async
react-testing-library are already pulling
act into their API and have means of accessing it (or should have in the future), so if you’re using either library, the above boilerplate isn’t necessary. That said, I found it useful to go through this exercise to get a sense of how
I’m extremely excited React offers this utility - it’s extremely useful in fixing things like intermittently failing tests that rely on promises resolving in some fixed amount of time (which hopefully never existed in your test suite anyways). React testing forces you to understand the lifecycle of your components and how they handle state.
act is a great way to enhance that understanding.