vitest-react-profiler

December 17, 2025 ยท View on GitHub

npm version npm downloads CI

React React Testing Library Vitest

Enterprise Grade Testing Coverage Status Mutation testing badge Quality Gate Status Property-Based Testing

TypeScript Built with tsup ESLint Code Style: Prettier

License: MIT PRs Welcome Engineered with Claude Code

React component render tracking and performance testing utilities for Vitest

๐Ÿ“– Documentation โ€ข ๐Ÿš€ Quick Start โ€ข ๐Ÿ“š API Reference โ€ข ๐Ÿ’ฌ Discussions


Features

  • ๐Ÿ” Precise Render Tracking - Count exact number of renders with zero guesswork
  • โšก Performance Monitoring - Detect unnecessary re-renders and track component behavior
  • ๐ŸŽฏ Phase Detection - Distinguish between mount, update, and nested update phases
  • ๐Ÿ“ธ Snapshot API - Create render baselines with snapshot() and measure deltas with Extended Matchers
  • ๐Ÿช Hook Profiling - Profile custom hooks with full Context support via wrapper option
  • โฑ๏ธ Async Testing - Subscribe to renders with onRender() and wait with waitForNextRender()
  • ๐Ÿ”” Real-Time Notifications - React to renders immediately with event-based subscriptions
  • โš›๏ธ React 18+ Concurrent Ready - Full support for useTransition and useDeferredValue
  • ๐Ÿงน True Automatic Cleanup - Zero boilerplate! Components auto-clear between tests
  • ๐Ÿš€ Zero Config - Works out of the box with Vitest and React Testing Library
  • ๐Ÿ›ก๏ธ Built-in Safety Mechanisms - Automatic detection of infinite render loops and memory leaks
  • ๐Ÿ’ช Full TypeScript Support - Complete type safety with custom Vitest matchers
  • ๐Ÿงฌ Battle-Tested Quality - 100% mutation score, property-based testing, stress tests, SonarCloud verified.
  • ๐Ÿ”ฌ Mathematically Verified - 266 property tests with 140,000+ randomized scenarios per run
  • ๐Ÿ‹๏ธ Stress-Tested - 34 stress tests validate performance on 10,000-render histories
  • ๐Ÿ“Š Performance Baselines - 46 benchmarks establish regression detection metrics

๐Ÿ‘ฅ Who Is This For?

๐ŸŽจ UI-Kit and Design System Developers

Building a UI-kit for your project or company? You need to track, measure, and improve component performance. This tool helps you:

  • Catch unnecessary re-renders during development
  • Set performance budgets for components
  • Document performance characteristics in tests

๐Ÿ“ฆ Open Source React Library Maintainers

Publishing React components? It's critical to prove your solution is optimized and won't degrade performance in user projects. With this tool, you can:

  • Add performance tests to CI/CD pipelines
  • Showcase performance metrics in documentation
  • Track performance regressions between releases

๐Ÿ“Š Teams with Strict Performance SLAs

Have strict performance requirements (fintech, healthcare, real-time systems)? The tool allows you to:

  • Set thresholds for render counts
  • Automatically verify SLA compliance in tests
  • Track asynchronous state updates

Quick Start

Installation

npm install --save-dev vitest-react-profiler
# or
yarn add -D vitest-react-profiler
# or
pnpm add -D vitest-react-profiler

Setup

// vitest-setup.ts
import "vitest-react-profiler"; // Auto-registers afterEach cleanup

Configure Vitest:

// vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    environment: "jsdom",
    setupFiles: ["./vitest-setup.ts"],
  },
});

Your First Test

import { render } from '@testing-library/react';
import { withProfiler } from 'vitest-react-profiler';
import { MyComponent } from './MyComponent';

it('should render only once on mount', () => {
  const ProfiledComponent = withProfiler(MyComponent);
  render(<ProfiledComponent />);

  expect(ProfiledComponent).toHaveRenderedTimes(1);
  expect(ProfiledComponent).toHaveMountedOnce();
});

โฑ๏ธ Async Testing

Test components with asynchronous state updates using event-based utilities.

const AsyncComponent = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
    fetchData().then(setData);
  }, []);
  return <div>{data ?? "Loading..."}</div>;
};

it('should handle async updates', async () => {
  const Profiled = withProfiler(AsyncComponent);
  render(<Profiled />);

  // Wait for mount + async update
  await expect(Profiled).toEventuallyRenderTimes(2);
});

Key Matchers

  • toEventuallyRenderTimes(n) - Wait for exact render count
  • toEventuallyRenderAtLeast(n) - Wait for minimum renders
  • toEventuallyReachPhase(phase) - Wait for specific phase

๐Ÿ“š Read the complete guide โ†’


๐ŸŽฏ Stabilization API (v1.12.0)

Wait for components to "stabilize" - useful for virtualized lists, debounced search, and animations.

Key Methods

  • waitForStabilization(options) - Wait for renders to stop (debounce pattern)
  • toEventuallyStabilize(options) - Matcher version for cleaner assertions

๐Ÿ“š Read the complete guide โ†’


๐Ÿช Hook Profiling

Profile custom hooks with full Context support.

import { profileHook } from 'vitest-react-profiler';

const useCounter = (initial: number) => {
  const [count, setCount] = useState(initial);
  return { count, increment: () => setCount(c => c + 1) };
};

it('should track hook renders', () => {
  const { result, profiler } = profileHook(() => useCounter(0));

  expect(profiler).toHaveRenderedTimes(1);

  act(() => result.current.increment());

  expect(profiler).toHaveRenderedTimes(2);
  expect(result.current.count).toBe(1);
});

With Context Support

const { result, profiler } = profileHook(() => useTheme(), {
  wrapper: ({ children }) => (
    <ThemeProvider theme="dark">{children}</ThemeProvider>
  ),
});

๐Ÿ“š Read the complete guide โ†’


โš›๏ธ React 18+ Concurrent Features

Full support for React 18+ Concurrent rendering features - no special configuration needed!

The library automatically tracks renders from:

useTransition / startTransition

Test components using transitions for non-urgent updates

useDeferredValue

Test components using deferred values for performance optimization

How It Works

The library uses React's built-in <Profiler> API, which automatically handles Concurrent mode:

  • โœ… Transitions are tracked as regular renders
  • โœ… Deferred values trigger additional renders (as expected)
  • โœ… Interrupted renders are handled correctly by React
  • โœ… No special configuration or setup required

Note: The library tracks renders, not React's internal scheduling. Concurrent Features work transparently - your tests verify component behavior, not React internals.

๐Ÿ“š Read the complete guide โ†’


๐Ÿ“ธ Snapshot API

Create render baselines and measure deltas for optimization testing.

Testing Single Render Per Action

const ProfiledCounter = withProfiler(Counter);
render(<ProfiledCounter />);

ProfiledCounter.snapshot();                    // Create baseline
fireEvent.click(screen.getByText('Increment'));
expect(ProfiledCounter).toHaveRerenderedOnce(); // Verify single rerender

Testing React.memo Effectiveness

const ProfiledList = withProfiler(MemoizedList);
const { rerender } = render(<ProfiledList items={items} theme="light" />);

ProfiledList.snapshot();
rerender(<ProfiledList items={items} theme="dark" />);
expect(ProfiledList).toNotHaveRerendered();    // Memo prevented rerender

Extended Matchers

// Sync matchers
expect(ProfiledComponent).toHaveRerendered();     // At least one rerender
expect(ProfiledComponent).toHaveRerendered(3);    // Exactly 3 rerenders

// Async matchers - wait for rerenders
await expect(ProfiledComponent).toEventuallyRerender();
await expect(ProfiledComponent).toEventuallyRerenderTimes(2, { timeout: 2000 });

Key Methods & Matchers

Method/MatcherDescription
snapshot()Mark baseline for render counting
getRendersSinceSnapshot()Get number of renders since baseline
toHaveRerenderedOnce()Assert exactly one rerender
toNotHaveRerendered()Assert no rerenders
toHaveRerendered()Assert at least one rerender
toHaveRerendered(n)Assert exactly n rerenders
toEventuallyRerender()Wait for rerender
toEventuallyRerenderTimes(n)Wait for exact count

๐Ÿ“š Read the complete guide โ†’


Documentation

๐Ÿ“– Full documentation is available in the Wiki


Contributing

We welcome contributions! Please read our Contributing Guide and Code of Conduct.

# Run tests
npm test                    # Unit/integration tests (811 tests)
npm run test:properties     # Property-based tests (266 tests, 140k+ checks)
npm run test:stress         # Stress tests (34 tests, large histories)
npm run test:bench          # Performance benchmarks (46 benchmarks)
npm run test:mutation       # Mutation testing (100% score)

# Build
npm run build

License

MIT ยฉ Oleg Ivanov


Made with โค๏ธ by the community

Report Bug โ€ข Request Feature โ€ข Discussions