Vitest + React Testing Library
约 405 字大约 1 分钟
布欧-Lewyon
2026-05-15
配置
npm install -D vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: './src/test/setup.ts',
},
})// src/test/setup.ts
import '@testing-library/jest-dom'渲染测试
// Counter.tsx
function Counter({ initial = 0 }) {
const [count, setCount] = useState(initial)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
)
}// Counter.test.tsx
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { describe, it, expect } from 'vitest'
describe('Counter', () => {
it('renders initial count', () => {
render(<Counter initial={5} />)
expect(screen.getByText('Count: 5')).toBeInTheDocument()
})
it('increments count on click', async () => {
const user = userEvent.setup()
render(<Counter />)
const button = screen.getByRole('button', { name: 'Increment' })
await user.click(button)
expect(screen.getByText('Count: 1')).toBeInTheDocument()
})
})异步测试
// UserList.tsx
function UserList() {
const [users, setUsers] = useState<string[]>([])
useEffect(() => {
setTimeout(() => setUsers(['Alice', 'Bob']), 100)
}, [])
return (
<ul>
{users.map(u => <li key={u}>{u}</li>)}
</ul>
)
}it('loads and displays users', async () => {
render(<UserList />)
// 等待数据出现
await waitFor(() => {
expect(screen.getByText('Alice')).toBeInTheDocument()
expect(screen.getByText('Bob')).toBeInTheDocument()
})
})Hook 测试
// useCounter.ts
function useCounter(initial = 0) {
const [count, setCount] = useState(initial)
const increment = () => setCount(c => c + 1)
const decrement = () => setCount(c => c - 1)
return { count, increment, decrement }
}import { renderHook, act } from '@testing-library/react'
describe('useCounter', () => {
it('should increment', () => {
const { result } = renderHook(() => useCounter())
act(() => result.current.increment())
expect(result.current.count).toBe(1)
})
it('should accept initial value', () => {
const { result } = renderHook(() => useCounter(10))
expect(result.current.count).toBe(10)
})
})Mock 函数
import { vi } from 'vitest'
it('calls onSubmit with form data', async () => {
const onSubmit = vi.fn()
const user = userEvent.setup()
render(<Form onSubmit={onSubmit} />)
await user.type(screen.getByLabelText('Name'), 'Alice')
await user.click(screen.getByRole('button', { name: 'Submit' }))
expect(onSubmit).toHaveBeenCalledWith({ name: 'Alice' })
expect(onSubmit).toHaveBeenCalledTimes(1)
})小结
- Vitest + React Testing Library 是前端测试标准组合。
render/screen.getBy*/userEvent模拟交互。waitFor处理异步渲染。renderHook+act测试自定义 Hook。vi.fn()创建 Mock 函数验证回调。
上一节:HOC 与错误边界 下一节:Cypress E2E 测试
