5. Vitest: введение

Что такое Vitest?
Заголовок раздела «Что такое Vitest?»Vitest — современный тест-раннер для Vite-проектов. В 2-10× быстрее Jest благодаря нативной ESM поддержке и параллельному выполнению.
Установка
Заголовок раздела «Установка»npm install --save-dev vitest
# Для UInpm install --save-dev @vitest/ui
# Для coveragenpm install --save-dev @vitest/coverage-v8// vite.config.ts или vitest.config.tsimport { defineConfig } from 'vitest/config'
export default defineConfig({ test: { environment: 'node', // или 'jsdom', 'happy-dom' globals: true, // нет нужды импортировать expect, test setupFiles: ['./src/test/setup.ts'], coverage: { provider: 'v8', reporter: ['text', 'html'], include: ['src/**/*.ts'], }, },}){ "scripts": { "test": "vitest", "test:ui": "vitest --ui", "test:run": "vitest run", "test:coverage": "vitest run --coverage" }}Совместимость с Jest
Заголовок раздела «Совместимость с Jest»Vitest полностью совместим с Jest API — большинство тестов переносятся без изменений:
// Работает одинаково в Jest и Vitestimport { describe, it, expect, beforeEach, vi } from 'vitest'
describe('calculator', () => { it('adds numbers', () => { expect(1 + 1).toBe(2) })})Параллельное выполнение
Заголовок раздела «Параллельное выполнение»// Параллельные тесты внутри файла (осторожно с shared state)import { describe, it, expect } from 'vitest'
describe.concurrent('parallel tests', () => { it('test 1', async () => { await someAsyncOperation() expect(true).toBe(true) })
it('test 2', async () => { await anotherAsyncOperation() expect(true).toBe(true) })})Vitest UI
Заголовок раздела «Vitest UI»npx vitest --uiОткрывает интерактивный браузерный интерфейс с деревом тестов, ошибками и coverage.
Snapshot тесты
Заголовок раздела «Snapshot тесты»import { expect, it } from 'vitest'
it('renders correctly', () => { const result = formatUser({ name: 'Alice', role: 'admin' }) expect(result).toMatchSnapshot() // При первом запуске: создаёт снапшот // При последующих: сравнивает с сохранённым})
// Inline snapshotit('inline snapshot', () => { expect(formatUser({ name: 'Bob' })).toMatchInlineSnapshot(` { "display": "Bob", "initials": "B", } `)})
// Обновить снапшоты// npx vitest --update-snapshotsОтличия от Jest
Заголовок раздела «Отличия от Jest»// Moки: vi вместо jestimport { vi } from 'vitest'
// jest.fn() → vi.fn()const mockFn = vi.fn()
// jest.spyOn() → vi.spyOn()const spy = vi.spyOn(console, 'log')
// jest.mock() → vi.mock()vi.mock('./api', () => ({ fetchUser: vi.fn().mockResolvedValue({ name: 'Alice' })}))
// jest.useFakeTimers() → vi.useFakeTimers()vi.useFakeTimers()
// jest.setSystemTime() → vi.setSystemTime()vi.setSystemTime(new Date('2024-01-15'))Настройка jsdom для React
Заголовок раздела «Настройка jsdom для React»export default defineConfig({ test: { environment: 'jsdom', globals: true, setupFiles: ['./src/test/setup.ts'], },})
// src/test/setup.tsimport '@testing-library/jest-dom'In-Source Testing (тесты прямо в файле)
Заголовок раздела «In-Source Testing (тесты прямо в файле)»export function add(a: number, b: number) { return a + b}
// Тесты прямо в исходнике (удаляются при сборке)if (import.meta.vitest) { const { it, expect } = import.meta.vitest it('adds correctly', () => { expect(add(1, 2)).toBe(3) })}export default defineConfig({ test: { includeSource: ['src/**/*.ts'], }, define: { 'import.meta.vitest': 'undefined', // убрать в продакшн },})Практические задания
Заголовок раздела «Практические задания»- Создай Vite + TypeScript проект, добавь Vitest
- Перенеси Jest тесты в Vitest (измени импорты)
- Настрой coverage report и посмотри результат в HTML
- Vitest быстрее Jest за счёт Vite и ESM
- API совместим с Jest — миграция проста
viвместоjestдля моков и spy- Встроенный UI (
vitest --ui) — удобно для разработки