Vitest Browser React Renderer
vitest-browser-react is a testing utility designed to render React components within Vitest's Browser Mode, providing a browser-like environment for component testing. Currently at version 2.2.0, this library receives regular updates, often aligning with Vitest's own release cycle, indicating active maintenance. Its core differentiator lies in its deep integration with Vitest Browser Mode's native locator and retry-ability APIs, offering an ergonomic testing experience without requiring explicit `act` calls for most scenarios. Unlike `@testing-library/react`, it leverages Vitest's built-in browser assertion mechanisms, simplifying asynchronous testing patterns. It also provides a `renderHook` utility for testing React hooks and can automatically inject `page.render` into the Vitest `page` object for convenience.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'render')
cause The `render` function from 'vitest-browser-react' was not properly imported or the `page.render` global was not correctly set up in Vitest Browser Mode.fixEnsure you have `import { render } from 'vitest-browser-react'` at the top of your test file or `import 'vitest-browser-react'` in your Vitest `setupFiles` if you intend to use `page.render`. -
Error: `vitest-browser-react` requires `vitest@^4.0.0`. Found `vitest@3.2.0`.
cause Mismatch between the installed `vitest` version and the peer dependency requirement of `vitest-browser-react`.fixUpgrade your `vitest` package to version 4.0.0 or newer: `npm install vitest@latest` or `yarn add vitest@latest`. -
Warning: An update to X inside a test was not wrapped in act(...)
cause React detected state updates or effects outside of an `act` context during testing, often due to asynchronous operations not being awaited or handled within the testing utility's lifecycle.fixReview your test for any asynchronous operations or direct state mutations. Ensure that any interactions causing state changes are properly awaited (e.g., `await screen.getByRole('button').click()`) or, if necessary, explicitly wrapped in `act` from `vitest/browser`. -
ReferenceError: React is not defined
cause React is not implicitly available in the scope where JSX is being used, typically because `@vitejs/plugin-react` is missing or misconfigured in `vite.config.ts`.fixAdd `@vitejs/plugin-react` to your `vite.config.ts` (`npm i -D @vitejs/plugin-react`) or ensure `import React from 'react'` is present in files containing JSX, if not using automatic JSX runtime.
Warnings
- breaking Version 2.0.0 introduced breaking changes related to `async act v2` and support for Vitest 4 syntax. Migrating from `vitest-browser-react` v1 to v2 requires upgrading to Vitest 4.x and potentially adjusting how `act` is handled or ensuring full reliance on the library's built-in retry mechanisms.
- gotcha The library explicitly requires `vitest` 4.0.0 or higher as a peer dependency. Using an older version of Vitest will result in installation issues or runtime errors, as `vitest-browser-react` relies on features and APIs introduced in Vitest 4.
- gotcha For proper JSX support and certain React features (like auto-importing React), it's highly recommended to use `@vitejs/plugin-react` in your `vite.config.ts`. Without it, you might encounter issues with JSX transformation or 'React is not defined' errors.
- gotcha Although `vitest-browser-react` tries to avoid `act` warnings internally, complex asynchronous state updates or direct DOM manipulations outside of the library's `render` and `act` helpers can still trigger React's 'An update to X inside a test was not wrapped in act(...)' warnings.
Install
-
npm install vitest-browser-react -
yarn add vitest-browser-react -
pnpm add vitest-browser-react
Imports
- render
const { render } = require('vitest-browser-react')import { render } from 'vitest-browser-react' - renderHook
import renderHook from 'vitest-browser-react'
import { renderHook } from 'vitest-browser-react' - page.render
import { render } from 'vitest-browser-react'; await page.render(...)import { page } from 'vitest/browser'; await page.render(...) - configure
import { configure } from 'vitest-browser-react'import { configure } from 'vitest-browser-react/pure' - Global Types
import 'vitest-browser-react'
Quickstart
import { render } from 'vitest-browser-react';
import { expect, test } from 'vitest';
function Counter({ initialCount = 0 }) {
const [count, setCount] = useState(initialCount);
return (
<div>
<p>Count is {count}</p>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
);
}
// Simulate useState if React is not directly imported for brevity
let currentCount = 0;
const useState = (initial) => {
if (currentCount === 0) currentCount = initial;
const setter = (val) => { currentCount = typeof val === 'function' ? val(currentCount) : val; };
return [currentCount, setter];
};
test('counter button increments the count', async () => {
currentCount = 1; // Reset for test clarity
const screen = await render(<Counter initialCount={1} />);
await screen.getByRole('button', { name: 'Increment' }).click();
await expect.element(screen.getByText('Count is 2')).toBeVisible();
});