act
is a test helper to apply pending React updates before making assertions.
await act(async actFn)
To prepare a component for assertions, wrap the code rendering it and performing updates inside an await act()
call. This makes your test run closer to how React works in the browser.
Reference
await act(async actFn)
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.
The name act
comes from the Arrange-Act-Assert pattern.
it ('renders with button disabled', async () => {
await act(async () => {
root.render(<TestComponent />)
});
expect(container.querySelector('button')).toBeDisabled();
});
Parameters
async actFn
: An async function wrapping renders or interactions for components being tested. Any updates triggered within theactFn
, are added to an internal act queue, which are then flushed together to process and apply any changes to the DOM. Since it is async, React will also run any code that crosses an async boundary, and flush any updates scheduled.
Returns
act
does not return anything.
Usage
When testing a component, you can use act
to make assertions about its output.
For example, let’s say we have this Counter
component, the usage examples below show how to test it:
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(prev => prev + 1);
}
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={handleClick}>
Click me
</button>
</div>
)
}
Rendering components in tests
To test the render output of a component, wrap the render inside act()
:
import {act} from 'react';
import ReactDOMClient from 'react-dom/client';
import Counter from './Counter';
it('can render and update a counter', async () => {
container = document.createElement('div');
document.body.appendChild(container);
// ✅ Render the component inside act().
await act(() => {
ReactDOMClient.createRoot(container).render(<Counter />);
});
const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 0 times');
expect(document.title).toBe('You clicked 0 times');
});
Here, we create a container, append it to the document, and render the Counter
component inside act()
. This ensures that the component is rendered and its effects are applied before making assertions.
Using act
ensures that all updates have been applied before we make assertions.
Dispatching events in tests
To test events, wrap the event dispatch inside act()
:
import {act} from 'react';
import ReactDOMClient from 'react-dom/client';
import Counter from './Counter';
it.only('can render and update a counter', async () => {
const container = document.createElement('div');
document.body.appendChild(container);
await act( async () => {
ReactDOMClient.createRoot(container).render(<Counter />);
});
// ✅ Dispatch the event inside act().
await act(async () => {
button.dispatchEvent(new MouseEvent('click', { bubbles: true }));
});
const button = container.querySelector('button');
const label = container.querySelector('p');
expect(label.textContent).toBe('You clicked 1 times');
expect(document.title).toBe('You clicked 1 times');
});
Here, we render the component with act
, and then dispatch the event inside another act()
. This ensures that all updates from the event are applied before making assertions.
Troubleshooting
I’m getting an error: “The current testing environment is not configured to support act”(…)”
Using act
requires setting global.IS_REACT_ACT_ENVIRONMENT=true
in your test environment. This is to ensure that act
is only used in the correct environment.
If you don’t set the global, you will see an error like this:
To fix, add this to your global setup file for React tests:
global.IS_REACT_ACT_ENVIRONMENT=true