Skip to content

Resolving React Test act Deprecation Warnings

Problem Statement

When testing React components with Jest and React Testing Library, developers often encounter this warning:

"Warning: An update to [Component] inside a test was not wrapped in act(...)."

Despite following this instruction, your IDE may flag the act method as deprecated when using React 18+, causing confusion about correct implementation. The core issues are:

  • React 18's state batching changes
  • Outdated Testing Library dependencies
  • Incorrect act imports
  • Conflicts between testing packages

1. Update Testing Library Dependencies

Primary Fix: Upgrade to compatible versions that support React 18's act changes:

bash
npm install @testing-library/react@^15.0.6
npm install @types/react@18.3.1

Compatibility Notes

  • Requires React ≥18.3.1
  • Fixes type declarations and prevents deprecated warnings (Release Notes)

2. Correct Import for act

Import from React’s package instead of testing utils:

diff
- import { act } from '@testing-library/react'
+ import { act } from 'react'

3. Eliminate Conflicting Packages

Uninstall deprecated libraries causing type conflicts:

bash
npm uninstall react-test-renderer

Updated Test Example

javascript
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { act } from 'react'; // Correct import
import ContactFormController from '.';

describe('Contact Form Controller tests', () => {
  it('renders loader and disables submit on form submit', async () => {
    render(<ContactFormController />);
    const submitBtn = screen.getByTestId('contact-submit-button');

    // Wrap interactions in act
    await act(async () => {
      await userEvent.type(screen.getByLabelText(/First Name/i), 'Captain');
      await userEvent.type(screen.getByLabelText(/Last Name/i), 'Bob');
      await userEvent.type(screen.getByLabelText(/Email/i), 'captain@bob.com');
      await userEvent.type(
        screen.getByPlaceholderText(/Greetings/i),
        'Captain Ahoy'
      );
      await userEvent.click(submitBtn);
    });

    expect(screen.getByRole('alert')).toBeInTheDocument();
    expect(submitBtn).toBeDisabled();
  });
});

Key Improvements:

  • Uses screen for queries (Best Practice)
  • Adds await to all userEvent interactions
  • Corrects act import source

Why These Solutions Work

  1. Dependency Updates:
    React 18.3.1+ exports act via the main react package. Newer React Testing Library versions resolve type conflicts with this change.

  2. Async Event Handling:
    Modern userEvent methods are asynchronous. Using await ensures state updates complete before assertions.

  3. IDE Warning Resolution:
    Upgraded @types/react provides accurate TypeScript definitions matching React's API changes.

Final Recommendations

  • Update routinely: Keep alignment between React and Testing Library versions.
  • Avoid unnecessary act: Most user interactions and queries handle act internally. Only use explicit act for uncontrolled state updates.
  • Use Testing Library's waitFor for complex async flows instead of manual act wrapping.

React 18 Testing Rules

  • Automatic batching handles most common scenarios
  • Manual act is required only for non-user-triggered updates (e.g., timers, external subscriptions)
  • Use await userEvent for interactions

By updating dependencies and adjusting imports, you eliminate deprecation warnings while ensuring tests validate component behavior correctly.