Reference for common test file migrations required by React 19.
Scope: limit edits to the test files the user names. Get confirmation from the user before changing shared render helpers or test setup files, and before batch edits across many files.
Fix test files in this order; each layer depends on the previous:
- Fix the
act import first, it unblocks everything else
- Replace
Simulate → fireEvent immediately after act
- Do the Full react-dom/test-utils cleanup to remove remaining imports
- Check StrictMode call counts by measuring actual counts and explaining each change
// Before: REMOVED in React 19:
import { act } from 'react-dom/test-utils';
// After:
import { act } from 'react';
If mixed with other test-utils imports:
// Before:
import { act, Simulate, renderIntoDocument } from 'react-dom/test-utils';
// After: split the imports:
import { act } from 'react';
import { fireEvent, render } from '@testing-library/react'; // replaces Simulate + renderIntoDocument
// Before: Simulate REMOVED in React 19:
import { Simulate } from 'react-dom/test-utils';
Simulate.click(element);
Simulate.change(input, { target: { value: 'hello' } });
Simulate.submit(form);
Simulate.keyDown(element, { key: 'Enter', keyCode: 13 });
// After:
import { fireEvent } from '@testing-library/react';
fireEvent.click(element);
fireEvent.change(input, { target: { value: 'hello' } });
fireEvent.submit(form);
fireEvent.keyDown(element, { key: 'Enter', keyCode: 13 });
If @testing-library/react is not already installed, ask the user before installing it, choose a release that supports React 19, and commit the updated lockfile.
| Old (react-dom/test-utils) | New location |
|---|
act
| import { act } from 'react'
|
Simulate
| fireEvent from @testing-library/react
|
renderIntoDocument
| render from @testing-library/react
|
findRenderedDOMComponentWithTag
| getByRole, getByTestId from RTL
|
findRenderedDOMComponentWithClass
| getByRole or container.querySelector
|
scryRenderedDOMComponentsWithTag
| getAllByRole from RTL
|
isElement, isCompositeComponent
| Remove as not needed with RTL |
isDOMComponent
| Remove |
React 19 StrictMode in development still runs effects as mount, unmount, then mount again, so effect call counts do not simply drop by half. Spy assertions that count calls may still change after the upgrade; attribute each change to its real cause.
Strategy: measure actual counts, and explain each one before changing an assertion.
- Before running tests, inspect the test script in the project package file and confirm it calls the expected test runner. Run tests only in a repository the user trusts, after the user confirms, and prefer an isolated environment with no secrets and limited network access.
- The command below assumes a Jest setup. Check which runner the project configures first; for a different runner, use the equivalent single file run for that runner, and ask the user if unsure.
- Replace the placeholder only with a test file path that exists in the repository and contains only letters, digits, dots, dashes, underscores and slashes. If a path contains other characters, stop and ask the user.
- Read the full output, including the Expected and Received lines and any other errors or warnings.
- Before editing an assertion, explain the count change by a known React 19 behavior and add a short comment beside the changed assertion stating the reason. Report unexplained differences to the user and leave those assertions as they are.
# Run the failing test and read the full output:
npm test -- --watchAll=false --testPathPattern="[filename]"
// Render-phase calls (component body) are still double-invoked in React 19 StrictMode:
expect(renderSpy).toHaveBeenCalledTimes(2); // stays at 2 for render body calls