Почему Vitest?

Vitest представляет собой легковесную, быструю и современную среду тестирования, разработанную на основе экосистемы Vite. Она позиционируется как убедительная альтернатива уже зарекомендовавшим себя инструментам, таким как Jest, и особенно привлекательна для проектов, использующих современные JavaScript и TypeScript.

Фундаментальная сила Vitest заключается в использовании сверхбыстрой системы сборки и сервера разработки Vite, что приводит к мгновенным обновлениям во время тестирования и обеспечивает согласованный рабочий процесс от разработки до тестирования.

Vitest не просто является очередной средой тестирования; она спроектирована для оптимизации опыта разработчика, предлагая минимальную настройку и впечатляющую скорость. Ее глубокая интеграция с Vite означает, что процесс тестирования ощущается естественным продолжением процесса разработки, что улучшает как скорость, так и общий рабочий процесс.

Ключевые преимущества

Бесшовная совместимость с Jest и путь миграции

Vitest разработан с учетом высокой совместимости с API Jest, что делает переход для команд, уже использующих Jest, на удивление плавным. Это включает в себя знакомые функции, такие как describe, it (или test), expect, а также хуки жизненного цикла, такие как beforeEach, afterEach, beforeAll и afterAll. API для мокирования, хотя и использует vi вместо jest, работает по схожим принципам.

Высокая совместимость с Jest значительно снижает барьер для внедрения Vitest в существующие проекты. Это означает, что анализ затрат и выгод для миграции явно благоприятствует Vitest, поскольку команды могут получить преимущества в производительности без полной переработки своих тестовых наборов. Такое положение дел делает Vitest не просто альтернативой, а прямым, оптимизированным по производительности путем обновления для пользователей Jest, что способствует его быстрому внедрению.

Молниеносная производительность (интеграция с Vite, горячая перезагрузка, режим наблюдения)

Vitest обеспечивает значительно более быстрое выполнение тестов по сравнению с Jest, что особенно заметно в режиме наблюдения. Эта скорость объясняется уникальным подходом Vitest, использующим сервер разработки Vite и горячую перезагрузку модулей. Вместо повторного запуска целых тестовых файлов механизм горячей перезагрузки Vitest гарантирует, что повторно выполняются только измененный код и непосредственно затронутые тесты, что приводит к значительным приростам производительности. Независимые тесты показывают, что Vitest может работать в 10-20 раз быстрее, чем Jest, для тех же тестов в режиме наблюдения.

Сравнение функций Vitest и Jest:

 

Функция Подход/Поведение Jest Подход/Поведение Vitest
Скорость (режим наблюдения) Приоритет надежности, создает отдельные среды/процессы Node.js, может быть медленнее для крупных проектов. Значительно быстрее (в 10-20 раз в режиме наблюдения), использует сервер разработки Vite и горячую перезагрузку (запускается только измененный код/затронутые тесты).
Поддержка ES-модулей Часто требует Babel/дополнительной настройки для полной поддержки ESM. Нативная поддержка ESM «из коробки».
Поддержка TypeScript Может требовать дополнительной настройки для TS. Нативная поддержка TypeScript «из коробки».
Конфигурация Отдельный файл конфигурации (jest.config.js). Использует общую конфигурацию Vite (vite.config.ts) или выделенный vitest.config.ts для согласованности.
API мокирования Использует глобальный объект jest для мокирования. Использует глобальный объект vi или импорты для мокирования, с очень похожим API.
Сообщество/Экосистема Более крупное, зрелое сообщество, обширные сторонние инструменты. Новое, быстрорастущее сообщество, преимущества экосистемы Vite.
Поведение наблюдателя Создает отдельные среды для тестов, повторно запускает целые тестовые файлы при изменении. Горячая перезагрузка, интеллектуально повторно запускает только затронутые тесты.

 

Начало работы: базовое тестирование JavaScript с Vitest

Установка и начальная настройка

Для начала работы с Vitest необходимо убедиться, что установлены Node.js версии 18.3 или выше и Vite версии 5 или выше. Процесс установки начинается с инициализации нового проекта npm: npm init -y. Затем критически важно включить модули ES в файле package.json, добавив "type": "module" или выполнив команду npm pkg set type="module". Это является ключевым шагом для современных проектов на JavaScript.

После этого Vitest устанавливается как зависимость для разработки: npm install -D vitest. Для удобного запуска тестов рекомендуется добавить скрипт test в файл package.json: "scripts": { "test": "vitest" }. Для получения интерактивного браузерного пользовательского интерфейса для запуска тестов можно дополнительно установить @vitest/ui: npm install -D @vitest/ui. 

Базовая конфигурация (vitest.config.ts и скрипты package.json)

Vitest может бесшовно интегрироваться с существующим файлом vite.config.ts, наследуя плагины и конфигурации, такие как resolve.alias, непосредственно из конфигурации Vite. Для настроек, специфичных для тестирования, или для переопределения настроек Vite, можно создать выделенный файл vitest.config.ts в корне проекта. Этот файл имеет более высокий приоритет для опций, связанных с тестированием.  

Распространенной опцией конфигурации является globals: true внутри объекта test. Эта настройка делает утилиты тестирования, такие как describe, it и expect, глобально доступными, устраняя необходимость в явных импортах в каждом тестовом файле. Это может сделать тестовый код более чистым и привычным для пользователей Jest. Однако, хотя Vitest предлагает globals: true для совместимости с Jest и удобства, его поведение по умолчанию, требующее явных импортов, соответствует современному модульному подходу JavaScript. Такой подход способствует созданию более чистого кода, лучшему удалению неиспользуемого кода (tree-shaking) и избеганию загрязнения глобальной области видимости. Это представляет собой сознательный компромисс для разработчиков между простотой миграции/знакомства и соблюдением современных стандартов модулей.

Опция environment определяет среду выполнения для тестов. Для чистого JavaScript-кода или серверного кода Node.js подходит environment: 'node'. Также можно использовать опцию exclude, чтобы Vitest не запускал тесты в определенных каталогах, например, в тестах сквозного тестирования (e2e). Конфигурация coverage позволяет указать провайдера покрытия (например, provider: 'v8') и репортеры (например, reporter: ['text', 'json', 'html']) для генерации отчетов о покрытии кода.

Написание первого теста (пример простой функции JavaScript)

Vitest автоматически находит тестовые файлы, следующие соглашениям, таким как .test.js или .spec.js. Рекомендуется организовывать тесты в выделенном каталоге tests или рядом с кодом, который они тестируют. В тестовом файле обычно импортируются describe для группировки связанных тестов в набор, it (или test) для определения отдельных тестовых случаев и expect для выполнения утверждений. Для запуска тестов достаточно выполнить npm test (как настроено в package.json) или npx vitest непосредственно из терминала. Vitest затем найдет и выполнит тестовые файлы, предоставляя подробный вывод, включая время выполнения.

Пример кода: math.js

Пример теста: math.test.js

Тестирование компонентов React с Vitest

Настройка среды тестирования React

Тестирование компонентов React требует симулированной браузерной среды, поскольку сам Node.js не предоставляет необходимых API DOM. Для тестирования, ориентированного на пользователя, потребуется установить @testing-library/react, а в качестве среды DOM — jsdom (или happy-dom).

Затем необходимо настроить vitest.config.ts (или vite.config.ts, если он общий) для использования среды jsdom. Это указывает Vitest симулировать браузерную среду при запуске тестов.

Для расширенных утверждений настоятельно рекомендуется установить @testing-library/jest-dom и настроить его в файле настройки. Это предоставляет пользовательские сопоставители (например, toBeInTheDocument), которые делают утверждения более читаемыми и выразительными.

Затем создайте vitest.setup.js (как указано в setupFiles в вашей конфигурации):

Пример: Тестирование простого компонента React

При тестировании компонентов React цель часто состоит в том, чтобы симулировать взаимодействия пользователя и проверить вывод компонента в DOM. @testing-library/react предоставляет утилиты, такие как render и screen, для достижения этой цели, аналогично их использованию в Jest.

Пример React компонента: UserProfile.jsx

Пример кода: UserProfile.test.jsx

Моки в Vitest

Мокирование — это фундаментальный метод в модульном тестировании, позволяющий создавать «поддельные» версии внутренних или внешних сервисов, функций или модулей.

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

Мокирование функций с помощью vi.fn()

vi.fn() создает мок-функцию, которая позволяет отслеживать детали ее выполнения, такие как количество вызовов, аргументы, с которыми она была вызвана, и возвращаемые значения. История вызовов хранится в mock.calls и mock.results. Можно предоставить реализацию по умолчанию для мок-функции:

const myMockFn = vi.fn(() => 'default value');. Для последовательных вызовов mockImplementationOnce() может быть связан в цепочку для предоставления различных возвращаемых значений или реализаций для последующих вызовов. withImplementation() позволяет временно переопределять реализацию мока на время выполнения функции обратного вызова, возвращаясь к исходной после этого.

Пример кода: vi.fn() для вызова сервиса

Мокирование модулей и внешних сервисов с помощью vi.mock()

vi.mock() используется для замены целого модуля мокированной версией. Это особенно полезно для подделки сторонних библиотек, клиентов API или любых модулей, имеющих побочные эффекты или сложные зависимости. Синтаксис очень похож на jest.mock() в Jest. При мокировании можно предоставить фабричную функцию, которая определяет мокированные экспорты модуля. Vitest затем будет использовать эту фабрику для создания мокированной версии модуля.

Для всеобъемлющего мокирования API надежным подходом является интеграция такого инструмента, как Mock Service Worker (msw), который позволяет перехватывать сетевые запросы на уровне service worker и возвращать мокированные ответы.

Пример кода: Мокирование вызова API с помощью vi.mock()

Лучшие практики мокирования (очистка моков, изоляция)

Для обеспечения изоляции тестов и предотвращения утечки состояния между тестами всегда следует очищать или восстанавливать моки. mockClear() сбрасывает историю вызовов мок-функции, не влияя на ее реализацию. Это полезно для очистки между различными утверждениями в тестовом наборе.

Можно включить настройку clearMocks в конфигурации Vitest для автоматического вызова mockClear() перед каждым тестом, что упрощает очистку. При использовании Mock Service Worker (msw) необходимо вызывать server.resetHandlers() в хуке afterEach для обеспечения изоляции тестов. Следует помнить о подводных камнях мокирования: обычно невозможно мокировать вызовы методов, которые вызываются внутренне другими методами в том же файле, из-за того, как модули компилируются и импортируются.

Глобальные переменные и тестовые среды

Опция конфигурации globals: Явные импорты против глобальной области видимости

По умолчанию Vitest придерживается современного подхода, при котором он не загрязняет глобальную область видимости утилитами тестирования. Это означает, что функции, такие как describe, it и expect, должны быть явно импортированы из vitest в каждом тестовом файле. Этот выбор дизайна предпочтителен для многих, поскольку он способствует созданию более чистого кода и избеганию конфликтов глобального пространства имен.

Однако для разработчиков, переходящих с Jest, или тех, кто предпочитает более лаконичный синтаксис, Vitest предоставляет опцию globals: true в своей конфигурации. При включении этой опции утилиты тестирования становятся глобально доступными, отражая поведение Jest по умолчанию и потенциально делая тестовый код более читаемым для знакомых пользователей.

Мокирование глобальных объектов с помощью vi.stubGlobal()

В сценариях, когда необходимо мокировать глобальные переменные или специфичные для браузера API, которые не полностью реплицируются средами jsdom или node (например, IntersectionObserver, localStorage, window.location), Vitest предоставляет vi.stubGlobal(). Эта утилита позволяет определить мок-реализацию для глобальной переменной, эффективно заменяя ее исходное поведение в тестовой среде. Мокированное значение помещается непосредственно в объект globalThis.

Пример кода: Мокирование IntersectionObserver

Функция vi.stubGlobal() решает общую проблему в тестировании: работу с браузерными или сложными глобальными API, которые не полностью реплицируются jsdom или трудно контролируются. Предоставляя специальную утилиту для заглушки глобальных объектов, Vitest предлагает точный контроль над тестовой средой, позволяя разработчикам изолировать и тестировать код, который зависит от этих внешних браузерных API, без фактического взаимодействия с браузером.

Заключение

Vitest выделяется как мощная и эффективная среда тестирования, идеально соответствующая требованиям современной разработки на JavaScript и TypeScript. Ее основные преимущества заключаются в исключительной скорости, в значительной степени благодаря глубокой интеграции с горячей перезагрузкой модулей и сервером разработки Vite. Эта производительность напрямую приводит к более быстрым циклам обратной связи и значительному повышению производительности разработчиков.