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.
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
When testing components with async state updates, wrap the code that triggers updates in act() from React's test utilities:
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.
Testing Library provides async queries (findBy*) that automatically handle act() wrapping. Always use await with these queries for elements that appear asynchronously:
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.
In React Testing Library v14+, userEvent methods return promises. Always await them when they trigger state updates:
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.
For scenarios not covered by findBy queries, use waitFor to wrap assertions that depend on async state:
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).
For components with async useEffect, you need to wait for the effect to complete:
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.
Ensure your test environment is properly configured:
// 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.
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.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite