У Vitest есть два инструмента, которые выходят за рамки обычной проверки поведения: бенчмарки и in-source тесты. Оба нишевые, оба легко применить не к месту, и оба полезны, когда понятна их узкая роль. Бенчмарк отвечает на вопрос 'насколько это быстро', а не 'правильно ли это'; in-source тест позволяет держать проверку прямо в исходнике. Ни то ни другое не заменяет обычные тесты - это дополнение для конкретных случаев.
Бенчмарк пишут функцией bench вместо test. Под капотом Vitest использует tinybench и прогоняет функцию многократно, собирая статистику: hz - число операций в секунду, mean - среднее время, p99 - время, в которое укладываются 99% прогонов, rme - относительная погрешность измерения. Запускают их отдельной командой vitest bench, а не обычным прогоном, потому что цель у них иная - измерение, а не проверка.
Несколько реализаций одного алгоритма удобно сравнивать, сгруппировав их в обычном describe: внутри него каждый bench меряется в одних условиях, и Vitest показывает их рядом с отметкой самого быстрого. Так сравнивают, скажем, две версии парсера или две стратегии дедупликации на реальных данных. Важно держать в голове, что механизм помечен экспериментальным: его API может измениться между версиями, и завязывать на него CI-гейты преждевременно.
Ключевое ограничение бенчмарка - он не критерий правильности. Быстрая реализация, дающая неверный результат, бесполезна, поэтому bench не отменяет обычные test на то же поведение. Разумный порядок такой: сначала тестами доказать, что все сравниваемые версии корректны, и только потом бенчмарком выбирать из корректных самую быструю. Мерить производительность заведомо сломанного кода - потерянное время.
Второй инструмент - in-source тесты, проверки прямо в файле с кодом. Их пишут внутри блока if (import.meta.vitest), куда импортируют test и expect из того же import.meta.vitest. При обычном исполнении модуля import.meta.vitest равен undefined, поэтому блок не выполняется; Vitest же под опцией includeSource видит его и запускает как тесты, находящиеся в одном файле с проверяемой функцией.
Чтобы этот блок не попал в продакшен-бандл, сборщик вырезают его на этапе билда: в конфиге Vite задают define, подставляющий import.meta.vitest как undefined, и тогда мёртвая ветка удаляется тришейкингом. Это устраняет главный страх перед приёмом - что тестовый код и импорты Vitest утекут в поставку. При правильной настройке пользователь получает чистый модуль без единой тестовой строки.
Уместность у in-source узкая. Он хорош для маленьких чистых утилит, где держать проверку рядом с реализацией нагляднее, чем заводить отдельный файл: крошечная функция форматирования, парсер одного формата, чистое преобразование. Для полноценных модулей с многими сценариями по-прежнему лучше отдельные тест-файлы - там in-source только замусорит исходник. Это инструмент для мелкого и очевидного, а не общий стиль.
Типичный провал с бенчмарком - принимать по нему решения без обычных тестов и оптимизировать код, который на самом деле неверен. Второй - забыть про define при in-source и утащить тестовый блок в бандл поставки. И общий промах - применять оба приёма шире их ниши: бенчмаркать то, что не в горячем пути, и пихать in-source в модули, которым куда честнее обычный тест-файл рядом.
import { bench, describe } from 'vitest'
describe('дедупликация', () => {
bench('через Set', () => { dedupeSet(data) })
bench('через reduce', () => { dedupeReduce(data) })
})
// vitest bench -> hz, mean, p99, rme; самый быстрый помеченexport function slugify(s: string) {
return s.trim().toLowerCase().replace(/\s+/g, '-')
}
if (import.meta.vitest) {
const { test, expect } = import.meta.vitest
test('slugify', () => expect(slugify(' Hello World ')).toBe('hello-world'))
}
// config: test.includeSource + define: { 'import.meta.vitest': 'undefined' }