Skip to content
tezvyn:

The `act()` Utility: Syncing Tests with React's Updates

Source: react.devMediumHow cards are made

The `act()` Utility: Syncing Tests with React's Updates

The act() utility ensures your tests wait for React to finish updating the DOM before you make assertions. Use it to wrap component renders and state updates. The footgun is forgetting to use await with an async function, which can lead to flaky tests.

Why it exists

React updates the DOM asynchronously for performance. This creates a timing problem for tests: an assertion might run before a state update has actually rendered, causing a false failure. act() was created to bridge this gap, pausing the test until React is done.

The mental model

Think of act() as a gatekeeper for your test assertions. It tells your test runner, "Hold on, React is processing an update. I will let you proceed to check the DOM only after all state changes, effects, and re-renders from this interaction are completely finished." It forces your test's timeline to align with React's rendering timeline.

How it works

When you wrap code in await act(async () => { ... }), any React updates triggered inside are queued. act() then flushes this queue, processes all changes, and applies them to the DOM. Because it's async, it also waits for updates inside promises or other async code to resolve before letting your test continue. This ensures the component's state and the DOM are fully in sync before you make an assertion.

When to use it

Use act() when writing tests without a library like React Testing Library (RTL), which handles it for you. You need it when you manually render a component (e.g., with ReactDOM.createRoot().render()) or when you manually trigger an event that causes a state update.

When not to use it

You generally don't need to call act() yourself if you're using a modern testing library like React Testing Library. Its helpers, like render() and fireEvent, are already wrapped in act() internally. Adding it yourself is redundant and adds noise.

One canonical example

To test a simple counter, you must wrap both the initial render and the click event in act(). First, await act(async () => { root.render(<Counter />); }); ensures the initial render is complete. Then, to test a click, you'd wrap the event dispatch: await act(async () => { button.click(); });. Only after this second act() call can you reliably assert that the counter's text has updated from 0 to 1.

Interview question

In which scenario would you typically NOT need to manually wrap your test code with `act()`?

  • a.When using React Testing Library's `render` and `fireEvent` utilitiesCorrect
  • b.When testing a component that only displays static content
  • c.When rendering a component directly using `ReactDOM.createRoot().render()`
  • d.When asserting immediately after a user interaction that changes state
Why?

Modern testing libraries like React Testing Library (RTL) already wrap their helpers in `act()` internally, making manual `act()` calls redundant. Even when testing static content (B), if you are manually rendering the component without RTL, `act()` is still necessary to ensure the initial render is fully committed to the DOM before making assertions.

Just read this? Test yourself on what you have been reading.

Read the original → react.dev

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on react — each one lists the topics its interview covers.

See open roles