Практические заметки: встроенный тест-запускатель Node против Jest и Vitest: один набор тестов, три инструмента
Пошаговое руководство по практическим заметкам: встроенный тест-запускач Node против Jest и Vitest: один набор инструментов, три варианта использования — контракты, проверки и слоты для дополнительного кода для команд, применяющих эту паттерн-архитектуру.
Используйте это как переработанную версию идей из статьи «Node’s Native Test Runner vs Jest vs Vitest: One Suite, Three Runners, Real Timings», ориентированную на операторов: четкие этапы, упорядоченные блоки кода и записи о восстановлении, сохраняющиеся при передаче задачи. Этап Обзора работает наилучшим образом, если рассматривать его как измеримую основу. Сначала зафиксируйте один идеальный пример выполнения, один случай сбоя и запись о возврате к предыдущему состоянию, прежде чем расширять объем работы. Рассматривайте этот этап как контракт между входными данными и проверенными результатами. Дайте названия результатам тестирования, определите критерии успеха и не соглашайтесь на молчаливое частичное выполнение задачи.
Три инструмента тестирования, честно говоря
Для трех участников соревнования необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отображение стоимости заранее помогает избежать неожиданных счетов при переходе от демо-среды к общедоступным средам. Размещайте состояние рядом с компонентом, ответственным за его изменение. Если всё хранить в глобальном хранилище, будет сложнее обнаруживать ошибки, связанные с временем выполнения.
1. node:test — скучный вариант, но он просто работает
Для тестирования с одним узлом на этапе необходимо заранее определить входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь граф. Храните состояние рядом с компонентом, ответственным за его изменение. Размещение всего в глобальном хранилище затрудняет обнаружение ошибок, связанных с временем выполнения.
// node-test/test/string-utils.test.js
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { slugify } from '../../src/string-utils.js';
describe('slugify', () => {
it('converts a basic sentence', () => {
assert.equal(slugify('Hello World'), 'hello-world');
});
it('strips diacritics', () => {
assert.equal(slugify('Café résumé'), 'cafe-resume');
});
it('throws TypeError on non-string input', () => {
assert.throws(() => slugify(123), TypeError);
});
});
# Run it, no install step
node --test node-test/test/*.test.js
# Watch mode
node --test --watch node-test/test/*.test.js
# Coverage (still experimental, but the numbers are real V8 counts)
node --test --experimental-test-coverage \
--test-coverage-include='src/**/*.js' \
node-test/test/*.test.js
2. Jest — стандартный инструмент, который вы уже используете
Для стандартной фазы 2 Jest необходимо определить входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Необходимо одновременно задокументировать успешный и восстановительный сценарии работы. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не этапом последующей доработки. Состояние следует хранить вместе с компонентом, ответственным за его изменение. Хранение всего в глобальном хранилище затрудняет выявление проблем с временем выполнения. Для стандартной фазы 2 Jest необходимо определить входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рассматривайте эту фазу как контракт между входными данными и проверенными выходными результатами. Дайте названия элементам, определите критерии успеха и не допускайте безответственного частичного завершения работы.
// jest/test/string-utils.test.js
import { slugify } from '../../src/string-utils.js';
describe('slugify', () => {
it('converts a basic sentence', () => {
expect(slugify('Hello World')).toBe('hello-world');
});
it('strips diacritics', () => {
expect(slugify('Café résumé')).toBe('cafe-resume');
});
it('throws TypeError on non-string input', () => {
expect(() => slugify(123)).toThrow(TypeError);
});
});
// jest/jest.config.js, minimal. Run it with NODE_OPTIONS=--experimental-vm-modules
export default {
rootDir: '.',
testMatch: ['<rootDir>/test/**/*.test.js'],
testEnvironment: 'node',
verbose: true,
};
# Run (the flag is required for native ESM)
NODE_OPTIONS=--experimental-vm-modules npx jest --config jest/jest.config.js
# Watch
NODE_OPTIONS=--experimental-vm-modules npx jest --config jest/jest.config.js --watch
3. Vitest — новый стандарт с одним недостатком
При работе с новым этапом 3 Vitest сначала запишите условия контракта: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой чек-лист поможет избежать ошибок при последующих изменениях кода. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные расходы при переходе с демо-среды в общедоступные среды. Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену вычисляемых значений во время отрисовки.
// vitest/test/string-utils.test.js
import { describe, it, expect } from 'vitest';
import { slugify } from '../../src/string-utils.js';
describe('slugify', () => {
it('converts a basic sentence', () => {
expect(slugify('Hello World')).toBe('hello-world');
});
it('strips diacritics', () => {
expect(slugify('Café résumé')).toBe('cafe-resume');
});
it('throws TypeError on non-string input', () => {
expect(() => slugify(123)).toThrow(TypeError);
});
});
// vitest/vitest.config.mjs
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
include: ['test/**/*.test.js'],
environment: 'node',
coverage: { provider: 'v8', include: ['../src/**/*.js'] },
},
});
# Run
cd vitest && npx vitest run
# Watch (this is the killer feature)
cd vitest && npx vitest
# Coverage
cd vitest && npx vitest run --coverage
Методология, чтобы вы могли назвать её чепухой
При работе над методологией планирования сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену вычисляемых значений во время отрисовки.
# Reproduce on your own machine
git clone https://github.com/manisuec/techinsights-tutorials
cd techinsights-tutorials/nodejs-test-runner
npm install
bash shared/bench.sh 5 # cold runs
WARM=1 bash shared/bench.sh 5 # warm runs
Реальные числа
При работе над этапом «Реальные числа» сначала запишите контракт: необходимые входные данные, сигнал о успехе и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Документируйте как успешный путь, так и путь восстановления одновременно. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не элементами последующей доработки. Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену вычисляемых значений во время отрисовки. При работе над этапом «Реальные числа» сначала запишите контракт: необходимые входные данные, сигнал о успехе и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Рассматривайте этот этап как контракт между входными данными и проверенными выходными данными. Дайте названия результатам работы, определите критерии успеха и не допускайте безусловного частичного завершения задачи.
=== node:test (Node v24.14.0) [cold] ===
run 1: 91 ms
run 2: 93 ms
run 3: 89 ms
run 4: 90 ms
run 5: 90 ms
median: 90 ms
=== Jest (30.4.1) [cold] ===
run 1: 817 ms
run 2: 689 ms
run 3: 718 ms
run 4: 711 ms
run 5: 685 ms
median: 711 ms
=== Vitest (4.1.11) [cold] ===
run 1: 548 ms
run 2: 648 ms
run 3: 534 ms
run 4: 531 ms
run 5: 535 ms
median: 535 ms
Матрица функций, 2026 год, последняя проверка
Матрица функций 2026 на последней стадии работает наилучшим образом, когда рассматривается как измеримая поверхность. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Записывайте временные показатели, а также стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счёты при переходе от демо-среды к общедоступным средам. Старайтесь сохранять низкие затраты на обработку данных и откладывайте дорогостоящие вычисления с использованием мемоизации только после их измерения; преждевременное использование мемоизации может скрыть ошибки, связанные с устаревшими данными.
Когда выбирать тот или иной подход
Определение наиболее подходящей стадии работы лучше всего рассматривать как измеримую характеристику. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Сделайте процесс отрисовки простым и откладывайте затратные вычисления с использованием мемоизации только после их измерения. Преждевременное применение мемоизации может скрыть ошибки, связанные с устаревшими данными.
Миграция с Jest на Vitest за 30 минут
Переход с Jest на стадию тестирования в стадии разработки работает лучше всего, когда его рассматривают как объект с измеримыми показателями. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Документируйте как успешный, так и восстановительный сценарии работы. Повторные попытки, проверки со стороны человека и обработка неработоспособных сообщений являются частью продукта, а не этапом последующей доработки. Сохраняйте низкую стоимость процесса отрисовки и откладывайте дорогостоящие операции на этап мемоизации только после проведения измерений. Преждевременная мемоизация может скрыть ошибки, связанные с устаревшими данными. Переход с Jest на стадию тестирования в стадии разработки работает лучше всего, когда его рассматривают как объект с измеримыми показателями. Соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объема работ. Рассматривайте эту стадию как контракт между входными данными и проверенными выходными результатами. Дайте названия всем элементам, определите критерии успеха и не допускайте молчаливого частичного завершения работы.
# 1. Install
npm install -D vitest
# 2. Add a config (or piggyback on vite.config.ts if you have one)
# vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true, // makes describe/it/expect global
environment: 'jsdom', // or 'node' for backend
setupFiles: ['./tests/setup.ts'],
},
});
# 3. Swap imports, find/replace in your editor
# jest.mock → vi.mock
# jest.fn → vi.fn
# jest.spyOn → vi.spyOn
# require('@jest/globals') → require('vitest')
# jest.useFakeTimers() → vi.useFakeTimers()
# 4. Swap npm scripts
# "test": "jest" → "test": "vitest run"
# "test:watch": "jest --watch" → "test:watch": "vitest"
# 5. If you used babel-jest, delete it and babel.config.js
# 6. Run. Fix the 3-5 things that fail. Drink coffee.
Чего делать не следует
Что касается элементов, которые нельзя запускать в прямом режиме, необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отображение затрат с самого начала помогает избежать неожиданных счетов при переходе от демо-среды к общедоступным средам. Состояние следует хранить в том же компоненте, который отвечает за его изменение. Хранение всего в глобальном хранилище затрудняет выявление ошибок, связанных с временем выполнения.
Вердикт
На этапе принятия решения необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Конфигурацию следует хранить отдельно от кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь кодовый граф. Состояние следует хранить вместе с компонентом, ответственным за его изменение. Хранение всего в глобальном хранилище затрудняет выявление ошибок, связанных с временем выполнения.
Приложение: как интерпретировать цифры в этой статье
В приложении описано, как читать информацию о этапе, определять входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Необходимо задокументировать как успешный, так и восстановительный пути выполнения. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не последующими улучшениями. Состояние должно храниться вместе с компонентом, ответственным за его изменение. Хранение всего в глобальном хранилище затрудняет выявление проблем с временем выполнения. В приложении описано, как читать информацию о этапе, определять входные данные, ответственного за шаг и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия элементам, определите критерии успеха и не допускайте безответственного частичного завершения работы.
Чек-лист операционной работы
На этапе составления чек-листа операционной работы сначала запишите условия контракта: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист помогает сохранять честность при последующих изменениях кода.
Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Если какой-то шаг не сработает, причина должна быть связана с конкретной функцией, а не с запутанной цепочкой операций.
Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену значений, получаемых в процессе отрисовки.
Фиксируйте версии зависимостей и записывайте хэш изображения, использованного для демонстрации. Воспроизводимость важнее коллективных знаний.
Рассматривайте этот этап как контракт между входными данными и проверенными выходными результатами. Дайте названия элементам кода, определите критерии успеха и не допускайте молчаливого частичного выполнения задачи.
Рассматривайте эффекты как синхронизацию с внешним миром, а не как замену вычисляемых значений во время отрисовки.
Перед продвижением стека заморозьте версии, сделайте копию «золотого» отчета для критической цепочки и уточните шаги возврата к предыдущему состоянию. В совместных средах необходимы ограничения на частоту запросов, проверки принадлежности и четко определенный ответственный за обновление секретов. Лучше выбирать простую надежность, чем умные одноразовые демонстрации.
Примечание для билда b78b143fb7a9: не храните ключи поставщика в репозитории, установите лимит токенов на сессию и сохраняйте отчеты рядом с фикстурами оценки, чтобы последующие замены моделей оставались сопоставимыми.