### Install and Run Examples
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/snapshot/README.md
Instructions for setting up and running the snapshot API examples. This involves navigating to the example directory, installing dependencies, and executing the tests.
```bash
cd examples/snapshot
npm install
npm test
```
--------------------------------
### Install and Run Concurrent Examples
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/concurrent/README.md
Commands to install dependencies and run tests for the concurrent examples directory. Includes options for watch mode and UI testing.
```bash
cd examples/concurrent
# Install dependencies (from workspace root)
npm install
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with UI
npm run test:ui
```
--------------------------------
### Install Project Dependencies
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/memoization/README.md
Install npm packages for the memoization example directory or the entire project.
```bash
# From this directory
npm install
# Or from the root of the project
npm install --workspace=examples/memoization
```
--------------------------------
### Install vitest-react-profiler
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/basic/README.md
Install the necessary packages for vitest-react-profiler. This can be done from the example directory or the project root.
```bash
# From this directory
npm install
# Or from the root of the project
npm install --workspace=examples/basic
```
--------------------------------
### Create Vitest Setup File
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Getting-Started
Create a setup file for Vitest to import the profiler.
```typescript
// vitest-setup.ts
import "vitest-react-profiler";
```
--------------------------------
### Run All Examples
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/async/README.md
Execute all tests in the project.
```bash
npm test
```
--------------------------------
### Install vitest-react-profiler
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Getting-Started
Install the package using npm, yarn, or pnpm.
```bash
# npm
npm install --save-dev vitest-react-profiler
# yarn
yarn add -D vitest-react-profiler
# pnpm
pnpm add -D vitest-react-profiler
```
--------------------------------
### Run Examples with UI
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/async/README.md
Execute all tests with the Vitest UI enabled.
```bash
npm run test:ui
```
--------------------------------
### Install Dependencies
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CONTRIBUTING.md
Install project dependencies using pnpm.
```bash
pnpm install
```
--------------------------------
### Install Dependencies
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/performance/README.md
Installs the necessary project dependencies using npm.
```bash
# Install dependencies
npm install
```
--------------------------------
### GitHub Actions Workflow for Performance Tests
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/basic/README.md
An example GitHub Actions workflow that checks out code, sets up Node.js, installs dependencies, runs tests, and uploads performance results. Integrate this into your CI/CD pipeline.
```yaml
# Example GitHub Actions workflow
name: Performance Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm test
- name: Upload results
if: always()
uses: actions/upload-artifact@v3
with:
name: performance-results
path: coverage/
```
--------------------------------
### Run Examples in Watch Mode
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/async/README.md
Execute tests and automatically re-run them when files change.
```bash
npm run test:watch
```
--------------------------------
### Verify Installation with a Simple Test
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Getting-Started
Run a basic test to ensure the profiler is working correctly.
```typescript
import { render } from '@testing-library/react';
import { withProfiler } from 'vitest-react-profiler';
const TestComponent = () =>
Hello
;
it('should work', () => {
const Profiled = withProfiler(TestComponent);
render();
expect(Profiled).toHaveRenderedTimes(1);
});
```
--------------------------------
### Import Setup File in Vitest Config
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Troubleshooting
Ensure your vitest setup file is imported in `vitest.config.ts` to register custom matchers.
```typescript
export default defineConfig({
test: {
setupFiles: ["./vitest-setup.ts"], // ✅ Must include this
},
});
```
--------------------------------
### Import Vitest React Profiler in Setup File
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Troubleshooting
Import the library in your `vitest-setup.ts` file to make its matchers available.
```typescript
import "vitest-react-profiler"; // ✅ Registers matchers
```
--------------------------------
### Configure Vitest Config
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Getting-Started
Configure Vitest to use the setup file by adding it to `setupFiles`.
```typescript
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "jsdom",
setupFiles: ["./vitest-setup.ts"],
},
});
```
--------------------------------
### Troubleshooting: Matchers Not Found
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Getting-Started
Ensure the setup file is imported in `vitest.config.ts` if matchers are not found.
```typescript
setupFiles: ["./vitest-setup.ts"]
```
--------------------------------
### Basic Snapshot API Example
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Use this snippet to create a render baseline, trigger an action, and assert that the component rerendered exactly once.
```typescript
const ProfiledComponent = withProfiler(Counter);
render();
ProfiledComponent.snapshot();
fireEvent.click(screen.getByText('Increment'));
expect(ProfiledComponent).toHaveRerenderedOnce();
```
--------------------------------
### Troubleshooting: Install React Peer Dependency
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Getting-Started
Install React and React DOM as peer dependencies if you encounter 'Cannot find module "react"' errors.
```bash
npm install react react-dom
```
--------------------------------
### Conventional Commit Example
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CLAUDE.md
Example of a commit message following the Conventional Commits format for a performance improvement.
```bash
perf(ProfilerData): O(1) addRender complexity
```
--------------------------------
### Project Structure
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CLAUDE.md
Illustrates the directory layout for the vitest-react-profiler project, including core profiler implementation, matchers, utilities, types, tests, and examples.
```tree
vitest-react-profiler/
├── src/
│ ├── profiler/ # Core profiler implementation
│ │ ├── api/ # Public API methods
│ │ ├── components/ # React components (withProfiler, etc.)
│ │ └── core/ # Core data structures (ProfilerData, Cache)
│ ├── matchers/ # Vitest custom matchers
│ │ ├── async.ts # Async matchers (toEventuallyRender, etc.)
│ │ ├── sync.ts # Sync matchers (toHaveRendered, etc.)
│ │ └── index.ts # ⚠️ NOT a barrel export! Registers matchers
│ ├── utils/ # Utility functions
│ └── types.ts # All type definitions
├── tests/
│ ├── unit/ # Unit tests (*.test.ts)
│ ├── integration/ # Integration tests (*.test.tsx)
│ ├── property/ # Property-based tests (*.properties.tsx)
│ └── benchmarks/ # Performance benchmarks (*.bench.tsx)
└── examples/ # Usage examples (npm workspace)
```
--------------------------------
### Basic useDeferredValue Example with Profiler
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/React-18-Concurrent-Features
Demonstrates how `useDeferredValue` defers updates to an expensive component, allowing the UI to remain responsive. This example uses `vitest-react-profiler` to track renders.
```typescript
import { useState, useDeferredValue, memo } from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import { withProfiler } from 'vitest-react-profiler';
// Expensive component that renders large list
const ExpensiveList = memo(({ query }: { query: string }) => {
const items = generateItems(query, 1000);
return (
);
}
it('should track deferred value updates', async () => {
const Profiled = withProfiler(DeferredFilterComponent);
const { getByPlaceholderText, getByTestId } = render();
// Initial mount
expect(Profiled).toHaveMountedOnce();
// Type in filter
const input = getByPlaceholderText('Filter items...');
fireEvent.change(input, { target: { value: 'test' } });
// Immediate value updates instantly
expect(getByTestId('immediate')).toHaveTextContent('test');
// Wait for deferred value to catch up
await waitFor(() => {
expect(getByTestId('deferred')).toHaveTextContent('test');
});
// Profiler tracked: mount + input update + deferred update
expect(Profiled.getRenderCount()).toBeGreaterThanOrEqual(2);
});
```
--------------------------------
### Conventional Commits Examples
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CONTRIBUTING.md
Examples of commit messages following the Conventional Commits specification for different types of changes.
```git
feat: add toHaveRenderedBetween matcher
fix: handle undefined render history in getLastRender
docs: update API reference for new matchers
```
--------------------------------
### Real-Time Render Monitoring with Subscriptions
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Advanced-Usage
Monitor component renders in real-time by subscribing to render events. This example demonstrates how to subscribe to render notifications, log detailed render information, and unsubscribe.
```typescript
it('should monitor renders in real-time', () => {
const Profiled = withProfiler(MyComponent);
// Subscribe to all renders
const unsubscribe = Profiled.onRender((info) => {
console.log(`
Render #${info.count}
Phase: ${info.phase}
History: [${info.history.join(', ')}]
`);
});
render();
// Trigger actions...
unsubscribe();
});
```
--------------------------------
### Run Specific Test File
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/performance/README.md
Executes a specific test file, for example, 'PerformanceTest.test.tsx', using npm test.
```bash
# Run specific test file
npm test PerformanceTest.test.tsx
```
--------------------------------
### useTransition Example
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/concurrent/README.md
Demonstrates marking state updates as non-urgent with useTransition for UI elements like search or filtering. Use when responsiveness is more critical than immediate completeness.
```typescript
const [isPending, startTransition] = useTransition();
const handleSearch = (value: string) => {
setInput(value); // Urgent: immediate UI feedback
startTransition(() => {
setResults(mockSearch(value)); // Non-urgent: can be interrupted
});
};
```
--------------------------------
### Test useTransition with vitest-react-profiler
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/React-18-Concurrent-Features
This example demonstrates how to test a component using `useTransition` for non-urgent updates. It verifies that `vitest-react-profiler` tracks renders during the transition.
```typescript
import { useState, useTransition } from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import { withProfiler } from 'vitest-react-profiler';
function SearchComponent() {
const [isPending, startTransition] = useTransition();
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const handleSearch = (value: string) => {
// Urgent: Update input immediately (responsive UI)
setQuery(value);
// Non-urgent: Update results (can be interrupted)
startTransition(() => {
const filtered = performExpensiveSearch(value);
setResults(filtered);
});
};
return (
);
}
it('should handle rapid typing with transitions', async () => {
const Profiled = withProfiler(SearchComponent);
const { getByPlaceholderText } = render();
const input = getByPlaceholderText('Search...');
// Type rapidly
fireEvent.change(input, { target: { value: 'a' } });
fireEvent.change(input, { target: { value: 'ab' } });
fireEvent.change(input, { target: { value: 'abc' } });
// Wait for final transition
await waitFor(() => {
expect(screen.getByTestId('status')).toHaveTextContent('Ready');
});
// React may batch some updates
// Use toBeGreaterThanOrEqual instead of exact count
expect(Profiled.getRenderCount()).toBeGreaterThan(1);
});
```
--------------------------------
### Basic Component Render Test
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Home
This snippet demonstrates how to use `withProfiler` to track component renders and assert that a component renders exactly once. Ensure `@testing-library/react` and `vitest-react-profiler` are installed.
```typescript
import { render } from '@testing-library/react';
import { withProfiler } from 'vitest-react-profiler';
it('should render only once', () => {
const ProfiledComponent = withProfiler(MyComponent);
render();
expect(ProfiledComponent).toHaveRenderedTimes(1);
});
```
--------------------------------
### ProfileHookOptions Example
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Configure hook profiling with `ProfileHookOptions`, particularly for providing custom `renderOptions` like context providers via React Testing Library.
```typescript
const options: ProfileHookOptions = {
renderOptions: {
wrapper: ({ children }) => {children}
}
};
const { result } = profileHook(() => useMyHook(), options);
```
--------------------------------
### Assert Component Mounted Once
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Use `toHaveMountedOnce()` to assert that a component has mounted exactly one time. This is useful for verifying initial setup.
```typescript
expect(ProfiledComponent).toHaveMountedOnce();
```
--------------------------------
### Generate Performance Reports in CI
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Best-Practices
A setup script for CI/CD that collects render counts for all profiled components after each test and logs them as JSON. This data can be used for performance analysis.
```typescript
// vitest.setup.ts
afterEach(() => {
const results = getAllProfiledComponents().map(c => ({
name: c.displayName,
renders: c.getRenderCount(),
}));
// Log for CI analysis
console.log(JSON.stringify(results, null, 2));
});
```
--------------------------------
### Performance Benchmarking Between Implementations
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Advanced-Usage
Compare the performance of different component implementations using vitest-react-profiler and Node.js's `perf_hooks`. This example benchmarks two implementations against defined duration budgets.
```typescript
import { performance } from 'perf_hooks';
describe('Performance comparison', () => {
it('implementation A', () => {
const Profiled = withProfiler(ImplementationA);
const start = performance.now();
render();
const duration = performance.now() - start;
expect(Profiled).toHaveRenderedTimes(1);
expect(duration).toBeLessThan(100); // 100ms budget
});
it('implementation B', () => {
const Profiled = withProfiler(ImplementationB);
const start = performance.now();
render();
const duration = performance.now() - start;
expect(Profiled).toHaveRenderedTimes(1);
expect(duration).toBeLessThan(50); // B should be 2x faster
});
});
```
--------------------------------
### GitHub Actions Workflow for Performance Tests
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/performance/README.md
This YAML snippet shows an example GitHub Actions workflow for running performance tests and uploading the results as an artifact. It includes steps to run tests and upload artifacts regardless of test success or failure.
```yaml
# Example GitHub Actions workflow
- name: Run Performance Tests
run: npm test
- name: Upload Performance Results
if: always()
uses: actions/upload-artifact@v3
with:
name: performance-results
path: coverage/
```
--------------------------------
### Performance Measurements and Budgets
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/basic/README.md
Measure component render duration and enforce performance budgets. This example logs the render duration and asserts that it falls within an acceptable time limit.
```tsx
const ProfiledComponent = withProfiler(TodoList, "TodoList");
render();
// Get render metrics
const lastRender = ProfiledComponent.getLastRender();
console.log(`Render duration: ${lastRender?.actualDuration}ms`);
// Validate performance
expect(ProfiledComponent).toHaveRenderedWithin(50); // 50ms budget
```
--------------------------------
### Testing Component Performance Budgets with vitest-react-profiler
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/memoization/README.md
Example of defining performance budgets for different components and using the `toHaveRenderedWithin` matcher from vitest-react-profiler to test if components render within their allocated time.
```tsx
const performanceBudgets = {
MemoizedList: 50, // Max 50ms
MemoizedForm: 75, // Max 75ms
MemoizedDataGrid: 100, // Max 100ms
};
// Test each component against budget
expect(ProfiledList).toHaveRenderedWithin(performanceBudgets.MemoizedList);
expect(ProfiledForm).toHaveRenderedWithin(performanceBudgets.MemoizedForm);
expect(ProfiledGrid).toHaveRenderedWithin(performanceBudgets.MemoizedDataGrid);
```
--------------------------------
### Test useMemo for Memoization
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Examples
Verifies that `useMemo` prevents expensive calculations when dependencies have not changed. The example shows rerendering with the same and different references for the `items` prop.
```typescript
const ExpensiveCalc = ({ items }: { items: number[] }) => {
const sum = useMemo(() => {
return items.reduce((a, b) => a + b, 0);
}, [items]);
return
{sum}
;
};
it('should not re-render with same items reference', () => {
const ProfiledComponent = withProfiler(ExpensiveCalc);
const items = [1, 2, 3];
const { rerender } = render();
// Same reference - should not recalculate
rerender();
expect(ProfiledComponent).toHaveRenderedTimes(2);
// New reference - should recalculate
rerender();
expect(ProfiledComponent).toHaveRenderedTimes(3);
});
```
--------------------------------
### Fail on Performance Regression in CI
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Best-Practices
Example of setting up a test in CI/CD to fail if a component's render count exceeds a baseline. This helps catch performance regressions early.
```typescript
describe('Performance regression tests', () => {
it('should not regress on render count', () => {
const Profiled = withProfiler(CriticalComponent);
render();
// Hard limit based on baseline
expect(Profiled.getRenderCount()).toBeLessThanOrEqual(3);
});
});
```
--------------------------------
### Clone Repository and Navigate
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CONTRIBUTING.md
Clone the repository and navigate into the project directory to begin development.
```bash
git clone https://github.com/your-username/vitest-react-profiler.git
cd vitest-react-profiler
```
--------------------------------
### Use notToHaveRenderLoops to ignore initial updates
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
When a component has an expected initialization sequence, you can use `ignoreInitialUpdates` to skip a specified number of initial updates before starting loop detection. This example ignores the first 2 updates and sets a stricter consecutive update threshold.
```typescript
expect(ProfiledComponent).notToHaveRenderLoops({
ignoreInitialUpdates: 2, // Skip first 2 updates
maxConsecutiveUpdates: 5
});
```
--------------------------------
### Build Project
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CLAUDE.md
Builds the project for production.
```bash
npm run build
```
--------------------------------
### Get Last Render Phase
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Use getLastRender to get the phase of the most recent render.
```typescript
const lastPhase = ProfiledComponent.getLastRender();
// "update"
```
--------------------------------
### Build the Package
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CONTRIBUTING.md
Build the project package using pnpm.
```bash
pnpm build
```
--------------------------------
### Build Project
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/README.md
Compile and bundle the project for deployment or distribution. This command generates the production-ready build artifacts.
```bash
# Build
npm run build
```
--------------------------------
### Local Testing with Linking
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CONTRIBUTING.md
Link the project locally for testing in another project. First, link the project itself, then link it into your test project.
```bash
pnpm link
# In your test project
pnpm link vitest-react-profiler
```
--------------------------------
### Get Full Render History
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Use getRenderHistory to obtain an array of all render phases the component has gone through.
```typescript
const history = ProfiledComponent.getRenderHistory();
// ["mount", "update", "update"]
```
--------------------------------
### Basic Performance Measurement with Profiler
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/performance/README.md
Demonstrates how to use the `withProfiler` HOC to measure component render times and check if a render occurred within a specified duration.
```tsx
const ProfiledComponent = withProfiler(MyComponent, "MyComponent");
render();
// Check render occurred
expect(ProfiledComponent).toHaveRendered();
// Check render time
expect(ProfiledComponent).toHaveRenderedWithin(100); // ms
// Get specific metrics
const lastRender = ProfiledComponent.getLastRender();
console.log(`Render took ${lastRender?.actualDuration}ms`);
```
--------------------------------
### Get Total Render Count
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Use getRenderCount to retrieve the total number of times a component has rendered.
```typescript
const count = ProfiledComponent.getRenderCount();
```
--------------------------------
### Create Snapshot and Verify Delta
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Snapshot-API
Demonstrates creating a render baseline with `snapshot()` and verifying the render delta using `getRendersSinceSnapshot()`. The initial render is counted before the snapshot, and subsequent renders are measured against this baseline.
```typescript
const ProfiledComponent = withProfiler(MyComponent);
render();
// Before snapshot: includes initial mount
expect(ProfiledComponent.getRendersSinceSnapshot()).toBe(1);
ProfiledComponent.snapshot(); // Create baseline
// Immediately after snapshot: delta is 0
expect(ProfiledComponent.getRendersSinceSnapshot()).toBe(0);
```
--------------------------------
### Run Benchmarks
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CLAUDE.md
Executes performance benchmarks for the project.
```bash
npm run test:bench
```
--------------------------------
### Run Unit/Integration Tests
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/README.md
Execute the project's unit and integration tests using npm. This command runs a comprehensive suite of tests to ensure core functionality.
```bash
# Run tests
npm test # Unit/integration tests (811 tests)
```
--------------------------------
### Get Renders by Specific Phase
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Use getRendersByPhase to filter and retrieve all render phases that match a specified phase.
```typescript
const updates = ProfiledComponent.getRendersByPhase("update");
// ["update", "update", "update"]
```
--------------------------------
### Configuration Files Reference
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CLAUDE.md
Provides a reference for configuration files used in the project, detailing their purpose and key notes.
```markdown table
| File | Purpose | Notes |
| ------------------------------ | ---------------------- | ------------------------------------------------------------------- |
| `vitest.config.common.mts` | **Base config** | Shared settings for all test configs (resolve, define, environment) |
| `vitest.config.unit.mts` | Unit/Integration tests | Coverage enabled (100%), 10s timeout, 4 workers |
| `vitest.config.properties.mts` | Property tests | Extends common, coverage disabled, 30s timeout |
| `vitest.config.bench.mts` | Benchmarks | Extends common, forks pool, 600s timeout |
| `vitest.stryker.config.mts` | Mutation testing | Extends common, forks pool, 5s timeout |
| `vitest.stress.config.mts` | Stress tests | Extends common, memory/load testing |
| `eslint.config.mjs` | ESLint rules | Flat config format |
| `tsconfig.json` | TypeScript | Path aliases (`@/` → `src/`) |
| `tsup.config.ts` | Build config | ESM + CJS bundles |
| `codecov.yml` | Codecov config | 100% target, bundle analysis |
| `sonar-project.properties` | SonarCloud | Quality gates, version must match `package.json` |
```
--------------------------------
### Listener Cleanup Example
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/async/README.md
Demonstrates the importance of manually unsubscribing from event listeners when they are no longer needed to prevent memory leaks.
```typescript
const unsubscribe = ProfiledComponent.onRender(() => {
// handle event
});
// ✅ Clean up when done
unsubscribe();
```
--------------------------------
### Tracking Render Phases with Profiler
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/performance/README.md
Demonstrates how to track and verify different render phases (mount and update) for a component using the `withProfiler` HOC and its history methods.
```tsx
const ProfiledComponent = withProfiler(Component, "Component");
render();
// Check mount phase
const renders = ProfiledComponent.getRenderHistory();
expect(renders[0]?.phase).toBe("mount");
// Check for updates
const updates = ProfiledComponent.getRendersByPhase("update");
expect(updates).toHaveLength(expectedUpdateCount);
```
--------------------------------
### Correct Usage of waitForStabilization
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Illustrates the correct pattern for using `waitForStabilization` by initiating the wait *before* triggering renders to ensure all renders are captured.
```typescript
// ✅ Correct: Start waiting first
const promise = ProfiledComponent.waitForStabilization();
triggerManyRenders();
await promise;
// ❌ Wrong: Waiting after renders - may resolve immediately
triggerManyRenders();
await ProfiledComponent.waitForStabilization(); // May miss renders!
```
--------------------------------
### Get Renders Since Last Snapshot
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Use getRendersSinceSnapshot to retrieve the number of renders that have occurred since the last snapshot() call.
```typescript
const delta = ProfiledComponent.getRendersSinceSnapshot();
```
--------------------------------
### Snapshot API Quick Reference
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
A quick reference table for the Snapshot API methods used for creating render baselines and measuring render deltas.
```APIDOC
## Snapshot API
### Description
Provides methods for creating render baselines and measuring render deltas. This is the primary tool for testing React optimizations like `React.memo`, `useCallback`, and ensuring single renders per user action.
### Methods
- `snapshot()`: Create baseline for render counting.
- `getRendersSinceSnapshot()`: Get renders since baseline.
- `toHaveRerenderedOnce()`: Assert exactly 1 rerender.
- `toNotHaveRerendered()`: Assert no rerenders.
- `toHaveRerendered()`: Assert at least 1 rerender (v1.11.0).
- `toHaveRerendered(n)`: Assert exact N rerenders (v1.11.0).
- `toEventuallyRerender()`: Wait for async rerender (v1.11.0).
- `toEventuallyRerenderTimes(n)`: Wait for exact N async rerenders (v1.11.0).
### Basic Example
```typescript
const ProfiledComponent = withProfiler(Counter);
render();
ProfiledComponent.snapshot();
fireEvent.click(screen.getByText('Increment'));
expect(ProfiledComponent).toHaveRerenderedOnce();
```
```
--------------------------------
### snapshot()
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Snapshot-API
Creates a baseline for render counting. All subsequent `getRendersSinceSnapshot()` calls return the number of renders since this baseline.
```APIDOC
## snapshot()
### Description
Creates a baseline for render counting. All subsequent `getRendersSinceSnapshot()` calls return the number of renders since this baseline.
### Signature
```typescript
function snapshot(): void
```
### Example
```typescript
const ProfiledComponent = withProfiler(MyComponent);
render();
// Before snapshot: includes initial mount
expect(ProfiledComponent.getRendersSinceSnapshot()).toBe(1);
ProfiledComponent.snapshot(); // Create baseline
// Immediately after snapshot: delta is 0
expect(ProfiledComponent.getRendersSinceSnapshot()).toBe(0);
```
```
--------------------------------
### Count Hook Renders on Mount
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Hook-Profiling
Test a custom hook to ensure it renders exactly once when initially mounted. This example uses a `useCounter` hook.
```typescript
function useCounter(initialValue: number) {
const [count, setCount] = useState(initialValue);
return { count, increment: () => setCount(c => c + 1) };
}
it('should render once on mount', () => {
const { ProfiledHook } = profileHook(
({ initial }) => useCounter(initial),
{ initial: 0 }
);
expect(ProfiledHook).toHaveRenderedTimes(1);
});
```
--------------------------------
### Polling-Based API Example (Deprecated)
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/async/README.md
Illustrates the older, less efficient polling-based approach for checking render counts, which is now superseded by the event-based API.
```typescript
// ❌ Inefficient polling
await waitFor(() => {
expect(component.getRenderCount()).toBe(2);
});
```
--------------------------------
### Get Render Phase by Index
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Use getRenderAt with a 0-based index to retrieve the render phase at a specific point in the component's history.
```typescript
const firstRender = ProfiledComponent.getRenderAt(0);
// "mount"
```
--------------------------------
### Handle Search Updates with startTransition
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/React-18-Concurrent-Features
Use `startTransition` to defer non-urgent state updates like search results, ensuring the UI remains responsive to urgent updates like input changes.
```typescript
const handleSearch = (value: string) => {
setInput(value); // Urgent: show in input immediately
startTransition(() => {
setResults(searchData(value)); // Non-urgent: can wait
});
};
```
--------------------------------
### Correct Memo Wrapper for Profiled Component
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Best-Practices
Demonstrates the correct way to wrap a component with `memo` and `withProfiler` to ensure `memo` is not bypassed. The incorrect approach is shown for contrast.
```typescript
// ❌ Wrong - Profiler bypasses memo
const Profiled = withProfiler(memo(Component));
const { rerender } = render();
rerender();
expect(Profiled).toHaveRenderedTimes(1); // ❌ Fails!
// ✅ Correct - Additional memo wrapper
const Profiled = withProfiler(memo(Component));
const MemoProfiled = memo(Profiled);
const { rerender } = render();
rerender();
expect(Profiled).toHaveRenderedTimes(1); // ✅ Passes!
```
--------------------------------
### Profile a Hook (Basic Usage)
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Use `profileHook` to detect extra renders in a React hook. This basic example profiles a hook without parameters.
```typescript
// Basic usage
const { result, ProfiledHook } = profileHook(() => useMyHook());
expect(ProfiledHook).toHaveRenderedTimes(1);
```
--------------------------------
### Run ESLint
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CLAUDE.md
Lints the project code using ESLint to enforce code style and quality.
```bash
npm run lint
```
--------------------------------
### Async Operation Performance Tracking
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/basic/README.md
Track performance during asynchronous operations, such as data fetching. This example waits for data to load and checks the render phases.
```tsx
const ProfiledProfile = withProfiler(UserProfile, "UserProfile");
render();
// Wait for async data
await waitFor(() => {
expect(screen.queryByText("Loading...")).not.toBeInTheDocument();
});
// Check render phases
const renders = ProfiledProfile.getRenderHistory();
expect(renders[0]?.phase).toBe("mount"); // Initial mount
expect(renders[1]?.phase).toBe("update"); // After data loaded
```
--------------------------------
### Run Tests
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CONTRIBUTING.md
Execute tests using pnpm. Use 'pnpm test' for a single run or 'pnpm dev' for watch mode. 'pnpm test:ui' opens the Vitest UI.
```bash
pnpm test # Run tests once
pnpm dev # Run tests in watch mode
pnpm test:ui # Open Vitest UI
```
--------------------------------
### Add vitest-react-profiler to devDependencies
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/SECURITY.md
Ensure vitest-react-profiler is listed in your project's devDependencies to manage it as a development tool. This example shows how to add it using npm.
```json
{
"devDependencies": {
"vitest-react-profiler": "^1.7.0"
}
}
```
--------------------------------
### Testing useTransition
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/concurrent/README.md
Example of testing a component using useTransition with vitest-react-profiler. It involves simulating user input and waiting for the transition to complete before asserting on render counts.
```typescript
const ProfiledComponent = withProfiler(TransitionExample);
render();
fireEvent.change(input, { target: { value: 'test' } });
// Wait for transition to settle
await waitFor(() => {
expect(screen.getByTestId('status')).toHaveTextContent('Ready');
});
// Profiler tracked all renders automatically
expect(ProfiledComponent.getRenderCount()).toBeGreaterThanOrEqual(2);
```
--------------------------------
### Run Tests with UI for Visual Debugging
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/performance/README.md
Launches the test runner with a user interface for visual debugging, using npm run test:ui.
```bash
# Run with UI for visual debugging
npm run test:ui
```
--------------------------------
### Testing useDeferredValue
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/concurrent/README.md
Example of testing a component using useDeferredValue. It simulates input changes and asserts that the deferred value eventually updates, while checking the total render count.
```typescript
const ProfiledComponent = withProfiler(DeferredExample);
render();
fireEvent.change(input, { target: { value: 'test' } });
// Deferred value updates later
await waitFor(() => {
expect(screen.getByTestId('deferred-value')).toHaveTextContent('test');
});
// Profiler tracked: mount + input + deferred update
expect(ProfiledComponent.getRenderCount()).toBeGreaterThanOrEqual(2);
```
--------------------------------
### Handle Tab Switching with startTransition
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/React-18-Concurrent-Features
Defer loading tab content using `startTransition` to keep the tab switching interaction smooth, while immediately updating the active tab.
```typescript
const handleTabChange = (tabId: string) => {
setActiveTab(tabId); // Urgent: highlight tab
startTransition(() => {
setTabContent(loadTabContent(tabId)); // Non-urgent: load content
});
};
```
--------------------------------
### Create Hook Profiler with Context Provider
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Profile hooks that require context providers by passing them in the `renderOptions`. This allows testing hooks within specific environmental setups.
```typescript
const profiler = createHookProfiler(
() => useTheme(),
{ renderOptions: { wrapper: ThemeProvider } }
);
profiler.expectRenderCount(1);
expect(profiler.result.current.theme).toBe('light');
```
--------------------------------
### Profile Router Hook with Mock Provider
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Hook-Profiling
Demonstrates profiling a router hook by providing a mock router context using the `wrapper` option.
```typescript
// Mock router provider for tests
const MockRouterProvider = ({ children }: { children: React.ReactNode }) => (
{}
}}>
{children}
);
// Profile the router hook
const { result, ProfiledHook } = profileHook(
() => useRouter(),
{ renderOptions: { wrapper: MockRouterProvider } }
);
expect(ProfiledHook).toHaveRenderedTimes(1);
expect(result.current.params.userId).toBe('123');
```
--------------------------------
### Code Formatting and Linting
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CONTRIBUTING.md
Ensure code quality by running formatting and linting commands. Run 'pnpm format' before committing and 'pnpm lint' to check for issues.
```bash
pnpm format
pnpm lint
```
--------------------------------
### Get Renders Since Snapshot
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/snapshot/README.md
Returns the number of renders that have occurred since the last `snapshot()` call. This is useful for verifying that specific actions trigger a predictable number of rerenders.
```tsx
import { withProfiler } from 'vitest-react-profiler';
import { render, rerender } from '@testing-library/react';
const MyComponent = ({ value }) =>
{value}
;
const ProfiledComponent = withProfiler(MyComponent);
render();
ProfiledComponent.snapshot();
rerender();
rerender();
expect(ProfiledComponent.getRendersSinceSnapshot()).toBe(2);
```
--------------------------------
### Run Coverage Report
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CLAUDE.md
Generates a code coverage report for the project.
```bash
npm run test:coverage
```
--------------------------------
### toHaveMountedOnce()
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Asserts that a component has been mounted exactly one time. This is crucial for verifying correct initialization and preventing unintended remounts.
```APIDOC
## `toHaveMountedOnce()`
### Description
Asserts that component mounted exactly once.
### Method
`expect(ProfiledComponent).toHaveMountedOnce()`
### Example
```typescript
expect(ProfiledComponent).toHaveMountedOnce();
```
```
--------------------------------
### React Batches Updates Example
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/concurrent/README.md
Illustrates how React may batch multiple state updates into fewer renders, especially in concurrent mode. Use `toBeGreaterThanOrEqual` for assertions on render counts.
```typescript
// 3 rapid updates...
fireEvent.change(input, { target: { value: "a" } });
fireEvent.change(input, { target: { value: "ab" } });
fireEvent.change(input, { target: { value: "abc" } });
// ...may produce 2-3 renders (React optimizes)
expect(component.getRenderCount()).toBeGreaterThanOrEqual(2);
```
--------------------------------
### Track Renders with Subscription
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Examples
Demonstrates how to subscribe to render events using `onRender` to track component renders in real-time. The callback receives render information, and `unsubscribe` should be called to clean up the listener.
```typescript
it('should track renders with subscription', () => {
const ProfiledCounter = withProfiler(Counter);
const { getByText } = render();
const renders: RenderEventInfo[] = [];
const unsubscribe = ProfiledCounter.onRender((info) => {
renders.push(info);
console.log(`Render #${info.count}: ${info.phase}`);
});
fireEvent.click(getByText("Increment"));
fireEvent.click(getByText("Increment"));
expect(renders).toHaveLength(2);
expect(renders[0]!.phase).toBe("update");
expect(renders[1]!.phase).toBe("update");
unsubscribe();
});
```
--------------------------------
### useDeferredValue Example
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/concurrent/README.md
Demonstrates using useDeferredValue to defer rendering expensive updates, improving performance for components like large lists or visualizations. The deferred value updates later than the input.
```typescript
const [input, setInput] = useState('');
const deferredInput = useDeferredValue(input);
// Expensive component receives deferred value
```
--------------------------------
### Run vitest-react-profiler Tests
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/basic/README.md
Commands to execute tests using vitest-react-profiler. Includes options for UI debugging, coverage, and watch mode.
```bash
# Run all tests
npm test
# Run with UI for visual debugging
npm run test:ui
# Run with coverage
npm run test:coverage
# Watch mode for development
npm run test:watch
```
--------------------------------
### Test Batched State Updates
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Best-Practices
Verify that multiple state updates are batched into a single render. This example uses `fireEvent` to trigger updates and `toHaveRenderedTimes` to assert the expected render count.
```typescript
it('should batch state updates', () => {
const Profiled = withProfiler(MultiStateComponent);
const { getByText } = render();
// Trigger multiple state updates
fireEvent.click(getByText("Update All"));
// React should batch them into 1 render
expect(Profiled).toHaveRenderedTimes(2); // mount + batched update
});
```
--------------------------------
### Track Initial Render Performance
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/performance/README.md
Measures the initial mount and update phases of a component. Ensures the render completes within a specified time limit.
```typescript
// Track initial render performance
it("should track initial render performance");
// Measures mount and update phases separately
// Validates render completes within 1000ms
```
--------------------------------
### Integrate with React Testing Library
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Advanced-Usage
Use vitest-react-profiler seamlessly within your React Testing Library tests. This example shows how to profile a component and assert its render count after user interactions.
```typescript
import { render, screen, fireEvent } from '@testing-library/react';
import { withProfiler } from 'vitest-react-profiler';
it('should integrate with RTL', () => {
const Profiled = withProfiler(Counter);
render();
const button = screen.getByRole('button');
fireEvent.click(button);
expect(Profiled).toHaveRenderedTimes(2);
expect(screen.getByText('1')).toBeInTheDocument();
});
```
--------------------------------
### Compare Virtualized vs Non-Virtualized List Performance
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/performance/README.md
Compares the render performance of virtualized and non-virtualized lists for a large number of items. Expects virtualized lists to be faster.
```typescript
// Virtualization comparison
it("should compare virtualized vs non-virtualized list performance");
// 1000 items
// Expects virtualized < non-virtualized render time
```
--------------------------------
### Wait for Async State Update
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/Examples
This example shows how to wait for an asynchronous state update in a component using `toEventuallyRenderTimes`. It asserts that the component renders at least twice (initial mount and after async update).
```typescript
const AsyncComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
setTimeout(() => {
setData({ result: "success" });
}, 100);
}, []);
return
{data?.result || "Loading..."}
;
};
it('should wait for async state update', async () => {
const Profiled = withProfiler(AsyncComponent);
render();
// Wait for mount + async update
await expect(Profiled).toEventuallyRenderTimes(2);
expect(Profiled).toHaveMountedOnce();
});
```
--------------------------------
### Fixing a Render Loop with Dependency Array
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
This example demonstrates how to fix an infinite render loop in a React component by correctly adding a dependency array to the `useEffect` hook. The `notToHaveRenderLoops` matcher can be used to detect such issues.
```jsx
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
setCount(c => c + 1);
}, []); // ✅ Added dependency array - loop fixed!
return
{count}
;
}
```
--------------------------------
### Run Vitest Tests
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/examples/memoization/README.md
Commands to run tests with vitest, including UI mode, coverage, and watch mode.
```bash
# Run all tests
npm test
# Run with UI
npm run test:ui
# Run with coverage
npm run test:coverage
# Watch mode for development
npm run test:watch
```
--------------------------------
### Use notToHaveRenderLoops with custom thresholds and component name
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
Configure `notToHaveRenderLoops` with custom thresholds for stricter loop detection and provide a component name for clearer error messages. This example sets the maximum consecutive updates to 3.
```typescript
expect(ProfiledComponent).notToHaveRenderLoops({
maxConsecutiveUpdates: 3,
componentName: 'Counter'
});
```
--------------------------------
### Real-world diagnostic workflow: Adding notToHaveRenderLoops to diagnose a hanging test
Source: https://github.com/greydragon888/vitest-react-profiler/wiki/API-Reference
This workflow shows how to use `notToHaveRenderLoops` to debug a test that hangs during rendering. By adding the matcher, you can get diagnostic information pinpointing the cause of the infinite loop, such as an `useEffect` issue.
```typescript
// Step 1: Test hangs - you don't know why
it('should update counter', () => {
render();
// Test hangs here... ❓
});
// Step 2: Add diagnostic matcher
it('should update counter', () => {
const Profiled = withProfiler(Counter);
render();
// Add this to diagnose the hang
expect(Profiled).notToHaveRenderLoops({
maxConsecutiveUpdates: 5
});
// Now you get: "Suspicious pattern: 11 consecutive 'update' phases"
// → Points to useEffect infinite loop
});
// Step 3: Fix the bug
```
--------------------------------
### Verify File Extensions Before Reading Configs
Source: https://github.com/greydragon888/vitest-react-profiler/blob/master/CLAUDE.md
Always check actual file extensions using `ls` before attempting to read or modify configuration files. This prevents errors caused by assuming incorrect extensions.
```bash
# ✅ CORRECT: Check first
ls vitest.config.*
# ❌ WRONG: Assume extension
Read vitest.config.ts
```