Перейти к содержимому

13. Тестирование с Vitest

Vitest — это современный тест-раннер, созданный специально для Vite-проектов. Он использует ту же конфигурацию vite.config.ts, поддерживает ESM из коробки и работает значительно быстрее Jest благодаря нативной интеграции с Vite.

Окно терминала
npm i -D vitest
# или с jsdom для тестирования DOM
npm i -D vitest jsdom @testing-library/react @testing-library/jest-dom
vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
test: {
// Среда выполнения тестов
environment: 'jsdom', // 'node' | 'jsdom' | 'happy-dom'
// Глобальные функции (describe, it, expect без импорта)
globals: true,
// Setup файл (импорт jest-dom матчеров)
setupFiles: ['./src/setupTests.ts'],
// Coverage
coverage: {
provider: 'v8', // 'v8' | 'istanbul'
reporter: ['text', 'html', 'lcov'],
include: ['src/**'],
exclude: ['src/**/*.stories.tsx'],
thresholds: {
lines: 80,
functions: 80,
branches: 70,
},
},
// Параллельное выполнение
pool: 'threads', // 'threads' | 'forks' | 'vmThreads'
poolOptions: {
threads: {
singleThread: false,
},
},
},
})
src/utils/math.test.ts
import { describe, it, expect } from 'vitest'
import { add, multiply, factorial } from './math'
describe('math utils', () => {
describe('add()', () => {
it('складывает два числа', () => {
expect(add(2, 3)).toBe(5)
})
it('работает с отрицательными числами', () => {
expect(add(-1, 1)).toBe(0)
})
})
it('factorial(5) === 120', () => {
expect(factorial(5)).toBe(120)
})
})
src/components/Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react'
import { describe, it, expect, vi } from 'vitest'
import { Button } from './Button'
describe('Button', () => {
it('отображает текст', () => {
render(<Button>Click me</Button>)
expect(screen.getByText('Click me')).toBeInTheDocument()
})
it('вызывает onClick при клике', () => {
const handleClick = vi.fn()
render(<Button onClick={handleClick}>Click me</Button>)
fireEvent.click(screen.getByText('Click me'))
expect(handleClick).toHaveBeenCalledOnce()
})
it('disabled кнопка не реагирует на клики', () => {
const handleClick = vi.fn()
render(<Button disabled onClick={handleClick}>Disabled</Button>)
fireEvent.click(screen.getByText('Disabled'))
expect(handleClick).not.toHaveBeenCalled()
})
})
// Mock функции
import { vi } from 'vitest'
// Мок модуля
vi.mock('./api', () => ({
fetchUser: vi.fn().mockResolvedValue({ id: 1, name: 'Alice' }),
}))
// Шпион
const spy = vi.spyOn(console, 'error')
expect(spy).toHaveBeenCalledWith('Expected error')
// Таймеры
vi.useFakeTimers()
vi.advanceTimersByTime(1000)
vi.useRealTimers()
// Инлайн снапшоты
expect(result).toMatchInlineSnapshot(\`
{
"name": "Alice",
"age": 30,
}
\`)
Окно терминала
# Запуск всех тестов
npx vitest
# Watch mode (для разработки)
npx vitest --watch
# UI mode — красивый веб-интерфейс
npx vitest --ui
# Coverage
npx vitest run --coverage
# Конкретный файл
npx vitest Button.test.tsx
# Bench (бенчмарки производительности)
npx vitest bench
51204/__vitest__/
npm i -D @vitest/ui
npx vitest --ui

Ниже — симулятор тест-раннера: запускай тесты и смотри результаты: