mrkeyoor.com_
Wed 23 Sept 09:33 UTC
npmTestingupdated 23 Sept 2026

react-shallow-renderer review

react-shallow-renderer 16.15.0 executes one React component and returns the React element that component produced without mounting its children or creating a DOM. Tests can inspect output props, rerender with new inputs, drive a returned callback, or reach a class instance. The release supports React 16, 17, and 18 through its peer range. It deliberately omits refs, effects, committed host behavior, and child integration, making it a compatibility dependency for older structural tests rather than a current default.

Verdict

Our react-shallow-renderer 16.15.0 browser build measured 23.3 KB minified and 7.2 KB gzipped, yet it cannot mount children, refs, or effects and its peer range ends at React 18. Retain it for legacy shallow assertions; start new component tests with behavior-focused tooling.

We installed it

Lab card: what happened when we installed react-shallow-rendererScreenshot of react-shallow-renderer documentation
Install✓ · 1.2s6 packages on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browser7.2 KBgzipped (23.3 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-shallow-renderer install cleanly?

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

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

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

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

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

Does react-shallow-renderer include TypeScript types?

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

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

@testing-library/react: Use it for React web tests that query rendered DOM and exercise visible behavior. Our react-shallow-renderer 16.15.0 browser build measured 23.3 KB minified and 7.2 KB gzipped, yet it cannot mount children, refs, or effects and its peer range ends at React 18.

When should you not use react-shallow-renderer?

You use React 19: the published peer dependency stops at React 18 and the implementation reads React private internals

API stability3/5For React 16 through 18, the constructor, `render`, `getRenderOutput`, `getMountedInstance`, and `unmount` surface has stayed small and recognizable. Version 16.15.0 understands function and class components plus memo, forwardRef, and several state hooks. Its weak point sits below that public surface: the implementation reads React private internals and hard-codes element behavior, so a React upgrade can break it even when the shallow renderer API itself has not changed.
Docs2/5The README explains one-level rendering, shows a complete output assertion, lists installation commands, warns that refs are unsupported, and documents `render()` plus `getRenderOutput()`. It omits class-instance access, unmount behavior, effect no-ops, skipped commit lifecycles, host-root rejection, React 19 incompatibility, module packaging, and the lack of queries or real event dispatch. The Enzyme recommendation also points readers toward an older testing model.
Maintenance1/5npm's latest release is 16.15.0, the React 18-era version, and GitHub shows the last repository push on 2023-03-04. The repository is open and the package is not marked deprecated, though the peer range has not moved beyond React 18 and GitHub reports 25 open issues and pull requests combined. A renderer tied to React internals needs prompt compatibility work; the current release history does not support expecting it.
Ecosystem2/5npm recorded 3,205,124 downloads last week, largely reflecting established React and testing dependency trees. The repository has 37 stars, the renderer stops at the React 18 peer range, and it exposes no query, adapter, or plugin layer of its own. Existing Jest and Enzyme suites can keep using its element output, while current React testing practice and integrations have moved toward Testing Library and full rendered behavior.

Use it if

  • A React 16 through 18 suite already asserts the exact one-level element structure returned by components
  • A pure component needs a fast DOM-free structural test and child execution would obscure the assertion
  • Legacy class tests require `getMountedInstance()` during a gradual move away from instance-level testing
  • A compatible React Native suite only inspects emitted child types and props, not native host behavior
Skip it if

Setup reality

We installed react-shallow-renderer 16.15.0 in our sandbox in 1.2 seconds. It left 6 packages and 1 MB on disk, and npm audit found 0 known vulnerabilities. The package is 156 KB unpacked, declares 2 direct dependencies and 1 peer dependency, and uses MIT. React itself must satisfy ^16.0.0 || ^17.0.0 || ^18.0.0; React 19 is outside the published contract.

The package entry is CommonJS and has no exports map. require() and ESM import worked under Node 22, but no TypeScript declarations were found. Our browser build measured 23.3 KB minified and 7.2 KB gzipped. The package supplies no runner, assertion library, JSX transform, or DOM. Keep it in devDependencies and let Jest, Vitest, Babel, or your existing test toolchain compile the component code.

Usage is synchronous: construct ShallowRenderer, render one custom component, then call getRenderOutput(). Passing a host element such as <div /> as the root is invalid. Child components remain unexecuted React elements. There are no semantic queries or event simulation helpers; calling an output prop invokes a function directly and does not reproduce browser propagation, default actions, focus changes, or accessibility behavior.

State hooks and class updates have partial models, while effect hooks are no-ops and refs are unsupported. componentWillUnmount can run for a class when unmount() is called, but mount and update commit lifecycles do not. The source depends on React's private internals and React 18-era element knowledge. Do not force the peer range beside React 19 merely because npm can be overridden.

Patterns

Inspect one function component render-component

import ShallowRenderer from 'react-shallow-renderer';

const renderer = new ShallowRenderer();
renderer.render(<Greeting name="Ada" />);
const output = renderer.getRenderOutput();
expect(output.type).toBe('h1');

The root must be a custom component. Passing a host element such as `<h1>` directly throws.

Check props on the returned host element assert-props

renderer.render(<Button disabled label="Save" />);
const output = renderer.getRenderOutput();
expect(output.type).toBe('button');
expect(output.props.disabled).toBe(true);

The output is a React element object; no button was created in a browser or native host tree.

Verify props passed to one child inspect-child

renderer.render(<Profile userId="u-42" />);
const child = renderer.getRenderOutput().props.children;
expect(child.type).toBe(Avatar);
expect(child.props.userId).toBe('u-42');

Avatar is not executed, so this assertion cannot detect a failure inside that child.

Normalize several returned children inspect-children

const children = React.Children.toArray(
  renderer.getRenderOutput().props.children
);
expect(children[0].type).toBe(SearchButton);

The renderer has no find or semantic query API. Walk the returned element shape or use Testing Library.

Update the same component with new props rerender-props

renderer.render(<Status online={false} />);
expect(renderer.getRenderOutput().props.children).toBe('Offline');
renderer.render(<Status online />);
expect(renderer.getRenderOutput().props.children).toBe('Online');

Reusing the same renderer and component type follows its update path; changing the root type resets state.

Call an emitted handler directly invoke-handler

const onSave = vi.fn();
renderer.render(<SaveButton onSave={onSave} />);
renderer.getRenderOutput().props.onClick();
expect(onSave).toHaveBeenCalledOnce();

This direct call skips event propagation, default browser behavior, focus management, and accessibility checks.

Observe a useState transition update-hook-state

renderer.render(<Counter />);
renderer.getRenderOutput().props.onClick();
expect(renderer.getRenderOutput().props.children).toBe(1);

State dispatch is modeled synchronously. `useEffect`, `useLayoutEffect`, and `useInsertionEffect` do not execute.

Call a method on a legacy class access-class-instance

renderer.render(<Counter />);
renderer.getMountedInstance().increment();
expect(renderer.getRenderOutput().props.children).toBe(1);

`getMountedInstance()` returns null for function components. Keep this pattern only while migrating class-focused tests.

Check a conditional empty render assert-null

renderer.render(<Notice visible={false} />);
expect(renderer.getRenderOutput()).toBeNull();

`getRenderOutput()` returns the component's value directly, including null, a string, or a React element.

Run class cleanup on unmount unmount-class

renderer.render(<Subscription id="news" />);
renderer.unmount();
expect(cleanup).toHaveBeenCalledOnce();

A class `componentWillUnmount` can run, while mount and update commit lifecycles are intentionally skipped.

Alternatives

PackageRegistryPick it when
@testing-library/reactnpmUse it for React web tests that query rendered DOM and exercise visible behavior.
react-test-renderernpmUse it only when a host-independent rendered tree is required and its React version is supported.
enzymenpmUse it only to maintain an existing Enzyme suite whose adapter and React version are already fixed.

More testing guides

pytest · chai · jsdom · vitest · 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.