mrkeyoor.com_
Tue 22 Sept 00:44 UTC
npmTestingupdated 21 Sept 2026

react-test-renderer review

react-test-renderer is React's deprecated renderer for turning a component tree into JavaScript objects without creating DOM or native host nodes. Tests can snapshot `toJSON()`, inspect component types and props through `root`, replace props with `update()`, or provide fake host instances for refs. React now describes this environment as contrived because its queries expose implementation structure that may change without notice. Version 19.2.8 matches the React 19.2.8 peer line; its release notes contain a Server Components decoding improvement rather than a test-renderer feature. The package README says it is unmaintained, will be removed in a future version, and warns on `create()` under React 19.

Verdict

Do not install react-test-renderer for a new suite. Keep 19.2.8 only as temporary support for old object-tree tests, then move web and native assertions to the testing libraries React itself recommends.

We installed it

Lab card: what happened when we installed react-test-rendererScreenshot of react-test-renderer documentation
Install✓ · 1.2s4 packages on disk · 2 MB
ImportESM import works · require() works · CommonJS package
Browser36.6 KBgzipped (122.1 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does react-test-renderer install cleanly?

Yes. In a fresh container with an empty cache, npm install react-test-renderer finished in 1 seconds, leaving 4 packages and 2 MB on disk. npm audit reported no known vulnerabilities.

How much does react-test-renderer add to a browser bundle?

36.6 KB gzipped (122.1 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does react-test-renderer work with both ESM and CommonJS?

Yes. Both import 'react-test-renderer' and require('react-test-renderer') worked in Node 22 in our run. The package is published as CommonJS.

Does react-test-renderer include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

react-test-renderer or @testing-library/react: which should you use?

@testing-library/react: Use it for web integration tests built around DOM roles, labels, text, and user-visible behavior. Do not install react-test-renderer for a new suite.

When should you not use react-test-renderer?

You are writing a new React test. The package README marks the renderer deprecated, unmaintained, and scheduled for removal.

API stability2/5The small API of `create`, `act`, `toJSON`, `toTree`, `root`, `update`, `unmount`, and `getInstance` has barely moved, so legacy tests look stable today. The package README states that React internals exposed through this renderer may change without notice and that the package will be removed in a future version. React 19 already adds a warning to every create call, making planned removal more relevant than historical method continuity.
Docs2/5The package README gives a direct deprecation notice, names web and React Native replacements, explains the concern about internal inspection, and links to the old API page. That page documents JSON output, tree navigation, node mocks, updates, unmounting, and class instances. It lives on the archived legacy React site, while react.dev provides a warning page rather than maintained task documentation for this renderer.
Maintenance1/5The React repository is active, with 247,882 stars, a push on August 24, 2026, and 1,266 open issues and pull requests. Those are signals for React as a monorepo, not this package's future. The renderer README explicitly says the package is deprecated and no longer maintained. Version 19.2.8 was published alongside React, and its release note lists a Server Components decoding change rather than renderer work.
Ecosystem2/5The npm endpoint still counted 8,619,500 downloads in the latest completed week, which reflects a large installed base of Jest snapshots and React Native tests. The current package points web users to Testing Library and browser environments, and points native users to React Native Testing Library. Tooling momentum therefore sits around DOM and native behavior testing even though old lockfiles continue downloading this package.

Use it if

  • An existing snapshot suite already depends on its JSON shape and needs a short maintenance window before migration.
  • A custom renderer test genuinely needs React component nodes rather than browser roles, events, focus, or accessibility behavior.
  • Legacy tests call class component instances or search by component type and cannot all be replaced in the current change.
  • A migration needs side-by-side old snapshots and new Testing Library assertions to verify behavior during conversion.
Skip it if

Setup reality

We installed react-test-renderer 19.2.8 in a fresh Node 22 Bookworm container. npm finished in 1.2 seconds, left 4 packages, and used 2 MB on disk. The package is 992 KB unpacked, has 2 direct dependencies and one peer dependency, and carries an MIT license. npm audit found zero known vulnerabilities. Both CommonJS require and ESM import worked, but the package contains no TypeScript declarations.

Match the renderer to React exactly enough to satisfy its peer range: 19.2.8 declares react ^19.2.8. Calling create() on React 19 writes a deprecation warning, by design. Do not hide all console errors to quiet it; broad filtering can erase missing-act and rendering warnings. If temporary suppression is unavoidable, match the one message and attach a removal ticket to the setup code.

There is no DOM. Test instances expose React types and props, and calling an event prop directly does not simulate bubbling, default prevention, disabled controls, focus, or browser input behavior. Host refs receive null unless createNodeMock returns a fake node. Any component that measures, focuses, observes, or calls browser methods needs a hand-built mock, which can make the test validate the mock rather than user behavior.

Updates and async work belong inside act imported from React. Unmount roots so effect cleanup runs and subscriptions do not leak between tests. Our browser bundle measured 122.1 KB minified and 36.6 KB gzipped, even though this is test-only code; keep it out of production dependencies and client builds. Plan migration to @testing-library/react for web or its React Native counterpart before a future React version removes the renderer.

Patterns

Capture the legacy JSON tree snapshot-json-tree

import TestRenderer from 'react-test-renderer';
import { act } from 'react';

let renderer;
await act(async () => {
  renderer = TestRenderer.create(
    <Link href='/account'>Account</Link>
  );
});
expect(renderer.toJSON()).toMatchSnapshot();

React 19 logs a deprecation warning when create() runs. Keep this pattern only while migrating an existing snapshot.

Locate one component instance find-component-type

const button = renderer.root.findByType(Button);
expect(button.props.disabled).toBe(true);

findByType throws unless exactly one node matches. The assertion knows the component implementation, which is the coupling React warns against.

Collect nodes with matching props find-nodes-by-props

const rows = renderer.root.findAllByProps({
  kind: 'invoice-row',
});
expect(rows).toHaveLength(3);

These are React props rather than resolved DOM attributes or accessibility semantics.

Call a handler directly invoke-event-prop

const button = renderer.root.findByType(Button);
await act(async () => {
  button.props.onClick();
});

Direct invocation skips event propagation, default actions, focus changes, and disabled-element behavior.

Render the root with new input update-root-props

await act(async () => {
  renderer.update(<Counter count={2} />);
});
expect(renderer.toJSON()).toMatchSnapshot();

update preserves state when React reconciles the new root with the old one. It is not a fresh mount.

Supply a fake node for refs mock-host-reference

const focus = jest.fn();
let renderer;
await act(async () => {
  renderer = TestRenderer.create(<SearchInput />, {
    createNodeMock(element) {
      return element.type === 'input' ? { focus } : null;
    },
  });
});
expect(focus).toHaveBeenCalled();

The object is your mock, not a real input. Browser layout, selection, and focus state remain untested.

Read the internal rendered tree inspect-component-tree

const tree = renderer.toTree();
console.log(tree.type);
console.log(tree.props);
console.log(tree.rendered);

toTree() includes user components that toJSON() leaves out. It is the most implementation-sensitive representation in this package.

Access a legacy class root read-class-instance

const instance = renderer.getInstance();
expect(instance.state.open).toBe(false);

Function components return null. Reaching into instance state is a migration candidate for a behavior-level assertion.

Run effect cleanup unmount-test-root

await act(async () => {
  renderer.unmount();
});
expect(unsubscribe).toHaveBeenCalled();

Unmount each retained root, preferably in test cleanup, so subscriptions and timers cannot escape into another case.

Replace a type query with a role query migrate-role-query

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

const user = userEvent.setup();
render(<SaveButton />);
await user.click(screen.getByRole('button', { name: 'Save' }));
expect(save).toHaveBeenCalled();

The new assertion observes an accessible button and a user interaction instead of the component name and raw prop.

Replace a broad snapshot with visible output migrate-snapshot-text

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

render(<Invoice total='$42.00' />);
expect(screen.getByText('$42.00')).toBeVisible();

Targeted assertions usually survive wrapper and component refactors that rewrite object snapshots without changing behavior.

Quarantine one deprecation message limit-warning-suppression

const originalError = console.error;
beforeAll(() => {
  jest.spyOn(console, 'error').mockImplementation((message, ...args) => {
    if (String(message).includes('react-test-renderer is deprecated')) return;
    originalError(message, ...args);
  });
});
afterAll(() => console.error.mockRestore());

Treat this as short-lived migration code. A blanket console.error mock hides other React warnings and real failures.

Alternatives

PackageRegistryPick it when
@testing-library/reactnpmUse it for web integration tests built around DOM roles, labels, text, and user-visible behavior.
@testing-library/react-nativenpmUse it for React Native integration tests; the React package README names it as the replacement.
jsdomnpmUse it as a DOM environment when plain browser-like APIs and your own assertion layer are enough.
react-shallow-renderernpmUse only for a legacy shallow-rendering migration where moving to behavior tests cannot happen in the same release.

More testing guides

pytest · chai · vitest · jsdom · playwright · coverage · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.