Eksperymentowanie z programem uruchamiającym testy Node.js
Wydanie Node.js 18 przyniosło niespodziankę: test runner, aczkolwiek za eksperymentalną flagą.
Skoro Mocha i Jest wypełniają tę pustkę przez ostatnią dekadę, czy nadszedł czas, aby przejść na tego rodzimego biegacza testowego? Koniec z zależnościami deweloperskimi tylko po to, by uruchomić zestaw testów?
Brzmi intrygująco!
Pierwsza próba
Zacząłem od zastąpienia test
kroku w package.json
pliku następującym:
{
"scripts": {
"test": "node --test test/**/*.js"
}
}
Mnóstwo błędów w konsoli:
not ok * - <test path>
---
duration_ms: 1028.112875
failureType: 'subtestsFailed'
exitCode: 1
stdout: ''
stderr: |-
<test path>
^
ReferenceError: describe is not defined
at Object.<anonymous> (<test path>)
at Module._compile (node:internal/modules/cjs/loader:1159:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
at Module.load (node:internal/modules/cjs/loader:1037:32)
at Module._load (node:internal/modules/cjs/loader:878:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:23:47
Node.js v18.12.1
error: 'test failed'
code: 'ERR_TEST_FAILURE'
...
const { describe, it, beforeEach, afterEach } = require('node:test');
// package.json
{
"scripts": {
"test": "node --test -r test.setup.js test/**/*.js"
}
}
// test.setup.js
global.describe = require('node:test').describe;
global.it = require('node:test').it;
global.beforeEach = require('node:test').beforeEach;
global.afterEach = require('node:test').afterEach;
global.before = require('node:test').before;
global.after = require('node:test').after;
Unable to resolve path to module 'node:test'. eslint(import/no-unresolved)
// .eslintrc.yml
settings:
import/core-modules: [ node:test ]
Nadal mnóstwo błędów:
# Subtest: Errors thrown should be handled
not ok 3 - Errors thrown should be handled
---
duration_ms: 0.116958
failureType: 'hookFailed'
error: 'failed running beforeEach hook'
code: 'ERR_TEST_FAILURE'
stack: |-
checkWrappedMethod (node_modules/sinon/lib/sinon/util/core/wrap-method.js:67:21)
wrapMethod (node_modules/sinon/lib/sinon/util/core/wrap-method.js:132:13)
stub (node_modules/sinon/lib/sinon/stub.js:130:44)
node_modules/sinon/lib/sinon/util/core/walk-object.js:41:17
node_modules/sinon/lib/sinon/util/core/walk.js:28:22
Array.forEach (<anonymous>)
walkInternal (node_modules/sinon/lib/sinon/util/core/walk.js:20:5)
walk (node_modules/sinon/lib/sinon/util/core/walk.js:48:12)
walkObject (node_modules/sinon/lib/sinon/util/core/walk-object.js:26:5)
Function.stub (node_modules/sinon/lib/sinon/stub.js:103:16)
extendObjectWithWrappedMethods (node_modules/sinon/lib/sinon/util/core/wrap-method.js:167:34)
wrapMethod (node_modules/sinon/lib/sinon/util/core/wrap-method.js:155:5)
stub (node_modules/sinon/lib/sinon/stub.js:130:44)
node_modules/sinon/lib/sinon/util/core/walk-object.js:41:17
node_modules/sinon/lib/sinon/util/core/walk.js:28:22
Array.forEach (<anonymous>)
walkInternal (node_modules/sinon/lib/sinon/util/core/walk.js:20:5)
walk (node_modules/sinon/lib/sinon/util/core/walk.js:48:12)
walkObject (node_modules/sinon/lib/sinon/util/core/walk-object.js:26:5)
Function.stub (node_modules/sinon/lib/sinon/stub.js:103:16)
...
Druga próba
Tym razem korzystałem z v18.16.0
wersji LTS Node.js. Nigdy więcej tajemniczych błędów! To była ulga.
Uruchomił raport zasięgu. 45% pokrycia! co? Czekać. 60% naszych testów nawet nie zostało uruchomionych!
Przeprowadzenie badań doprowadziło mnie do tego problemu z GitHub - problem z analizą globalną dla osoby przeprowadzającej testy. Wydawało się, że jest to podstawowa funkcja, ale tak, brakuje! Więc nie możemy użyć test/**/*.js
wzorca glob.
Jeśli zostanie napotkany katalog o nazwie test
, program uruchamiający test przeszuka go rekurencyjnie w poszukiwaniu wszystkich plików .js
, .cjs
, i ..mjs
https://nodejs.org/docs/latest-v18.x/api/test.html#test-runner-execution-model
Na szczęście nasz katalog testowy rzeczywiście miał nazwę test
. Więc nigdy więcej globu.
// package.json
{
"scripts": {
"test": "node --test -r test.setup.js"
}
}
Trzecia próba?
Zestaw testowy wreszcie był zielony. Zasięg był również zielony.
Następnie migracja z sinon.assert
natywnej polegała node:assert
na zastąpieniu wszystkich wezwań do:
sinon.assert.pass(condition);
sinon.assert.match(expected, received);
const assert = require('node:assert/strict');
assert.ok(condition);
assert.equal(expected, received);
Zestaw testowy jest nadal zielony. Pokrycie jest również zielone. Ale wydajność spadła. Hmm, to jest coś, czego wcześniej nie sprawdzałem.
Uruchomienie zestawu testowego zajęło ponad 16 sekund, podczas gdy Mocha skończyła w mniej niż sekundę! Nawet Jest miał podobne czasy do Mocha.
Odniosłem wrażenie, że korzystając z natywnego narzędzia do uruchamiania testów, może on przewyższyć narzędzia innych firm, takie jak Mocha i Jest. Ale wydaje się, że tak nie jest, jak wynika z tego wydania GitHub .
Będziemy więc musieli poczekać do następnej pomniejszej wersji Node.js, aby spróbować po raz trzeci!
Końcowe przemyślenia
Możliwość uruchomienia zestawu testów bez instalowania zależności innej firmy z pewnością ma swoje zalety. Co więcej, obsługa składni podobnej do Mocha sprawia, że migracja jest łatwa.
Jest o wiele więcej funkcji, które chciałem wypróbować: makiety, migawki, pokrycie kodu, obserwatorzy i nie tylko.
Ale występ był rzeczywiście odłożony. Z niecierpliwością czekam na poprawkę!