Vitest + RTL Vitest and RTL Testing

Last updated: 2026-11-02

Vitest + RTL Vitest and RTL Testing

Vitest is a very fast test runner that shares its configuration with Vite, and React Testing Library lets you test components the way a user would: render mounts the component, getByRole queries it by semantics, userEvent simulates interactions, and the assertions target behaviour instead of implementation details. That shift is what makes the tests survive a refactoring. Because the runner reuses the Vite pipeline, the same module graph that powers the dev server powers the suite.

GroupData & Engineering
KindTooling
SinceVitest 2.x + RTL 16

ℹ️ Info The editor transpiles JSX to JavaScript and renders the real UI in a sandbox; components mount automatically — no manual render call needed.

📝 Syntax

import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import Counter from './Counter'

describe('Counter', () => {
  it('increments the number after a click', async () => {
    render(<Counter />)
    expect(screen.getByRole('status')).toHaveTextContent('0')
    await userEvent.click(screen.getByRole('button', { name: '+1' }))
    expect(screen.getByRole('status')).toHaveTextContent('1')
  })
})

Returns:describe and it organise the cases; render mounts the component and returns the query handles; screen.getByRole and friends query elements by semantics; expect asserts the result.

▶ Example

The example runs out of the box: it auto-renders when expanded, and edits take effect instantly.

Output:

The Counter above changes with the buttons while the case panel below lights up one entry at a time - the RTL flow of a getByRole query plus a passing expect assertion (simulated demo).

💡 Key Points

💡 Tip Prefer semantic queries such as getByRole and getByLabelText: the test doubles as an accessibility check and stays closer to the user than getByTestId.
ℹ️ Info Vitest shares the configuration and the transform pipeline with Vite and is far faster than Jest; migrating from Jest usually only means changing the import source.
⚠️ Warning Do not assert on internal state or implementation details, a refactoring will turn the whole suite red; test what the user can see and what happens when they click.
More case studies coming soon.

📚 Related Tutorials

❓ FAQ

Q How does the thinking differ between RTL and Enzyme?
A Enzyme often reaches into the internal state and props, that is implementation detail, while RTL only queries the rendered result the way a user would. The tests survive refactoring better and it is the officially recommended approach.
Q How do I test an async operation (rendering after a request)?
A Use the findByRole family of queries, which poll with waitFor built in, and intercept the network with msw so the response returns controlled fake data.
Q How does Vitest test a custom Hook?
A Use renderHook from @testing-library/react, read the latest return value from result.current and assert after rerender triggers an update.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏