How to fix Test was not wrapped in act(...), state updates may not be detected in React

ReactINTERMEDIATEMEDIUMUpdated Dec 10, 2025· 108 views

This warning appears when testing React components with asynchronous state updates that aren't properly wrapped in React's act() utility. It indicates that your test isn't waiting for all React updates to complete before making assertions, which can lead to flaky tests or false positives. The warning commonly occurs when testing components with useEffect hooks, async data fetching, or user interactions that trigger state changes.

Quick fix

Fixes Test was not wrapped in act(...), state updates may not be detected

import { act } from 'react';
import { render, screen } from '@testing-library/react';

test('async component update', async () => {
  await act(async () => {
    render(<MyAsyncComponent />);
  });
  // Now assertions are safe
  expect(screen.getByText('Loaded')).toBeInTheDocument();
});
  1. Wrap async operations in act()
  2. Use Testing Library's async queries (findBy*)
  3. Await user interactions that trigger state updates
  4. Use waitFor for custom async assertions
react — error
import { act } from 'react';
import { render, screen } from '@testing-library/react';
test('async component update', async () => {
await act(async () => {
render(<MyAsyncComponent />);
});
// Now assertions are safe
expect(screen.getByText('Loaded')).toBeInTheDocument();
});
Test was not wrapped in act(...), state updates may not be detected

What this error means

The 'act()' warning is React's way of telling you that state updates are happening outside of a controlled test environment. React needs to know when state updates will occur during tests so it can properly schedule, flush, and apply them to the DOM before assertions are made. When you perform actions that trigger state updates (like clicking buttons, fetching data, or setting timeouts), React doesn't automatically know when those updates will complete. The act() function creates a boundary where React can track all updates and ensure they're fully processed before moving on. This warning is particularly common with React Testing Library because it encourages testing real user interactions and asynchronous behavior. Without proper act() wrapping, your tests might: 1. Make assertions before state updates complete 2. Have race conditions between test code and React's rendering cycle 3. Produce inconsistent test results (flaky tests) 4. Miss actual bugs because updates aren't being detected

Typical symptoms

  • Console warning: 'Warning: An update to Component inside a test was not wrapped in act(...)'
  • Tests pass but produce warning messages in the console output
  • Async state updates (like data fetching) cause warnings even when test logic is correct
  • Components with useEffect that call async functions trigger the warning on render
  • User interactions (clicks, typing) produce warnings when they trigger state changes
  • Tests are flaky - sometimes pass, sometimes fail with the same code

Common causes

  1. Async state updates inside useEffect without proper act() wrapping
  2. Using fireEvent or userEvent without awaiting subsequent state changes
  3. Missing await on async functions that trigger React state updates
  4. Not using act() when testing components with timers (setTimeout, setInterval)
  5. Testing environment not configured with IS_REACT_ACT_ENVIRONMENT=true
  6. Using getBy queries instead of findBy for elements that appear asynchronously
  7. State updates triggered by promises that aren't properly awaited in tests

How to fix "Test was not wrapped in act(...), state updates may not be detected"

1Wrap async operations in act()

When testing components with async state updates, wrap the code that triggers updates in act() from React's test utilities:

javascript
import { act } from 'react';
import { render, screen } from '@testing-library/react';

test('async component update', async () => {
  await act(async () => {
    render(<MyAsyncComponent />);
  });
  // Now assertions are safe
  expect(screen.getByText('Loaded')).toBeInTheDocument();
});

For operations that happen after render, you may need multiple act() calls. Remember that act() returns a promise for async operations.

2Use Testing Library's async queries (findBy*)

Testing Library provides async queries (findBy*) that automatically handle act() wrapping. Always use await with these queries for elements that appear asynchronously:

javascript
import { render, screen } from '@testing-library/react';

test('async element appearance', async () => {
  render(<MyComponent />);
  // findBy queries wait for the element and handle act() internally
  const element = await screen.findByText('Loaded data');
  expect(element).toBeInTheDocument();
});

findBy* queries are the preferred solution for waiting for elements that appear after async operations. They combine waitFor and getBy with proper act() handling.

3Await user interactions that trigger state updates

In React Testing Library v14+, userEvent methods return promises. Always await them when they trigger state updates:

javascript
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

test('user interaction with state update', async () => {
  const user = userEvent.setup();
  render(<MyForm />);

  // Await the click since it triggers a state update
  await user.click(screen.getByRole('button', { name: 'Submit' }));

  // Now wait for the resulting state change
  await screen.findByText('Submission complete');
});

Even fireEvent should be wrapped in act() if it triggers async state updates.

4Use waitFor for custom async assertions

For scenarios not covered by findBy queries, use waitFor to wrap assertions that depend on async state:

javascript
import { render, screen, waitFor } from '@testing-library/react';

test('custom async assertion', async () => {
  render(<MyComponent />);

  await waitFor(() => {
    expect(screen.getByText('Updated text')).toBeInTheDocument();
  });
});

waitFor automatically handles act() wrapping and retries the assertion until it passes or times out (default: 1000ms).

5Handle async useEffect patterns properly

For components with async useEffect, you need to wait for the effect to complete:

javascript
import { act } from 'react';
import { render, screen } from '@testing-library/react';

test('component with async useEffect', async () => {
  await act(async () => {
    render(<ComponentWithAsyncEffect />);
  });

  // Wait for the async effect to complete
  await screen.findByText('Data loaded');
});

Alternatively, mock the async function to resolve immediately in tests using Jest mocks or similar.

6Configure test environment and check for common issues

Ensure your test environment is properly configured:

javascript
// jest.setup.js or similar
global.IS_REACT_ACT_ENVIRONMENT = true;

Also check for:
1. Missing await on promises
2. Unmocked timers (use jest.useFakeTimers() for setTimeout/setInterval)
3. Nested act() calls (usually unnecessary)
4. State updates in cleanup functions (useEffect return)

Most testing frameworks set IS_REACT_ACT_ENVIRONMENT automatically, but verify if you see environment warnings.

Advanced notes

The act() warning is actually helpful—it catches potential race conditions in your tests. In React 18 with concurrent features, timing is even more critical.

Key insights:
1. act() ensures all updates (renders, effects, layout effects) are flushed
2. Async act() (await act(async () => {})) handles promises and async/await
3. Testing Library's utilities (findBy, waitFor, waitForElementToBeRemoved) are already wrapped with act()
4. In React 18, you might see fewer warnings due to improved automatic batching, but the principles remain

Common anti-patterns to avoid:
• Using setTimeout in tests to wait for updates (use waitFor instead)
• Multiple unnecessary act() wrappers
• Not awaiting userEvent in v14+
• Testing implementation details instead of user-visible outcomes

Remember: The goal is to write tests that resemble how users interact with your application. React Testing Library's async utilities are designed with this philosophy in mind.

Frequently asked questions

What does "Test was not wrapped in act(...), state updates may not be detected" mean?
The 'act()' warning is React's way of telling you that state updates are happening outside of a controlled test environment. React needs to know when state updates will occur during tests so it can properly schedule, flush, and apply them to the DOM before assertions are made. When you perform actions that trigger state updates (like clicking buttons, fetching data, or setting timeouts), React doesn't automatically know when those updates will complete.
How do I fix "Test was not wrapped in act(...), state updates may not be detected"?
This warning appears when testing React components with asynchronous state updates that aren't properly wrapped in React's act() utility. It indicates that your test isn't waiting for all React updates to complete before making assertions, which can lead to flaky tests or false positives. The warning commonly occurs when testing components with useEffect hooks, async data fetching, or user interactions that trigger state changes.
What causes "Test was not wrapped in act(...), state updates may not be detected"?
Async state updates inside useEffect without proper act() wrapping Using fireEvent or userEvent without awaiting subsequent state changes Missing await on async functions that trigger React state updates
Is the "Test was not wrapped in act(...), state updates may not be detected" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading