Strona główna / Artykuły / Wskazówki praktyczne: Natywny narzędzie testowe Node vs Jest vs Vitest: jedna suita, trzy opcje

Wskazówki praktyczne: Natywny narzędzie testowe Node vs Jest vs Vitest: jedna suita, trzy opcje

Krok po kroku praktyczne wskazówki: Natywny narzędzie testowe Node’a kontra Jest i Vitest – jedna platforma, trzy opcje: kontrakty, sprawdzania oraz miejsca na kod do wklejenia dla zespołów stosujących ten wzorzec.

2126 słów

Niech to służy jako przebudowa idei z artykułu „Node’s Native Test Runner vs Jest vs Vitest: One Suite, Three Runners, Real Timings” przeznaczona dla operatorów: wyraźne etapy, uporządkowane sekcje kodu oraz notatki dotyczące napraw, które przetrwają przeniesienie obowiązków. Etap Przeglądu działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię do analizy. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy artefaktom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadań.

Trzy narzędzia testowe, szczerze mówiąc

Aby trzej uczestnicy mogli uczciwie pracować, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie wykonać dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Stan powinien być umieszczany obok komponentu, który odpowiada za jego modyfikację. Umieszczanie wszystkiego w globalnym magazynie utrudnia wykrycie błędów związanych z czasem wykonywania.

1. node:test – nudny wybór, który po prostu działa

W przypadku testu z 1 węzłem na etapie przygotowawczym należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury aplikacji. Stan powinien być przechowywany razem z komponentem, który odpowiada za jego modyfikację. Umieszczanie wszystkiego w globalnym magazynie utrudnia wykrycie błędów związanych z czasem wykonywania operacji.

// 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 – standard, który dotychczas stosowaliście

Dla 2 Jest, który jest standardowym etapem, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg procesu, jak i ścieżkę naprawczą. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Stan powinien być przechowywany razem z komponentem, który odpowiada za jego modyfikację. Umieszczanie wszystkiego w globalnym magazynie utrudnia wykrycie błędów związanych z czasem realizacji. Dla 2 Jest, który jest standardowym etapem, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

// 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 – nowy standard z jedną wadą

Gdy przechodzisz do nowego etapu 3 Vitest, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisz czas wykonywania oraz koszt tokena lub zapytania obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Traktuj efekty jako synchronizację z otaczającym światem, a nie jako zamiennik wartości wyliczanych podczas renderowania.

// 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

Metodyka, żebyś mógł nazwać to bzdurą

Gdy przechodzisz przez metodologię projektowania, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Traktuj efekty jako synchronizację z otaczającym światem, a nie jako zamiennik wartości wyliczanych podczas renderowania.

# 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

Prawdziwe liczby

Gdy przechodzisz przez etap „Prawdziwe liczby”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponowne, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Traktuj efekty jako synchronizację z otaczającym światem, a nie jako zamiennik wartości wyliczanych podczas renderowania. Gdy przechodzisz przez etap „Prawdziwe liczby”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadania.

=== 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

Matryca funkcji, 2026, ostatnia data sprawdzenia

Matryca funkcji z 2026 roku w ostatniej fazie działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię. Zapisz jeden idealny przekaz, jeden przypadek awarii oraz notatkę o cofnięciu zmian przed rozszerzeniem zakresu. Zapisz czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych. Utrzymuj koszty renderowania na niskim poziomie i odkładaj drogie operacje wywodzenia na później, dopiero po ich zmierzeniu. Przedwczesne stosowanie mechanizmów memoizacji może ukrywać błędy związane ze starymi danymi.

Kiedy wybrać który

Najlepszy moment na wybór odpowiedniego etapu to wtedy, gdy traktuje się go jako mierzalną powierzchnię. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Trzymaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny haseł oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury. Utrzymuj koszty renderowania na niskim poziomie i odkładaj drogie operacje obliczeniowe na później, dopiero po ich zmierzeniu. Przedwczesne stosowanie mechanizmów memoizacji może ukrywać błędy związane ze starymi wartościami.

Migracja z Jest na Vitest w 30 minut

Migracja z Jest do stage działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię do analizy. Zapisz jeden „złoty” zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Zdokumentuj zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później w celu udoskonalenia. Utrzymuj koszty przetwarzania na niskim poziomie i odkładaj drogie operacje wywodzenia na później, tylko po dokonaniu pomiarów. Przedwczesne stosowanie mechanizmów memoizacji może ukrywać błędy związane ze starymi danymi. Migracja z Jest do stage działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię do analizy. Zapisz jeden „złoty” zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

# 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.

Czego nie powinieneś robić

Aby określić to, czego nie należy wykonywać na scenie, zdefiniuj dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Umieszczaj stan w tym samym komponencie, który odpowiada za jego modyfikację. Umieszczanie wszystkiego w globalnym magazynie utrudnia wykrycie błędów związanych z czasem wykonywania.

Werdykt

W fazie weryfikacji wyników należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Stan powinien być przechowywany razem z komponentem odpowiedzialnym za jego zmianę. Umieszczanie wszystkiego w globalnym magazynie utrudnia wykrycie błędów związanych z czasem wykonywania operacji.

Dodatek: jak odczytywać liczby w tym artykule

W Dodatku należy określić, jak odczytywać etap, jakie są dane wejściowe, kto jest odpowiedzialny za dany krok oraz jakie są kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg procesu, jak i ścieżkę naprawczą. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Stan powinien być przechowywany razem z komponentem, który odpowiada za jego zmianę. Umieszczanie wszystkiego w globalnym magazynie utrudnia wykrycie błędów związanych z czasem realizacji. W Dodatku należy określić, jak odczytywać etap, jakie są dane wejściowe, kto jest odpowiedzialny za dany krok oraz jakie są kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

List kontrolny operacyjny

Podczas przechodzenia przez etap listy kontrolnej operacyjnej najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego awarii. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie.

Wolimy małe, testowalne jednostki od rozbudowanych skryptów. Gdy jakiś krok zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany proces.

Rozpatruj efekty jako synchronizację z otaczającym światem, a nie jako zamiennik wartości wyliczanych podczas renderowania.

Zdefiniuj wersje zależności i zapisz hash obrazu użytego do demonstracji. Reprodukowalność jest ważniejsza od wiedzy przekazywanej ustnie.

Rozpatruj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy artefaktom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania.

Traktuj efekty jako synchronizację z otaczającym światem, a nie jako zamiennik wartości wyliczanych podczas renderowania.

Zanim przeprowadzisz promocję stosu, zamroź wersje, utwórz „złoty zapis” dla kluczowej ścieżki oraz potwierdź kroki odwracania zmian. Środowiska współdzielone wymagają ograniczeń szybkości, weryfikacji użytkowników oraz wyraźnego właściciela odpowiedzialnego za rotację haseł. Wolimy nudną niezawodność od sprytnych, jednorazowych demonstracji.

Uwaga dotycząca b78b143fb7a9: unikaj przechowywania kluczy dostawcy w repozytorium, ustaw ograniczenie liczby tokenów na sesję oraz przechowuj zapisy obok narzędzi eval, aby późniejsze zmiany modeli pozostały porównywalne.

Literatura pokrewna