Головна / Статті / Практичні нотатки: Вбудований тест-запускач Node проти Jest та Vitest: один набір, три варіанти

Практичні нотатки: Вбудований тест-запускач Node проти Jest та Vitest: один набір, три варіанти

Покроковий огляд практичних нотаток: вбудований тест-запускач Node проти Jest та Vitest: один набір інструментів, три варіанти — контракти, перевірки та слоти для коду для команд, які використовують цю схему.

2126 слів

Використовуйте цей документ як оновлену версію ідей з статті „Node’s Native Test Runner vs Jest vs Vitest: One Suite, Three Runners, Real Timings“, призначену для операторів: чіткі етапи, впорядковані блоки коду та примітки щодо відновлення, які зберігаються під час передачі обов’язків. Етап Огляду найкраще функціонує, якщо його розглядати як вимірювану основу. Запишіть один ідеальний запис виконання, один випадок збою та примітки щодо скасування змін перед розширенням обсягу роботи. Розглядайте цей етап як угоду між вхідними даними та перевіреними результатами. Позначте всі елементи, визначте критерії успіху та не допускайте мовчазного часткового виконання завдань.

Три засоби виконання тестів, чесно кажучи

Для цих трьох етапів роботи необхідно чесно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Відображення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-середовища до спільних. Розміщуйте стан разом із компонентом, який керує змінами. Перенесення всього до глобального сховища ускладнює виявлення проблем із часом виконання.

1. node:test — нудний варіант, який просто працює

Для тестування з 1 вузлом на етапі попередньо необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функціоналу мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Стан слід розміщувати разом із компонентом, який керує змінами. Розміщення всього в глобальному сховищі ускладнює виявлення проблем з таймінгом.

// 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 – новий стандарт із одним компромісом

Під час роботи з новою стадією 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: не включайте ключі постачальника до репозиторію, встановіть ліміт токенів на сеанс та зберігайте записи поруч із фікстурами eval, щоб подальша заміна моделей залишалася порівнянною.