返回 Skill 列表
extension
分类: 开发与工程无需 API Key

testing-react-with-vitest

专家指导使用React Testing Library为React应用程序编写Vitest测试。涵盖了组件测试、自定义钩子、实用工具测试、社交测试理念以及RTL查询优先级系统。偏好社交测试而非重度模拟,偏好存根而非模拟。在处理.test.ts/.test.tsx文件、vitest.config.ts、React Testing Library、@testing-library/user-event、@testing-library/jest-dom、renderHook时使用,或在讨论React测试模式、组件测试、钩子测试或测试组织时使用。

person作者: jakexiaohubgithub

Testing React with Vitest

Expert guidance for writing great Vitest tests for React applications using React Testing Library.

Quick Start

| Testing... | Reference File | Key Topics | |------------|----------------|------------| | Core Vitest setup, matchers, spies | core-vitest | describe, it, expect, vi.fn, vi.mock, timers | | RTL queries, render, screen | react-testing-library | render, screen, queries, waitFor, debug | | User interactions | user-event | setup, click, type, keyboard, async events | | Sociable tests, stubs, boundaries | sociable-testing | Real components, stub boundaries, functional core | | Custom hooks with renderHook | custom-hooks | renderHook, act, providers, cleanup | | Component testing patterns | component-patterns | Forms, modals, lists, error boundaries, a11y | | jest-dom assertion matchers | assertions | toBeInTheDocument, toBeVisible, toHaveTextContent |

Testing Philosophy

These principles are non-negotiable defaults for all React testing advice.

Sociable Tests by Default

Use real child components. A test for <CheckoutPage /> should render real <CartSummary /> and <PaymentForm /> components, not mocked replacements. Sociable tests catch integration bugs, survive refactors, and test actual behavior.

Stubs Over Mocks

When you must replace a dependency, prefer stubs that return canned data over mocks that verify call sequences. A stubbed fetch that returns { items: [] } is better than a mock that asserts fetch was called with specific arguments.

Test Behavior, Not Implementation

Assert on what the user sees and can do. Never assert on internal state, hook return values observed from outside, or component instance methods. If a user cannot observe it, do not test it.

Only Stub at True System Boundaries

Real boundaries: fetch/HTTP clients, browser APIs (localStorage, navigator, IntersectionObserver), third-party services, timers. Not boundaries: your own components, hooks, utilities, or context providers.

Query Priority: role > label > text > testid

Prefer accessible queries. getByRole('button', { name: 'Submit' }) is better than getByTestId('submit-btn'). Test IDs are a last resort when no accessible query works.

Anti-Patterns

  • Mocking child components: vi.mock('./CartSummary') hides integration bugs. Render real children unless they hit a system boundary.
  • Testing implementation details: expect(setState).toHaveBeenCalledWith(...) couples tests to internals. Assert on rendered output instead.
  • Snapshot overuse: Large snapshots break on every change and nobody reads the diffs. Prefer targeted assertions on specific elements.
  • Using container.querySelector: Bypasses the accessibility-first query model. Use screen.getByRole, screen.getByLabelText, or screen.getByText instead.
  • Wrapping every action in act(): RTL's render, fireEvent, and user-event already wrap in act(). Manual act() is only needed for direct state updates outside RTL.
  • Testing CSS classes or inline styles: These are implementation details. Use toBeVisible(), toHaveAccessibleName(), or test the behavior the style enables.
  • Mocking your own hooks: vi.mock('./useCart') tests the component in isolation from its real logic. Let the component use its real hooks.
  • getByTestId as a first choice: Always try getByRole, getByLabelText, getByText, getByPlaceholderText first. Test IDs are a last resort.

Reference File IDs

core-vitest . react-testing-library . user-event . sociable-testing . custom-hooks . component-patterns . assertions