Настройка vitest через vite.config

Vitest тесно интегрирован с Vite и использует его конфигурацию как основу для запуска тестов. Благодаря этому тестовая среда автоматически наследует:

  • алиасы;
  • плагины;
  • настройки TypeScript;
  • обработку CSS;
  • поддержку Vue, React, Svelte и других фреймворков;
  • переменные окружения;
  • особенности SSR;
  • трансформации модулей.

Основная идея заключается в том, что тесты выполняются в том же окружении, что и приложение. Это избавляет от дублирования конфигурации и делает поведение тестов максимально приближенным к реальной сборке.


Базовая структура конфигурации

Vitest может настраиваться прямо внутри vite.config.js, vite.config.ts или отдельного файла vitest.config.ts.

Простейшая конфигурация внутри vite.config.ts:

import { defineConfig } from 'vite'

export default defineConfig({
  test: {
    globals: true
  }
})

Для TypeScript чаще используется импорт из vitest/config:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true
  }
})

Причина использования vitest/config связана с типизацией. Этот вариант позволяет IDE корректно понимать секцию test.


Подключение Vitest в проект

После установки:

npm install -D vitest

в package.json обычно добавляется:

{
  "scripts": {
    "test": "vitest"
  }
}

Запуск:

npm run test

Режим наблюдения:

npm run test -- --watch

Однократный запуск:

npm run test -- --run

Секция test

Все параметры Vitest располагаются внутри свойства test.

Пример расширенной конфигурации:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
    watch: false,
    include: ['src/**/*.test.ts'],
    exclude: ['node_modules', 'dist']
  }
})

Параметр globals

По умолчанию Vitest требует явного импорта тестовых функций:

import { describe, it, expect } from 'vitest'

При включении:

test: {
  globals: true
}

глобально становятся доступны:

  • describe
  • it
  • test
  • expect
  • beforeEach
  • afterEach
  • vi

Тогда тест можно писать так:

describe('sum', () => {
  it('adds numbers', () => {
    expect(1 + 1).toBe(2)
  })
})

Плюсы globals

  • меньше импортов;
  • код ближе к Jest;
  • лаконичные тесты.

Минусы

  • менее явные зависимости;
  • сложнее анализировать код;
  • возможны конфликты имён.

В крупных проектах часто предпочитают явные импорты.


Параметр environment

Определяет среду выполнения тестов.

node

Используется по умолчанию.

test: {
  environment: 'node'
}

Подходит для:

  • backend;
  • утилит;
  • Node.js API;
  • SSR-логики;

jsdom

Эмулирует браузер.

test: {
  environment: 'jsdom'
}

Необходим для:

  • React;
  • Vue;
  • DOM API;
  • browser events;
  • Testing Library.

Пример:

document.body.innerHTML = `
  <button id="btn">Click</button>
`

const button = document.querySelector('#btn')

expect(button?.textContent).toBe('Click')

Без jsdom объект document отсутствует.


happy-dom

Альтернативная браузерная среда.

test: {
  environment: 'happy-dom'
}

Особенности:

  • быстрее jsdom;
  • меньше потребление памяти;
  • не полностью совместим с браузером.

Часто используется для ускорения CI.


Параметр include

Определяет список тестовых файлов.

test: {
  include: ['src/**/*.test.ts']
}

Поддерживаются:

  • glob-паттерны;
  • массивы путей;
  • вложенные шаблоны.

Пример:

include: [
  'src/**/*.test.ts',
  'src/**/*.spec.ts'
]

Параметр exclude

Исключает файлы из тестирования.

test: {
  exclude: [
    'node_modules',
    'dist',
    '.idea'
  ]
}

Часто сюда добавляют:

exclude: [
  '**/e2e/**',
  '**/coverage/**'
]

Параметр watch

Управляет режимом наблюдения.

test: {
  watch: false
}

Если true, Vitest автоматически перезапускает тесты при изменениях файлов.


Параметр setupFiles

Позволяет запускать код перед стартом тестов.

test: {
  setupFiles: ['./tests/setup.ts']
}

Пример setup-файла

import '@testing-library/jest-dom'

Или:

beforeEach(() => {
  localStorage.clear()
})

Параметр css

Управляет обработкой CSS.

test: {
  css: true
}

Особенно полезно при тестировании:

  • CSS Modules;
  • Vue SFC;
  • React-компонентов;
  • Tailwind.

Параметр mockReset

Автоматически сбрасывает mock-функции.

test: {
  mockReset: true
}

Эквивалентно:

beforeEach(() => {
  vi.resetAllMocks()
})

Параметр clearMocks

Очищает историю вызовов.

test: {
  clearMocks: true
}

Разница:

  • clearMocks — очищает вызовы;
  • mockReset — очищает реализацию и вызовы;
  • restoreMocks — восстанавливает оригинальные методы.

Параметр restoreMocks

test: {
  restoreMocks: true
}

Полезно при использовании:

vi.spyOn()

Параметр coverage

Настройка покрытия кода.

Пример:

test: {
  coverage: {
    provider: 'v8',
    reporter: ['text', 'html']
  }
}

Провайдеры coverage

v8

provider: 'v8'

Преимущества:

  • высокая скорость;
  • встроенная поддержка Node.js;
  • минимальные накладные расходы.

istanbul

provider: 'istanbul'

Особенности:

  • больше возможностей;
  • совместимость со старыми инструментами;
  • медленнее v8.

Форматы отчётов

reporter: ['text', 'json', 'html']

Популярные варианты:

  • text
  • json
  • html
  • lcov

Запуск coverage

vitest run --coverage

Параметр alias

Vitest использует алиасы Vite.

import path from 'node:path'
import { defineConfig } from 'vitest/config'

export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  }
})

Тогда:

import Button from '@/components/Button'

работает одинаково:

  • в приложении;
  • в тестах;
  • в dev server;
  • в build.

Использование плагинов Vite

Vitest автоматически применяет Vite-плагины.


React

import react from '@vitejs/plugin-react'
import { defineConfig } from 'vitest/config'

export default defineConfig({
  plugins: [react()]
})

Vue

import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()]
})

Svelte

import { svelte } from '@sveltejs/vite-plugin-svelte'

export default defineConfig({
  plugins: [svelte()]
})

Настройка TypeScript

Vitest автоматически использует tsconfig.json.

Пример:

{
  "compilerOptions": {
    "types": ["vitest/globals"]
  }
}

Это необходимо при использовании:

globals: true

Разделение конфигураций

Иногда Vite и Vitest конфигурируются отдельно.


vitest.config.ts

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true
  }
})

Использование mergeConfig

import { mergeConfig } from 'vite'
import viteConfig from './vite.config'
import { defineConfig } from 'vitest/config'

export default mergeConfig(
  viteConfig,
  defineConfig({
    test: {
      globals: true
    }
  })
)

Это позволяет:

  • переиспользовать Vite-конфиг;
  • не дублировать алиасы;
  • сохранить плагины;
  • разделить build и test настройки.

Настройка testTimeout

Устанавливает таймаут тестов.

test: {
  testTimeout: 5000
}

Пример:

it('fetches data', async () => {
  await fetchData()
}, 5000)

Настройка hookTimeout

Таймаут lifecycle-хуков:

test: {
  hookTimeout: 10000
}

Относится к:

  • beforeAll
  • beforeEach
  • afterEach
  • afterAll

Настройка retry

Повтор тестов при ошибке.

test: {
  retry: 2
}

Полезно для:

  • flaky-тестов;
  • нестабильного CI;
  • сетевых операций.

Настройка threads

Vitest поддерживает многопоточность.

test: {
  threads: true
}

Отключение:

threads: false

Иногда требуется при:

  • shared state;
  • legacy-коде;
  • нестабильных глобальных объектах.

Настройка reporters

Определяет формат вывода результатов.

test: {
  reporters: ['default']
}

Другие варианты:

reporters: [
  'verbose',
  'json',
  'junit'
]

Настройка outputFile

Используется вместе с json или junit.

test: {
  reporters: ['json'],
  outputFile: './reports/tests.json'
}

Browser Mode

Vitest поддерживает запуск тестов в браузере.

Пример:

test: {
  browser: {
    enabled: true,
    name: 'chrome'
  }
}

Поддерживаются:

  • Chrome;
  • Firefox;
  • Edge;
  • Playwright.

Использование defineConfig

Рекомендуемый вариант:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true
  }
})

Преимущества:

  • автодополнение;
  • типизация;
  • проверка конфигурации;
  • поддержка IDE.

Полный пример конфигурации

import path from 'node:path'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vitest/config'

export default defineConfig({
  plugins: [react()],

  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  },

  test: {
    globals: true,
    environment: 'jsdom',

    include: [
      'src/**/*.test.ts',
      'src/**/*.spec.tsx'
    ],

    exclude: [
      'node_modules',
      'dist',
      'e2e'
    ],

    setupFiles: ['./tests/setup.ts'],

    css: true,

    clearMocks: true,
    restoreMocks: true,

    testTimeout: 5000,

    coverage: {
      provider: 'v8',
      reporter: ['text', 'html']
    }
  }
})

Типичная структура проекта

project/
├── src/
├── tests/
│   ├── setup.ts
│   └── unit/
├── vite.config.ts
├── vitest.config.ts
├── tsconfig.json
└── package.json

Распространённые ошибки

Ошибка document is not defined

Причина:

environment: 'node'

Решение:

environment: 'jsdom'

Не работают алиасы

Причина:

  • отсутствует resolve.alias;
  • неправильный путь;
  • отдельный vitest.config.ts без merge.

Не видны глобальные типы

Решение:

{
  "compilerOptions": {
    "types": ["vitest/globals"]
  }
}

Плагины Vite не применяются

Причины:

  • отдельная конфигурация без merge;
  • неверный импорт defineConfig;
  • конфликт версий Vite и Vitest.

Отличия настройки Vitest от Jest

Возможность Vitest Jest
Использует Vite Да Нет
ESM Нативно Ограниченно
Скорость HMR Очень высокая Ниже
Конфигурация Через Vite Отдельная
Трансформация TS esbuild babel/ts-jest
Browser Mode Есть Ограниченно

Практический пример для React

import react from '@vitejs/plugin-react'
import { defineConfig } from 'vitest/config'

export default defineConfig({
  plugins: [react()],

  test: {
    environment: 'jsdom',
    globals: true,
    setupFiles: ['./src/tests/setup.ts']
  }
})

setup.ts:

import '@testing-library/jest-dom'

Практический пример для Vue

import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vitest/config'

export default defineConfig({
  plugins: [vue()],

  test: {
    environment: 'jsdom',
    globals: true
  }
})

Практический пример для Node.js

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    environment: 'node',
    globals: false,
    threads: true
  }
})

Практический пример для monorepo

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    projects: [
      './packages/frontend',
      './packages/backend'
    ]
  }
})

Такой подход позволяет:

  • изолировать тестовые окружения;
  • разделять coverage;
  • использовать разные environment;
  • запускать тесты пакетами.