Esecutore di test
[Cronologia]
Versione | Modifiche |
---|---|
v20.0.0 | L'esecutore di test è ora stabile. |
v18.0.0, v16.17.0 | Aggiunto in: v18.0.0, v16.17.0 |
[Stabile: 2 - Stabile]
Stabile: 2 Stabilità: 2 - Stabile
Codice sorgente: lib/test.js
Il modulo node:test
facilita la creazione di test JavaScript. Per accedervi:
import test from 'node:test'
const test = require('node:test')
Questo modulo è disponibile solo con lo schema node:
.
I test creati tramite il modulo test
consistono in una singola funzione che viene elaborata in uno dei tre modi seguenti:
Il seguente esempio illustra come vengono scritti i test usando il modulo test
.
test('test di passaggio sincrono', t => {
// Questo test passa perché non genera un'eccezione.
assert.strictEqual(1, 1)
})
test('test di fallimento sincrono', t => {
// Questo test fallisce perché genera un'eccezione.
assert.strictEqual(1, 2)
})
test('test di passaggio asincrono', async t => {
// Questo test passa perché la Promise restituita dalla funzione async
// è risolta e non rifiutata.
assert.strictEqual(1, 1)
})
test('test di fallimento asincrono', async t => {
// Questo test fallisce perché la Promise restituita dalla funzione async
// è rifiutata.
assert.strictEqual(1, 2)
})
test('test di fallimento usando Promise', t => {
// Le Promise possono essere usate direttamente anche.
return new Promise((resolve, reject) => {
setImmediate(() => {
reject(new Error('questo causerà il fallimento del test'))
})
})
})
test('test di passaggio con callback', (t, done) => {
// done() è la funzione di callback. Quando setImmediate() viene eseguito, invoca
// done() senza argomenti.
setImmediate(done)
})
test('test di fallimento con callback', (t, done) => {
// Quando setImmediate() viene eseguito, done() viene invocato con un oggetto Error e
// il test fallisce.
setImmediate(() => {
done(new Error('fallimento della callback'))
})
})
Se qualche test fallisce, il codice di uscita del processo viene impostato su 1
.
Subtest
Il metodo test()
del contesto di test consente di creare subtest. Permette di strutturare i test in modo gerarchico, creando test annidati all'interno di un test più ampio. Questo metodo si comporta in modo identico alla funzione test()
di livello superiore. L'esempio seguente mostra la creazione di un test di livello superiore con due subtest.
test('test di livello superiore', async t => {
await t.test('subtest 1', t => {
assert.strictEqual(1, 1)
})
await t.test('subtest 2', t => {
assert.strictEqual(2, 2)
})
})
In questo esempio, await
viene utilizzato per garantire che entrambi i subtest siano completati. Ciò è necessario perché i test non attendono il completamento dei loro subtest, a differenza dei test creati all'interno delle suite. Qualsiasi subtest ancora in sospeso al termine del genitore viene annullato e considerato un errore. Qualsiasi errore di subtest causa il fallimento del test padre.
Salto dei test
I singoli test possono essere saltati passando l'opzione skip
al test, o chiamando il metodo skip()
del contesto di test come mostrato nell'esempio seguente.
// Viene utilizzata l'opzione skip, ma non viene fornito alcun messaggio.
test('opzione skip', { skip: true }, t => {
// Questo codice non viene mai eseguito.
})
// Viene utilizzata l'opzione skip e viene fornito un messaggio.
test('opzione skip con messaggio', { skip: 'questo viene saltato' }, t => {
// Questo codice non viene mai eseguito.
})
test('metodo skip()', t => {
// Assicurarsi di restituire anche qui se il test contiene logica aggiuntiva.
t.skip()
})
test('metodo skip() con messaggio', t => {
// Assicurarsi di restituire anche qui se il test contiene logica aggiuntiva.
t.skip('questo viene saltato')
})
Test TODO
I singoli test possono essere contrassegnati come instabili o incompleti passando l'opzione todo
al test, o chiamando il metodo todo()
del contesto di test, come mostrato nell'esempio seguente. Questi test rappresentano un'implementazione in sospeso o un bug che deve essere corretto. I test TODO vengono eseguiti, ma non sono considerati errori di test e quindi non influenzano il codice di uscita del processo. Se un test è contrassegnato sia come TODO che come saltato, l'opzione TODO viene ignorata.
// Viene utilizzata l'opzione todo, ma non viene fornito alcun messaggio.
test('opzione todo', { todo: true }, t => {
// Questo codice viene eseguito, ma non considerato un errore.
throw new Error('questo non fa fallire il test')
})
// Viene utilizzata l'opzione todo e viene fornito un messaggio.
test('opzione todo con messaggio', { todo: 'questo è un test todo' }, t => {
// Questo codice viene eseguito.
})
test('metodo todo()', t => {
t.todo()
})
test('metodo todo() con messaggio', t => {
t.todo('questo è un test todo e non è considerato un errore')
throw new Error('questo non fa fallire il test')
})
Alias di describe()
e it()
È possibile scrivere suite e test anche utilizzando le funzioni describe()
e it()
. describe()
è un alias di suite()
, e it()
è un alias di test()
.
describe('Una cosa', () => {
it('dovrebbe funzionare', () => {
assert.strictEqual(1, 1)
})
it('dovrebbe andare bene', () => {
assert.strictEqual(2, 2)
})
describe('una cosa nidificata', () => {
it('dovrebbe funzionare', () => {
assert.strictEqual(3, 3)
})
})
})
describe()
e it()
sono importati dal modulo node:test
.
import { describe, it } from 'node:test'
const { describe, it } = require('node:test')
Test only
Se Node.js viene avviato con l'opzione della riga di comando --test-only
, o se l'isolamento dei test è disabilitato, è possibile saltare tutti i test eccetto un sottoinsieme selezionato passando l'opzione only
ai test che devono essere eseguiti. Quando è impostato un test con l'opzione only
, vengono eseguiti anche tutti i sottotest. Se una suite ha l'opzione only
impostata, vengono eseguiti tutti i test all'interno della suite, a meno che non abbia discendenti con l'opzione only
impostata, nel qual caso vengono eseguiti solo quei test.
Quando si utilizzano sottotest all'interno di un test()
/it()
, è necessario contrassegnare tutti i test antenati con l'opzione only
per eseguire solo un sottoinsieme selezionato di test.
Il metodo runOnly()
del contesto del test può essere utilizzato per implementare lo stesso comportamento a livello di sottotest. I test che non vengono eseguiti vengono omessi dall'output del runner dei test.
// Si presume che Node.js venga eseguito con l'opzione della riga di comando --test-only.
// L'opzione 'only' della suite è impostata, quindi questi test vengono eseguiti.
test('questo test viene eseguito', { only: true }, async t => {
// All'interno di questo test, tutti i sottotest vengono eseguiti per impostazione predefinita.
await t.test('sottotest in esecuzione')
// Il contesto del test può essere aggiornato per eseguire i sottotest con l'opzione 'only'.
t.runOnly(true)
await t.test('questo sottotest ora viene saltato')
await t.test('questo sottotest viene eseguito', { only: true })
// Ripristinare il contesto per eseguire tutti i test.
t.runOnly(false)
await t.test('questo sottotest ora viene eseguito')
// Esplicitamente non eseguire questi test.
await t.test('sottotest saltato 3', { only: false })
await t.test('sottotest saltato 4', { skip: true })
})
// L'opzione 'only' non è impostata, quindi questo test viene saltato.
test('questo test non viene eseguito', () => {
// Questo codice non viene eseguito.
throw new Error('errore')
})
describe('una suite', () => {
// L'opzione 'only' è impostata, quindi questo test viene eseguito.
it('questo test viene eseguito', { only: true }, () => {
// Questo codice viene eseguito.
})
it('questo test non viene eseguito', () => {
// Questo codice non viene eseguito.
throw new Error('errore')
})
})
describe.only('una suite', () => {
// L'opzione 'only' è impostata, quindi questo test viene eseguito.
it('questo test viene eseguito', () => {
// Questo codice viene eseguito.
})
it('questo test viene eseguito', () => {
// Questo codice viene eseguito.
})
})
Filtraggio dei test per nome
L'opzione della riga di comando --test-name-pattern
può essere utilizzata per eseguire solo i test il cui nome corrisponde al pattern fornito, e l'opzione --test-skip-pattern
può essere utilizzata per saltare i test il cui nome corrisponde al pattern fornito. I pattern dei nomi dei test sono interpretati come espressioni regolari JavaScript. Le opzioni --test-name-pattern
e --test-skip-pattern
possono essere specificate più volte per eseguire test nidificati. Per ogni test eseguito, vengono eseguiti anche gli hook di test corrispondenti, come beforeEach()
. I test che non vengono eseguiti vengono omessi dall'output del test runner.
Dato il seguente file di test, avviare Node.js con l'opzione --test-name-pattern="test [1-3]"
farebbe sì che il test runner eseguisse test 1
, test 2
e test 3
. Se test 1
non corrispondesse al pattern del nome del test, i suoi sottotest non verrebbero eseguiti, nonostante corrispondano al pattern. Lo stesso insieme di test potrebbe anche essere eseguito passando --test-name-pattern
più volte (es. --test-name-pattern="test 1"
, --test-name-pattern="test 2"
, ecc.).
test('test 1', async t => {
await t.test('test 2')
await t.test('test 3')
})
test('Test 4', async t => {
await t.test('Test 5')
await t.test('test 6')
})
I pattern dei nomi dei test possono anche essere specificati usando letterali di espressioni regolari. Questo permette l'utilizzo di flag di espressioni regolari. Nell'esempio precedente, avviare Node.js con --test-name-pattern="/test [4-5]/i"
(o --test-skip-pattern="/test [4-5]/i"
) corrisponderebbe a Test 4
e Test 5
perché il pattern non fa distinzione tra maiuscole e minuscole.
Per far corrispondere un singolo test con un pattern, è possibile anteporgli tutti i nomi dei suoi test antenati separati da uno spazio, per assicurarsi che sia unico. Ad esempio, dato il seguente file di test:
describe('test 1', t => {
it('some test')
})
describe('test 2', t => {
it('some test')
})
Avviare Node.js con --test-name-pattern="test 1 some test"
corrisponderebbe solo a some test
in test 1
.
I pattern dei nomi dei test non modificano l'insieme dei file che il test runner esegue.
Se vengono fornite sia --test-name-pattern
che --test-skip-pattern
, i test devono soddisfare entrambi i requisiti per essere eseguiti.
Attività asincrone estranee
Una volta che una funzione di test termina l'esecuzione, i risultati vengono riportati il più rapidamente possibile mantenendo l'ordine dei test. Tuttavia, è possibile che la funzione di test generi attività asincrone che sopravvivono al test stesso. Il runner dei test gestisce questo tipo di attività, ma non ritarda la segnalazione dei risultati dei test per accoglierla.
Nell'esempio seguente, un test si completa con due operazioni setImmediate()
ancora in sospeso. La prima setImmediate()
tenta di creare un nuovo sottotest. Poiché il test padre ha già terminato e prodotto i suoi risultati, il nuovo sottotest viene immediatamente contrassegnato come fallito e segnalato successivamente a <TestsStream>.
La seconda setImmediate()
crea un evento uncaughtException
. Gli eventi uncaughtException
e unhandledRejection
originati da un test completato sono contrassegnati come falliti dal modulo test
e segnalati come avvisi diagnostici di livello superiore da <TestsStream>.
test('un test che crea attività asincrone', t => {
setImmediate(() => {
t.test('sottotest creato troppo tardi', t => {
throw new Error('error1')
})
})
setImmediate(() => {
throw new Error('error2')
})
// Il test termina dopo questa riga.
})
Modalità di osservazione
Aggiunto in: v19.2.0, v18.13.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1 - Sperimentale
Il runner dei test Node.js supporta l'esecuzione in modalità di osservazione passando il flag --watch
:
node --test --watch
In modalità di osservazione, il runner dei test controllerà le modifiche ai file di test e alle loro dipendenze. Quando viene rilevata una modifica, il runner dei test riesegue i test interessati dalla modifica. Il runner dei test continuerà a funzionare fino alla terminazione del processo.
Esecuzione dei test dalla riga di comando
Il runner dei test Node.js può essere invocato dalla riga di comando passando il flag --test
:
node --test
Per impostazione predefinita, Node.js eseguirà tutti i file corrispondenti a questi pattern:
**/*.test.{cjs,mjs,js}
**/*-test.{cjs,mjs,js}
**/*_test.{cjs,mjs,js}
**/test-*.{cjs,mjs,js}
**/test.{cjs,mjs,js}
**/test/**/*.{cjs,mjs,js}
Quando viene fornito --experimental-strip-types
, vengono corrisponduti i seguenti pattern aggiuntivi:
**/*.test.{cts,mts,ts}
**/*-test.{cts,mts,ts}
**/*_test.{cts,mts,ts}
**/test-*.{cts,mts,ts}
**/test.{cts,mts,ts}
**/test/**/*.{cts,mts,ts}
In alternativa, uno o più pattern glob possono essere forniti come argomento(i) finale(i) del comando Node.js, come mostrato di seguito. I pattern glob seguono il comportamento di glob(7)
. I pattern glob devono essere racchiusi tra virgolette doppie sulla riga di comando per evitare l'espansione della shell, il che può ridurre la portabilità tra i sistemi.
node --test "**/*.test.js" "**/*.spec.js"
I file corrispondenti vengono eseguiti come file di test. Ulteriori informazioni sull'esecuzione del file di test sono disponibili nella sezione modello di esecuzione del runner dei test.
Modello di esecuzione del test runner
Quando è abilitato l'isolamento dei test a livello di processo, ogni file di test corrispondente viene eseguito in un processo figlio separato. Il numero massimo di processi figlio in esecuzione in qualsiasi momento è controllato dal flag --test-concurrency
. Se il processo figlio termina con un codice di uscita 0, il test è considerato superato. Altrimenti, il test è considerato un errore. I file di test devono essere eseguibili da Node.js, ma non è necessario che utilizzino internamente il modulo node:test
.
Ogni file di test viene eseguito come se fosse uno script normale. Cioè, se il file di test stesso utilizza node:test
per definire i test, tutti quei test verranno eseguiti all'interno di un singolo thread dell'applicazione, indipendentemente dal valore dell'opzione concurrency
di test()
.
Quando l'isolamento dei test a livello di processo è disabilitato, ogni file di test corrispondente viene importato nel processo del test runner. Una volta caricati tutti i file di test, i test di livello superiore vengono eseguiti con una concorrenza di uno. Poiché i file di test vengono tutti eseguiti nello stesso contesto, è possibile che i test interagiscano tra loro in modi che non sono possibili quando l'isolamento è abilitato. Ad esempio, se un test si basa sullo stato globale, è possibile che tale stato venga modificato da un test originato da un altro file.
Raccolta della copertura del codice
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1 - Sperimentale
Quando Node.js viene avviato con il flag della riga di comando --experimental-test-coverage
, viene raccolta la copertura del codice e le statistiche vengono riportate una volta completati tutti i test. Se la variabile di ambiente NODE_V8_COVERAGE
viene utilizzata per specificare una directory di copertura del codice, i file di copertura V8 generati vengono scritti in quella directory. I moduli core di Node.js e i file all'interno delle directory node_modules/
non sono, per impostazione predefinita, inclusi nel report di copertura. Tuttavia, possono essere inclusi esplicitamente tramite il flag --test-coverage-include
. Per impostazione predefinita, tutti i file di test corrispondenti sono esclusi dal report di copertura. Le esclusioni possono essere sostituite utilizzando il flag --test-coverage-exclude
. Se la copertura è abilitata, il report di copertura viene inviato a qualsiasi reporter di test tramite l'evento 'test:coverage'
.
La copertura può essere disabilitata su una serie di righe utilizzando la seguente sintassi di commento:
/* node:coverage disable */
if (anAlwaysFalseCondition) {
// Il codice in questo ramo non verrà mai eseguito, ma le righe vengono ignorate ai fini della copertura. Tutte le righe successive al commento 'disable' vengono ignorate fino a quando non viene incontrato un commento 'enable' corrispondente.
console.log('questo non viene mai eseguito')
}
/* node:coverage enable */
La copertura può anche essere disabilitata per un numero specificato di righe. Dopo il numero specificato di righe, la copertura verrà automaticamente riabilitata. Se il numero di righe non viene fornito esplicitamente, viene ignorata una singola riga.
/* node:coverage ignore next */
if (anAlwaysFalseCondition) {
console.log('questo non viene mai eseguito')
}
/* node:coverage ignore next 3 */
if (anAlwaysFalseCondition) {
console.log('questo non viene mai eseguito')
}
Reporter di copertura
I reporter tap
e spec
stamperanno un riepilogo delle statistiche di copertura. Esiste anche un reporter lcov
che genererà un file lcov
utilizzabile come report di copertura approfondito.
node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info
- Questo reporter non riporta i risultati dei test.
- Questo reporter dovrebbe idealmente essere usato insieme a un altro reporter.
Mocking
Il modulo node:test
supporta il mocking durante i test tramite un oggetto mock
di livello superiore. L'esempio seguente crea una spy su una funzione che somma due numeri. La spy viene poi usata per asserire che la funzione è stata chiamata come previsto.
import assert from 'node:assert'
import { mock, test } from 'node:test'
test('spies on a function', () => {
const sum = mock.fn((a, b) => {
return a + b
})
assert.strictEqual(sum.mock.callCount(), 0)
assert.strictEqual(sum(3, 4), 7)
assert.strictEqual(sum.mock.callCount(), 1)
const call = sum.mock.calls[0]
assert.deepStrictEqual(call.arguments, [3, 4])
assert.strictEqual(call.result, 7)
assert.strictEqual(call.error, undefined)
// Reimposta le mock tracciate globalmente.
mock.reset()
})
'use strict'
const assert = require('node:assert')
const { mock, test } = require('node:test')
test('spies on a function', () => {
const sum = mock.fn((a, b) => {
return a + b
})
assert.strictEqual(sum.mock.callCount(), 0)
assert.strictEqual(sum(3, 4), 7)
assert.strictEqual(sum.mock.callCount(), 1)
const call = sum.mock.calls[0]
assert.deepStrictEqual(call.arguments, [3, 4])
assert.strictEqual(call.result, 7)
assert.strictEqual(call.error, undefined)
// Reimposta le mock tracciate globalmente.
mock.reset()
})
La stessa funzionalità di mocking è esposta anche sull'oggetto TestContext
di ogni test. L'esempio seguente crea una spy su un metodo di oggetto usando l'API esposta su TestContext
. Il vantaggio del mocking tramite il contesto del test è che il test runner ripristinerà automaticamente tutte le funzionalità mockate una volta terminato il test.
test('spies on an object method', t => {
const number = {
value: 5,
add(a) {
return this.value + a
},
}
t.mock.method(number, 'add')
assert.strictEqual(number.add.mock.callCount(), 0)
assert.strictEqual(number.add(3), 8)
assert.strictEqual(number.add.mock.callCount(), 1)
const call = number.add.mock.calls[0]
assert.deepStrictEqual(call.arguments, [3])
assert.strictEqual(call.result, 8)
assert.strictEqual(call.target, undefined)
assert.strictEqual(call.this, number)
})
Timer
L'imitazione dei timer è una tecnica comunemente utilizzata nei test del software per simulare e controllare il comportamento dei timer, come setInterval
e setTimeout
, senza dover effettivamente attendere gli intervalli di tempo specificati.
Fare riferimento alla classe MockTimers
per un elenco completo di metodi e funzionalità.
Questo consente agli sviluppatori di scrivere test più affidabili e prevedibili per le funzionalità dipendenti dal tempo.
L'esempio seguente mostra come imitare setTimeout
. Usando .enable({ apis: ['setTimeout'] });
si imiteranno le funzioni setTimeout
nei moduli node:timers e node:timers/promises, così come dal contesto globale di Node.js.
Nota: La destrutturazione di funzioni come import { setTimeout } from 'node:timers'
non è attualmente supportata da questa API.
import assert from 'node:assert'
import { mock, test } from 'node:test'
test('simula setTimeout per essere eseguito sincronicamente senza dover effettivamente aspettare', () => {
const fn = mock.fn()
// Opzionalmente scegli cosa imitare
mock.timers.enable({ apis: ['setTimeout'] })
setTimeout(fn, 9999)
assert.strictEqual(fn.mock.callCount(), 0)
// Avanzamento nel tempo
mock.timers.tick(9999)
assert.strictEqual(fn.mock.callCount(), 1)
// Reimposta le imitazioni tracciate globalmente.
mock.timers.reset()
// Se si chiama reset mock instance, si reimposterà anche l'istanza dei timer
mock.reset()
})
const assert = require('node:assert')
const { mock, test } = require('node:test')
test('simula setTimeout per essere eseguito sincronicamente senza dover effettivamente aspettare', () => {
const fn = mock.fn()
// Opzionalmente scegli cosa imitare
mock.timers.enable({ apis: ['setTimeout'] })
setTimeout(fn, 9999)
assert.strictEqual(fn.mock.callCount(), 0)
// Avanzamento nel tempo
mock.timers.tick(9999)
assert.strictEqual(fn.mock.callCount(), 1)
// Reimposta le imitazioni tracciate globalmente.
mock.timers.reset()
// Se si chiama reset mock instance, si reimposterà anche l'istanza dei timer
mock.reset()
})
La stessa funzionalità di imitazione è esposta anche nella proprietà mock sull'oggetto TestContext
di ogni test. Il vantaggio dell'imitazione tramite il contesto del test è che il test runner ripristinerà automaticamente tutte le funzionalità dei timer imitati una volta terminato il test.
import assert from 'node:assert'
import { test } from 'node:test'
test('simula setTimeout per essere eseguito sincronicamente senza dover effettivamente aspettare', context => {
const fn = context.mock.fn()
// Opzionalmente scegli cosa imitare
context.mock.timers.enable({ apis: ['setTimeout'] })
setTimeout(fn, 9999)
assert.strictEqual(fn.mock.callCount(), 0)
// Avanzamento nel tempo
context.mock.timers.tick(9999)
assert.strictEqual(fn.mock.callCount(), 1)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('simula setTimeout per essere eseguito sincronicamente senza dover effettivamente aspettare', context => {
const fn = context.mock.fn()
// Opzionalmente scegli cosa imitare
context.mock.timers.enable({ apis: ['setTimeout'] })
setTimeout(fn, 9999)
assert.strictEqual(fn.mock.callCount(), 0)
// Avanzamento nel tempo
context.mock.timers.tick(9999)
assert.strictEqual(fn.mock.callCount(), 1)
})
Date
L'API dei timer simulati consente anche la simulazione dell'oggetto Date
. Questa è una funzionalità utile per testare funzionalità dipendenti dal tempo o per simulare funzioni di calendario interne come Date.now()
.
L'implementazione delle date fa anche parte della classe MockTimers
. Fare riferimento ad essa per un elenco completo di metodi e funzionalità.
Nota: Le date e i timer sono dipendenti quando simulati insieme. Ciò significa che se si hanno sia Date
che setTimeout
simulati, l'avanzamento del tempo farà anche avanzare la data simulata poiché simulano un singolo orologio interno.
L'esempio seguente mostra come simulare l'oggetto Date
e ottenere il valore corrente di Date.now()
.
import assert from 'node:assert'
import { test } from 'node:test'
test("simula l'oggetto Date", context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['Date'] })
// Se non specificato, la data iniziale sarà basata su 0 nell'epoca Unix
assert.strictEqual(Date.now(), 0)
// L'avanzamento nel tempo farà anche avanzare la data
context.mock.timers.tick(9999)
assert.strictEqual(Date.now(), 9999)
})
const assert = require('node:assert')
const { test } = require('node:test')
test("simula l'oggetto Date", context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['Date'] })
// Se non specificato, la data iniziale sarà basata su 0 nell'epoca Unix
assert.strictEqual(Date.now(), 0)
// L'avanzamento nel tempo farà anche avanzare la data
context.mock.timers.tick(9999)
assert.strictEqual(Date.now(), 9999)
})
Se non è impostata un'epoca iniziale, la data iniziale sarà basata su 0 nell'epoca Unix. Questo è il 1° gennaio 1970, 00:00:00 UTC. È possibile impostare una data iniziale passando una proprietà now
al metodo .enable()
. Questo valore verrà utilizzato come data iniziale per l'oggetto Date
simulato. Può essere un intero positivo o un altro oggetto Date.
import assert from 'node:assert'
import { test } from 'node:test'
test("simula l'oggetto Date con tempo iniziale", context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['Date'], now: 100 })
assert.strictEqual(Date.now(), 100)
// L'avanzamento nel tempo farà anche avanzare la data
context.mock.timers.tick(200)
assert.strictEqual(Date.now(), 300)
})
const assert = require('node:assert')
const { test } = require('node:test')
test("simula l'oggetto Date con tempo iniziale", context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['Date'], now: 100 })
assert.strictEqual(Date.now(), 100)
// L'avanzamento nel tempo farà anche avanzare la data
context.mock.timers.tick(200)
assert.strictEqual(Date.now(), 300)
})
È possibile utilizzare il metodo .setTime()
per spostare manualmente la data simulata in un altro momento. Questo metodo accetta solo un intero positivo.
Nota: Questo metodo eseguirà tutti i timer simulati che sono nel passato rispetto al nuovo tempo.
Nell'esempio seguente stiamo impostando un nuovo tempo per la data simulata.
import assert from 'node:assert'
import { test } from 'node:test'
test("imposta l'ora di un oggetto data", context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['Date'], now: 100 })
assert.strictEqual(Date.now(), 100)
// L'avanzamento nel tempo farà anche avanzare la data
context.mock.timers.setTime(1000)
context.mock.timers.tick(200)
assert.strictEqual(Date.now(), 1200)
})
const assert = require('node:assert')
const { test } = require('node:test')
test("imposta l'ora di un oggetto data", context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['Date'], now: 100 })
assert.strictEqual(Date.now(), 100)
// L'avanzamento nel tempo farà anche avanzare la data
context.mock.timers.setTime(1000)
context.mock.timers.tick(200)
assert.strictEqual(Date.now(), 1200)
})
Se si dispone di un timer impostato per essere eseguito nel passato, verrà eseguito come se fosse stato chiamato il metodo .tick()
. Questo è utile se si desidera testare funzionalità dipendenti dal tempo che sono già nel passato.
import assert from 'node:assert'
import { test } from 'node:test'
test('esegue i timer mentre setTime fa avanzare i tick', context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
const fn = context.mock.fn()
setTimeout(fn, 1000)
context.mock.timers.setTime(800)
// Il timer non viene eseguito perché il tempo non è ancora raggiunto
assert.strictEqual(fn.mock.callCount(), 0)
assert.strictEqual(Date.now(), 800)
context.mock.timers.setTime(1200)
// Il timer viene eseguito perché il tempo è ora raggiunto
assert.strictEqual(fn.mock.callCount(), 1)
assert.strictEqual(Date.now(), 1200)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('esegue i timer mentre setTime fa avanzare i tick', context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
const fn = context.mock.fn()
setTimeout(fn, 1000)
context.mock.timers.setTime(800)
// Il timer non viene eseguito perché il tempo non è ancora raggiunto
assert.strictEqual(fn.mock.callCount(), 0)
assert.strictEqual(Date.now(), 800)
context.mock.timers.setTime(1200)
// Il timer viene eseguito perché il tempo è ora raggiunto
assert.strictEqual(fn.mock.callCount(), 1)
assert.strictEqual(Date.now(), 1200)
})
L'utilizzo di .runAll()
eseguirà tutti i timer attualmente in coda. Ciò farà anche avanzare la data simulata fino al tempo dell'ultimo timer eseguito, come se il tempo fosse passato.
import assert from 'node:assert'
import { test } from 'node:test'
test('esegue i timer mentre setTime fa avanzare i tick', context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
const fn = context.mock.fn()
setTimeout(fn, 1000)
setTimeout(fn, 2000)
setTimeout(fn, 3000)
context.mock.timers.runAll()
// Tutti i timer vengono eseguiti perché il tempo è ora raggiunto
assert.strictEqual(fn.mock.callCount(), 3)
assert.strictEqual(Date.now(), 3000)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('esegue i timer mentre setTime fa avanzare i tick', context => {
// Opzionalmente scegli cosa simulare
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
const fn = context.mock.fn()
setTimeout(fn, 1000)
setTimeout(fn, 2000)
setTimeout(fn, 3000)
context.mock.timers.runAll()
// Tutti i timer vengono eseguiti perché il tempo è ora raggiunto
assert.strictEqual(fn.mock.callCount(), 3)
assert.strictEqual(Date.now(), 3000)
})
Test di snapshot
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1.0 - Sviluppo iniziale
I test di snapshot consentono di serializzare valori arbitrari in valori stringa e di confrontarli con un insieme di valori noti validi. I valori noti validi sono noti come snapshot e sono memorizzati in un file di snapshot. I file di snapshot sono gestiti dal test runner, ma sono progettati per essere leggibili dall'uomo per facilitare il debug. La prassi migliore è che i file di snapshot vengano inseriti nel controllo di versione insieme ai file di test.
I file di snapshot vengono generati avviando Node.js con il flag della riga di comando --test-update-snapshots
. Viene generato un file di snapshot separato per ogni file di test. Per impostazione predefinita, il file di snapshot ha lo stesso nome del file di test con estensione .snapshot
. Questo comportamento può essere configurato utilizzando la funzione snapshot.setResolveSnapshotPath()
. Ogni asserzione di snapshot corrisponde a un'esportazione nel file di snapshot.
Di seguito è riportato un esempio di test di snapshot. La prima volta che questo test viene eseguito, fallirà perché il corrispondente file di snapshot non esiste.
// test.js
suite('suite di test di snapshot', () => {
test('test di snapshot', t => {
t.assert.snapshot({ value1: 1, value2: 2 })
t.assert.snapshot(5)
})
})
Generare il file di snapshot eseguendo il file di test con --test-update-snapshots
. Il test dovrebbe riuscire e viene creato un file denominato test.js.snapshot
nella stessa directory del file di test. Il contenuto del file di snapshot è mostrato di seguito. Ogni snapshot è identificato dal nome completo del test e da un contatore per differenziare gli snapshot nello stesso test.
exports[`suite di test di snapshot > test di snapshot 1`] = `
{
"value1": 1,
"value2": 2
}
`
exports[`suite di test di snapshot > test di snapshot 2`] = `
5
`
Una volta creato il file di snapshot, eseguire nuovamente i test senza il flag --test-update-snapshots
. I test dovrebbero ora riuscire.
Reporter di test
[Cronologia]
Versione | Modifiche |
---|---|
v19.9.0, v18.17.0 | I reporter sono ora esposti in node:test/reporters . |
v19.6.0, v18.15.0 | Aggiunto in: v19.6.0, v18.15.0 |
Il modulo node:test
supporta l'utilizzo di flag --test-reporter
per il test runner, al fine di utilizzare uno specifico reporter.
Sono supportati i seguenti reporter integrati:
spec
Il reporterspec
fornisce i risultati del test in un formato leggibile dall'uomo. Questo è il reporter predefinito.tap
Il reportertap
fornisce i risultati del test nel formato TAP.dot
Il reporterdot
fornisce i risultati del test in un formato compatto, dove ogni test superato è rappresentato da un.
, e ogni test fallito è rappresentato da unaX
.junit
Il reporter junit fornisce i risultati dei test in formato XML jUnitlcov
Il reporterlcov
fornisce la copertura del test quando utilizzato con il flag--experimental-test-coverage
.
L'output esatto di questi reporter è soggetto a modifiche tra le diverse versioni di Node.js e non dovrebbe essere utilizzato in modo programmatico. Se è richiesto l'accesso programmatico all'output del test runner, utilizzare gli eventi emessi da <TestsStream>.
I reporter sono disponibili tramite il modulo node:test/reporters
:
import { tap, spec, dot, junit, lcov } from 'node:test/reporters'
const { tap, spec, dot, junit, lcov } = require('node:test/reporters')
Reporter personalizzati
--test-reporter
può essere utilizzato per specificare un percorso verso un reporter personalizzato. Un reporter personalizzato è un modulo che esporta un valore accettato da stream.compose. I reporter dovrebbero trasformare gli eventi emessi da un <TestsStream>
Esempio di un reporter personalizzato che utilizza <stream.Transform>:
import { Transform } from 'node:stream'
const customReporter = new Transform({
writableObjectMode: true,
transform(event, encoding, callback) {
switch (event.type) {
case 'test:dequeue':
callback(null, `test ${event.data.name} dequeued`)
break
case 'test:enqueue':
callback(null, `test ${event.data.name} enqueued`)
break
case 'test:watch:drained':
callback(null, 'test watch queue drained')
break
case 'test:start':
callback(null, `test ${event.data.name} started`)
break
case 'test:pass':
callback(null, `test ${event.data.name} passed`)
break
case 'test:fail':
callback(null, `test ${event.data.name} failed`)
break
case 'test:plan':
callback(null, 'test plan')
break
case 'test:diagnostic':
case 'test:stderr':
case 'test:stdout':
callback(null, event.data.message)
break
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals
callback(null, `total line count: ${totalLineCount}\n`)
break
}
}
},
})
export default customReporter
const { Transform } = require('node:stream')
const customReporter = new Transform({
writableObjectMode: true,
transform(event, encoding, callback) {
switch (event.type) {
case 'test:dequeue':
callback(null, `test ${event.data.name} dequeued`)
break
case 'test:enqueue':
callback(null, `test ${event.data.name} enqueued`)
break
case 'test:watch:drained':
callback(null, 'test watch queue drained')
break
case 'test:start':
callback(null, `test ${event.data.name} started`)
break
case 'test:pass':
callback(null, `test ${event.data.name} passed`)
break
case 'test:fail':
callback(null, `test ${event.data.name} failed`)
break
case 'test:plan':
callback(null, 'test plan')
break
case 'test:diagnostic':
case 'test:stderr':
case 'test:stdout':
callback(null, event.data.message)
break
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals
callback(null, `total line count: ${totalLineCount}\n`)
break
}
}
},
})
module.exports = customReporter
Esempio di un reporter personalizzato che utilizza una funzione generatore:
export default async function* customReporter(source) {
for await (const event of source) {
switch (event.type) {
case 'test:dequeue':
yield `test ${event.data.name} dequeued\n`
break
case 'test:enqueue':
yield `test ${event.data.name} enqueued\n`
break
case 'test:watch:drained':
yield 'test watch queue drained\n'
break
case 'test:start':
yield `test ${event.data.name} started\n`
break
case 'test:pass':
yield `test ${event.data.name} passed\n`
break
case 'test:fail':
yield `test ${event.data.name} failed\n`
break
case 'test:plan':
yield 'test plan\n'
break
case 'test:diagnostic':
case 'test:stderr':
case 'test:stdout':
yield `${event.data.message}\n`
break
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals
yield `total line count: ${totalLineCount}\n`
break
}
}
}
}
module.exports = async function* customReporter(source) {
for await (const event of source) {
switch (event.type) {
case 'test:dequeue':
yield `test ${event.data.name} dequeued\n`
break
case 'test:enqueue':
yield `test ${event.data.name} enqueued\n`
break
case 'test:watch:drained':
yield 'test watch queue drained\n'
break
case 'test:start':
yield `test ${event.data.name} started\n`
break
case 'test:pass':
yield `test ${event.data.name} passed\n`
break
case 'test:fail':
yield `test ${event.data.name} failed\n`
break
case 'test:plan':
yield 'test plan\n'
break
case 'test:diagnostic':
case 'test:stderr':
case 'test:stdout':
yield `${event.data.message}\n`
break
case 'test:coverage': {
const { totalLineCount } = event.data.summary.totals
yield `total line count: ${totalLineCount}\n`
break
}
}
}
}
Il valore fornito a --test-reporter
dovrebbe essere una stringa come quella utilizzata in un import()
nel codice JavaScript, o un valore fornito per --import
.
Più reporter
Il flag --test-reporter
può essere specificato più volte per riportare i risultati dei test in diversi formati. In questa situazione è necessario specificare una destinazione per ogni reporter usando --test-reporter-destination
. La destinazione può essere stdout
, stderr
o un percorso file. Reporter e destinazioni sono accoppiati secondo l'ordine in cui sono stati specificati.
Nell'esempio seguente, il reporter spec
verrà visualizzato su stdout
, e il reporter dot
verrà visualizzato su file.txt
:
node --test-reporter=spec --test-reporter=dot --test-reporter-destination=stdout --test-reporter-destination=file.txt
Quando viene specificato un singolo reporter, la destinazione predefinita sarà stdout
, a meno che una destinazione non venga fornita esplicitamente.
run([options])
[Cronologia]
Versione | Modifiche |
---|---|
v23.0.0 | Aggiunta l'opzione cwd . |
v23.0.0 | Aggiunte opzioni di copertura. |
v22.8.0 | Aggiunta l'opzione isolation . |
v22.6.0 | Aggiunta l'opzione globPatterns . |
v22.0.0, v20.14.0 | Aggiunta l'opzione forceExit . |
v20.1.0, v18.17.0 | Aggiunta un'opzione testNamePatterns . |
v18.9.0, v16.19.0 | Aggiunta in: v18.9.0, v16.19.0 |
options
<Oggetto> Opzioni di configurazione per l'esecuzione dei test. Sono supportate le seguenti proprietà:concurrency
<numero> | <booleano> Se viene fornito un numero, verranno eseguiti in parallelo tanti processi di test, dove ogni processo corrisponde a un file di test. Setrue
, verranno eseguitios.availableParallelism() - 1
file di test in parallelo. Sefalse
, verrà eseguito un solo file di test alla volta. Predefinito:false
.cwd
: <stringa> Specifica la directory di lavoro corrente da utilizzare dall'eseguitore dei test. Funge da percorso base per la risoluzione dei file in base al modello di esecuzione dell'eseguitore dei test. Predefinito:process.cwd()
.files
: <Array> Una matrice contenente l'elenco dei file da eseguire. Predefinito: file corrispondenti dal modello di esecuzione dell'eseguitore dei test.forceExit
: <booleano> Configura l'eseguitore dei test per uscire dal processo una volta che tutti i test noti sono stati eseguiti, anche se il loop degli eventi rimarrebbe altrimenti attivo. Predefinito:false
.globPatterns
: <Array> Una matrice contenente l'elenco dei modelli glob per i file di test corrispondenti. Questa opzione non può essere utilizzata insieme afiles
. Predefinito: file corrispondenti dal modello di esecuzione dell'eseguitore dei test.inspectPort
<numero> | <Funzione> Imposta la porta dell'inspector del processo figlio del test. Questo può essere un numero o una funzione che non accetta argomenti e restituisce un numero. Se viene fornito un valore nullish, ogni processo ottiene la sua porta, incrementata daprocess.debugPort
del principale. Questa opzione viene ignorata se l'opzioneisolation
è impostata su'none'
poiché non vengono generati processi figlio. Predefinito:undefined
.isolation
<stringa> Configura il tipo di isolamento del test. Se impostato su'process'
, ogni file di test viene eseguito in un processo figlio separato. Se impostato su'none'
, tutti i file di test vengono eseguiti nel processo corrente. Predefinito:'process'
.only
: <booleano> Se true, il contesto del test eseguirà solo i test che hanno l'opzioneonly
impostata.setup
<Funzione> Una funzione che accetta l'istanzaTestsStream
e può essere utilizzata per configurare gli ascoltatori prima dell'esecuzione di qualsiasi test. Predefinito:undefined
.execArgv
<Array> Una matrice di flag della riga di comando da passare all'eseguibilenode
quando si generano i sottoprocessi. Questa opzione non ha effetto quandoisolation
è'none'
. Predefinito:[]
argv
<Array> Una matrice di flag della riga di comando da passare a ciascun file di test quando si generano i sottoprocessi. Questa opzione non ha effetto quandoisolation
è'none'
. Predefinito:[]
.signal
<AbortSignal> Consente di interrompere un'esecuzione del test in corso.testNamePatterns
<stringa> | <RegExp> | <Array> Una stringa, una RegExp o una matrice RegExp, che può essere utilizzata per eseguire solo i test il cui nome corrisponde al modello fornito. I modelli di nome del test vengono interpretati come espressioni regolari JavaScript. Per ogni test eseguito, vengono eseguiti anche gli hook di test corrispondenti, comebeforeEach()
. Predefinito:undefined
.testSkipPatterns
<stringa> | <RegExp> | <Array> Una stringa, una RegExp o una matrice RegExp, che può essere utilizzata per escludere l'esecuzione di test il cui nome corrisponde al modello fornito. I modelli di nome del test vengono interpretati come espressioni regolari JavaScript. Per ogni test eseguito, vengono eseguiti anche gli hook di test corrispondenti, comebeforeEach()
. Predefinito:undefined
.timeout
<numero> Un numero di millisecondi dopo il quale l'esecuzione del test avrà esito negativo. Se non specificato, i sottotest ereditano questo valore dal loro padre. Predefinito:Infinity
.watch
<booleano> Se eseguire in modalità watch o meno. Predefinito:false
.shard
<Oggetto> Esecuzione di test in uno shard specifico. Predefinito:undefined
.index
<numero> è un intero positivo compreso tra 1 e\<totale\>
che specifica l'indice dello shard da eseguire. Questa opzione è obbligatoria.total
<numero> è un intero positivo che specifica il numero totale di shard in cui suddividere i file di test. Questa opzione è obbligatoria.coverage
<booleano> abilita la raccolta della copertura del codice. Predefinito:false
.coverageExcludeGlobs
<stringa> | <Array> Esclude file specifici dalla copertura del codice usando un modello glob, che può corrispondere a percorsi file sia assoluti che relativi. Questa proprietà è applicabile solo quandocoverage
è stato impostato sutrue
. Se vengono forniti siacoverageExcludeGlobs
checoverageIncludeGlobs
, i file devono soddisfare entrambi i criteri per essere inclusi nel report di copertura. Predefinito:undefined
.coverageIncludeGlobs
<stringa> | <Array> Include file specifici nella copertura del codice usando un modello glob, che può corrispondere a percorsi file sia assoluti che relativi. Questa proprietà è applicabile solo quandocoverage
è stato impostato sutrue
. Se vengono forniti siacoverageExcludeGlobs
checoverageIncludeGlobs
, i file devono soddisfare entrambi i criteri per essere inclusi nel report di copertura. Predefinito:undefined
.lineCoverage
<numero> Richiede una percentuale minima di linee coperte. Se la copertura del codice non raggiunge la soglia specificata, il processo terminerà con il codice1
. Predefinito:0
.branchCoverage
<numero> Richiede una percentuale minima di rami coperti. Se la copertura del codice non raggiunge la soglia specificata, il processo terminerà con il codice1
. Predefinito:0
.functionCoverage
<numero> Richiede una percentuale minima di funzioni coperte. Se la copertura del codice non raggiunge la soglia specificata, il processo terminerà con il codice1
. Predefinito:0
.
Restituisce: <TestsStream>
Nota: shard
viene utilizzato per parallelizzare orizzontalmente l'esecuzione dei test su macchine o processi, ideale per esecuzioni su larga scala in ambienti diversi. È incompatibile con la modalità watch
, progettata per un'iterazione rapida del codice rieseguendo automaticamente i test sulle modifiche ai file.
import { tap } from 'node:test/reporters'
import { run } from 'node:test'
import process from 'node:process'
import path from 'node:path'
run({ files: [path.resolve('./tests/test.js')] })
.on('test:fail', () => {
process.exitCode = 1
})
.compose(tap)
.pipe(process.stdout)
const { tap } = require('node:test/reporters')
const { run } = require('node:test')
const path = require('node:path')
run({ files: [path.resolve('./tests/test.js')] })
.on('test:fail', () => {
process.exitCode = 1
})
.compose(tap)
.pipe(process.stdout)
suite([name][, options][, fn])
Aggiunto in: v22.0.0, v20.13.0
name
<string> Il nome della suite, visualizzato nella reportistica dei risultati dei test. Default: La proprietàname
difn
, o'\<anonymous\>'
sefn
non ha un nome.options
<Object> Opzioni di configurazione facoltative per la suite. Supporta le stesse opzioni ditest([name][, options][, fn])
.fn
<Function> | <AsyncFunction> La funzione della suite che dichiara i test e le suite annidate. Il primo argomento di questa funzione è un oggettoSuiteContext
. Default: Una funzione no-op.- Restituisce: <Promise> Risolta immediatamente con
undefined
.
La funzione suite()
è importata dal modulo node:test
.
suite.skip([name][, options][, fn])
Aggiunto in: v22.0.0, v20.13.0
Abbreviazione per saltare una suite. È equivalente a suite([name], { skip: true }[, fn])
.
suite.todo([name][, options][, fn])
Aggiunto in: v22.0.0, v20.13.0
Abbreviazione per contrassegnare una suite come TODO
. È equivalente a suite([name], { todo: true }[, fn])
.
suite.only([name][, options][, fn])
Aggiunto in: v22.0.0, v20.13.0
Abbreviazione per contrassegnare una suite come only
. È equivalente a suite([name], { only: true }[, fn])
.
test([name][, options][, fn])
[Cronologia]
Versione | Modifiche |
---|---|
v20.2.0, v18.17.0 | Aggiunte le abbreviazioni skip , todo e only . |
v18.8.0, v16.18.0 | Aggiunta l'opzione signal . |
v18.7.0, v16.17.0 | Aggiunta l'opzione timeout . |
v18.0.0, v16.17.0 | Aggiunto in: v18.0.0, v16.17.0 |
name
<string> Il nome del test, visualizzato nella reportistica dei risultati dei test. Default: La proprietàname
difn
, o'\<anonymous\>'
sefn
non ha un nome.options
<Object> Opzioni di configurazione per il test. Sono supportate le seguenti proprietà:concurrency
<number> | <boolean> Se viene fornito un numero, vengono eseguiti in parallelo tanti test all'interno del thread dell'applicazione. Setrue
, tutti i test asincroni pianificati vengono eseguiti contemporaneamente all'interno del thread. Sefalse
, viene eseguito un solo test alla volta. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:false
.only
<boolean> Se veritiero, e il contesto del test è configurato per eseguire solo i testonly
, allora questo test verrà eseguito. Altrimenti, il test viene saltato. Default:false
.signal
<AbortSignal> Consente di interrompere un test in corso.skip
<boolean> | <string> Se veritiero, il test viene saltato. Se viene fornita una stringa, quella stringa viene visualizzata nei risultati del test come motivo per cui il test è stato saltato. Default:false
.todo
<boolean> | <string> Se veritiero, il test viene contrassegnato comeTODO
. Se viene fornita una stringa, quella stringa viene visualizzata nei risultati del test come motivo per cui il test èTODO
. Default:false
.timeout
<number> Un numero di millisecondi dopo il quale il test avrà esito negativo. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:Infinity
.plan
<number> Il numero di asserzioni e sottotest previsti da eseguire nel test. Se il numero di asserzioni eseguite nel test non corrisponde al numero specificato nel piano, il test avrà esito negativo. Default:undefined
.
fn
<Function> | <AsyncFunction> La funzione sottoposta a test. Il primo argomento di questa funzione è un oggettoTestContext
. Se il test utilizza callback, la funzione callback viene passata come secondo argomento. Default: Una funzione no-op.Restituisce: <Promise> Risolta con
undefined
una volta completato il test, o immediatamente se il test viene eseguito all'interno di una suite.
La funzione test()
è il valore importato dal modulo test
. Ogni invocazione di questa funzione determina la segnalazione del test a <TestsStream>.
L'oggetto TestContext
passato all'argomento fn
può essere utilizzato per eseguire azioni relative al test corrente. Esempi includono saltare il test, aggiungere informazioni diagnostiche aggiuntive o creare sottotest.
test()
restituisce una Promise
che viene risolta una volta completato il test. Se test()
viene chiamato all'interno di una suite, viene risolto immediatamente. Il valore di ritorno può generalmente essere scartato per i test di livello superiore. Tuttavia, il valore di ritorno dai sottotest deve essere utilizzato per impedire che il test principale termini prima e annulli il sottotest, come mostrato nell'esempio seguente.
test('test di livello superiore', async t => {
// Il setTimeout() nel seguente sottotest lo farebbe sopravvivere al suo
// test principale se 'await' venisse rimosso sulla riga successiva. Una volta completato il test principale,
// annullerà tutti i sottotest in sospeso.
await t.test('sottotest di durata maggiore', async t => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
})
})
})
L'opzione timeout
può essere utilizzata per far fallire il test se impiega più di timeout
millisecondi per completarsi. Tuttavia, non è un meccanismo affidabile per annullare i test perché un test in esecuzione potrebbe bloccare il thread dell'applicazione e quindi impedire l'annullamento pianificato.
test.skip([name][, options][, fn])
Abbreviazione per saltare un test, uguale a test([name], { skip: true }[, fn])
.
test.todo([name][, options][, fn])
Abbreviazione per marcare un test come TODO
, uguale a test([name], { todo: true }[, fn])
.
test.only([name][, options][, fn])
Abbreviazione per marcare un test come only
, uguale a test([name], { only: true }[, fn])
.
describe([name][, options][, fn])
Alias per suite()
.
La funzione describe()
è importata dal modulo node:test
.
describe.skip([name][, options][, fn])
Abbreviazione per saltare una suite. Questo è uguale a describe([name], { skip: true }[, fn])
.
describe.todo([name][, options][, fn])
Abbreviazione per marcare una suite come TODO
. Questo è uguale a describe([name], { todo: true }[, fn])
.
describe.only([name][, options][, fn])
Aggiunto in: v19.8.0, v18.15.0
Abbreviazione per marcare una suite come only
. Questo è uguale a describe([name], { only: true }[, fn])
.
it([name][, options][, fn])
[Cronologia]
Versione | Cambiamenti |
---|---|
v19.8.0, v18.16.0 | Chiamare it() è ora equivalente a chiamare test() . |
v18.6.0, v16.17.0 | Aggiunto in: v18.6.0, v16.17.0 |
Alias per test()
.
La funzione it()
è importata dal modulo node:test
.
it.skip([name][, options][, fn])
Abbreviazione per saltare un test, uguale a it([name], { skip: true }[, fn])
.
it.todo([name][, options][, fn])
Abbreviazione per marcare un test come TODO
, uguale a it([name], { todo: true }[, fn])
.
it.only([name][, options][, fn])
Aggiunto in: v19.8.0, v18.15.0
Abbreviazione per marcare un test come only
, uguale a it([name], { only: true }[, fn])
.
before([fn][, options])
Aggiunto in: v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La funzione hook. Se l'hook utilizza callback, la funzione di callback viene passata come secondo argomento. Default: Una funzione no-op.options
<Object> Opzioni di configurazione per l'hook. Sono supportate le seguenti proprietà:signal
<AbortSignal> Consente di interrompere un hook in corso.timeout
<number> Un numero di millisecondi dopo i quali l'hook fallirà. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:Infinity
.
Questa funzione crea un hook che viene eseguito prima dell'esecuzione di una suite.
describe('tests', async () => {
before(() => console.log('about to run some test'))
it('is a subtest', () => {
assert.ok('some relevant assertion here')
})
})
after([fn][, options])
Aggiunto in: v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La funzione hook. Se l'hook utilizza callback, la funzione di callback viene passata come secondo argomento. Default: Una funzione no-op.options
<Object> Opzioni di configurazione per l'hook. Sono supportate le seguenti proprietà:signal
<AbortSignal> Consente di interrompere un hook in corso.timeout
<number> Un numero di millisecondi dopo i quali l'hook fallirà. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:Infinity
.
Questa funzione crea un hook che viene eseguito dopo l'esecuzione di una suite.
describe('tests', async () => {
after(() => console.log('finished running tests'))
it('is a subtest', () => {
assert.ok('some relevant assertion here')
})
})
Nota: L'hook after
è garantito di essere eseguito, anche se i test all'interno della suite falliscono.
beforeEach([fn][, options])
Aggiunto in: v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La funzione hook. Se l'hook utilizza callback, la funzione callback viene passata come secondo argomento. Default: Una funzione no-op.options
<Object> Opzioni di configurazione per l'hook. Sono supportate le seguenti proprietà:signal
<AbortSignal> Permette di interrompere un hook in corso.timeout
<number> Un numero di millisecondi dopo il quale l'hook fallirà. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:Infinity
.
Questa funzione crea un hook che viene eseguito prima di ogni test nella suite corrente.
describe('tests', async () => {
beforeEach(() => console.log('about to run a test'))
it('is a subtest', () => {
assert.ok('some relevant assertion here')
})
})
afterEach([fn][, options])
Aggiunto in: v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La funzione hook. Se l'hook utilizza callback, la funzione callback viene passata come secondo argomento. Default: Una funzione no-op.options
<Object> Opzioni di configurazione per l'hook. Sono supportate le seguenti proprietà:signal
<AbortSignal> Permette di interrompere un hook in corso.timeout
<number> Un numero di millisecondi dopo il quale l'hook fallirà. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:Infinity
.
Questa funzione crea un hook che viene eseguito dopo ogni test nella suite corrente. L'hook afterEach()
viene eseguito anche se il test fallisce.
describe('tests', async () => {
afterEach(() => console.log('finished running a test'))
it('is a subtest', () => {
assert.ok('some relevant assertion here')
})
})
snapshot
Aggiunto in: v22.3.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1.0 - Sviluppo iniziale
Un oggetto i cui metodi vengono utilizzati per configurare le impostazioni di snapshot predefinite nel processo corrente. È possibile applicare la stessa configurazione a tutti i file inserendo codice di configurazione comune in un modulo precaricato con --require
o --import
.
snapshot.setDefaultSnapshotSerializers(serializers)
Aggiunto in: v22.3.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1.0 - Sviluppo iniziale
serializers
<Array> Una matrice di funzioni sincronizzate utilizzate come serializer predefiniti per i test snapshot.
Questa funzione viene utilizzata per personalizzare il meccanismo di serializzazione predefinito utilizzato dal test runner. Per impostazione predefinita, il test runner esegue la serializzazione chiamando JSON.stringify(value, null, 2)
sul valore fornito. JSON.stringify()
ha delle limitazioni per quanto riguarda le strutture circolari e i tipi di dati supportati. Se è necessario un meccanismo di serializzazione più robusto, è necessario utilizzare questa funzione.
snapshot.setResolveSnapshotPath(fn)
Aggiunto in: v22.3.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1.0 - Sviluppo iniziale
fn
<Function> Una funzione utilizzata per calcolare la posizione del file snapshot. La funzione riceve come unico argomento il percorso del file di test. Se il test non è associato a un file (ad esempio nella REPL), l'input è indefinito.fn()
deve restituire una stringa che specifica la posizione del file snapshot.
Questa funzione viene utilizzata per personalizzare la posizione del file snapshot utilizzato per i test snapshot. Per impostazione predefinita, il nome del file snapshot è lo stesso del nome del file di ingresso con estensione .snapshot
.
Classe: MockFunctionContext
Aggiunto in: v19.1.0, v18.13.0
La classe MockFunctionContext
viene utilizzata per ispezionare o manipolare il comportamento delle mock create tramite le API MockTracker
.
ctx.calls
Aggiunto in: v19.1.0, v18.13.0
Un getter che restituisce una copia dell'array interno utilizzato per tracciare le chiamate alla mock. Ogni elemento nell'array è un oggetto con le seguenti proprietà.
arguments
<Array> Un array degli argomenti passati alla funzione mock.error
<any> Se la funzione mock ha generato un'eccezione, questa proprietà contiene il valore generato. Default:undefined
.result
<any> Il valore restituito dalla funzione mock.stack
<Error> Un oggettoError
il cui stack può essere utilizzato per determinare il callsite dell'invocazione della funzione mock.target
<Function> | <undefined> Se la funzione mock è un costruttore, questo campo contiene la classe in costruzione. Altrimenti saràundefined
.this
<any> Il valorethis
della funzione mock.
ctx.callCount()
Aggiunto in: v19.1.0, v18.13.0
- Restituisce: <integer> Il numero di volte che questa mock è stata invocata.
Questa funzione restituisce il numero di volte che questa mock è stata invocata. Questa funzione è più efficiente rispetto al controllo di ctx.calls.length
perché ctx.calls
è un getter che crea una copia dell'array interno di tracciamento delle chiamate.
ctx.mockImplementation(implementation)
Aggiunto in: v19.1.0, v18.13.0
implementation
<Function> | <AsyncFunction> La funzione da utilizzare come nuova implementazione della mock.
Questa funzione viene utilizzata per modificare il comportamento di una mock esistente.
L'esempio seguente crea una funzione mock utilizzando t.mock.fn()
, chiama la funzione mock e quindi cambia l'implementazione della mock in una funzione diversa.
test('cambia il comportamento di una mock', t => {
let cnt = 0
function addOne() {
cnt++
return cnt
}
function addTwo() {
cnt += 2
return cnt
}
const fn = t.mock.fn(addOne)
assert.strictEqual(fn(), 1)
fn.mock.mockImplementation(addTwo)
assert.strictEqual(fn(), 3)
assert.strictEqual(fn(), 5)
})
ctx.mockImplementationOnce(implementation[, onCall])
Aggiunto in: v19.1.0, v18.13.0
implementation
<Function> | <AsyncFunction> La funzione da utilizzare come implementazione della mock per il numero di invocazione specificato daonCall
.onCall
<integer> Il numero di invocazione che utilizzeràimplementation
. Se l'invocazione specificata è già avvenuta, viene sollevata un'eccezione. Default: Il numero della prossima invocazione.
Questa funzione viene utilizzata per modificare il comportamento di una mock esistente per una singola invocazione. Una volta avvenuta l'invocazione onCall
, la mock tornerà al comportamento che avrebbe avuto se mockImplementationOnce()
non fosse stata chiamata.
L'esempio seguente crea una funzione mock utilizzando t.mock.fn()
, chiama la funzione mock, cambia l'implementazione della mock in una funzione diversa per la prossima invocazione e poi riprende il suo comportamento precedente.
test('cambia il comportamento di una mock una sola volta', t => {
let cnt = 0
function addOne() {
cnt++
return cnt
}
function addTwo() {
cnt += 2
return cnt
}
const fn = t.mock.fn(addOne)
assert.strictEqual(fn(), 1)
fn.mock.mockImplementationOnce(addTwo)
assert.strictEqual(fn(), 3)
assert.strictEqual(fn(), 4)
})
ctx.resetCalls()
Aggiunto in: v19.3.0, v18.13.0
Reimposta la cronologia delle chiamate della funzione mock.
ctx.restore()
Aggiunto in: v19.1.0, v18.13.0
Reimposta l'implementazione della funzione mock al suo comportamento originale. Il mock può ancora essere utilizzato dopo aver chiamato questa funzione.
Classe: MockModuleContext
Aggiunto in: v22.3.0, v20.18.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1.0 - Sviluppo iniziale
La classe MockModuleContext
viene utilizzata per manipolare il comportamento dei mock di modulo creati tramite le API MockTracker
.
ctx.restore()
Aggiunto in: v22.3.0, v20.18.0
Reimposta l'implementazione del modulo mock.
Classe: MockTracker
Aggiunto in: v19.1.0, v18.13.0
La classe MockTracker
viene utilizzata per gestire la funzionalità di mocking. Il modulo del test runner fornisce un'esportazione di livello superiore mock
che è un'istanza di MockTracker
. Ogni test fornisce anche la sua istanza MockTracker
tramite la proprietà mock
del contesto del test.
mock.fn([original[, implementation]][, options])
Aggiunto in: v19.1.0, v18.13.0
original
<Function> | <AsyncFunction> Una funzione opzionale su cui creare un mock. Default: Una funzione no-op.implementation
<Function> | <AsyncFunction> Una funzione opzionale utilizzata come implementazione del mock peroriginal
. Questo è utile per creare mock che mostrano un comportamento per un numero specificato di chiamate e poi ripristinare il comportamento dioriginal
. Default: La funzione specificata daoriginal
.options
<Object> Opzioni di configurazione opzionali per la funzione mock. Sono supportate le seguenti proprietà:times
<integer> Il numero di volte in cui il mock utilizzerà il comportamento diimplementation
. Una volta che la funzione mock è stata chiamatatimes
volte, ripristinerà automaticamente il comportamento dioriginal
. Questo valore deve essere un intero maggiore di zero. Default:Infinity
.
Restituisce: <Proxy> La funzione mockata. La funzione mockata contiene una proprietà speciale
mock
, che è un'istanza diMockFunctionContext
, e può essere utilizzata per ispezionare e modificare il comportamento della funzione mockata.
Questa funzione viene utilizzata per creare una funzione mock.
L'esempio seguente crea una funzione mock che incrementa un contatore di uno ad ogni invocazione. L'opzione times
viene utilizzata per modificare il comportamento del mock in modo che le prime due invocazioni aggiungano due al contatore invece di uno.
test('mocks a counting function', t => {
let cnt = 0
function addOne() {
cnt++
return cnt
}
function addTwo() {
cnt += 2
return cnt
}
const fn = t.mock.fn(addOne, addTwo, { times: 2 })
assert.strictEqual(fn(), 2)
assert.strictEqual(fn(), 4)
assert.strictEqual(fn(), 5)
assert.strictEqual(fn(), 6)
})
mock.getter(object, methodName[, implementation][, options])
Aggiunto in: v19.3.0, v18.13.0
Questa funzione è sintatticamente equivalente a MockTracker.method
con options.getter
impostato su true
.
mock.method(object, methodName[, implementation][, options])
Aggiunto in: v19.1.0, v18.13.0
object
<Object> L'oggetto il cui metodo viene simulato.methodName
<string> | <symbol> L'identificatore del metodo suobject
da simulare. Seobject[methodName]
non è una funzione, viene generato un errore.implementation
<Function> | <AsyncFunction> Una funzione opzionale utilizzata come implementazione simulata perobject[methodName]
. Default: Il metodo originale specificato daobject[methodName]
.options
<Object> Opzioni di configurazione facoltative per il metodo simulato. Sono supportate le seguenti proprietà:getter
<boolean> Setrue
,object[methodName]
viene trattato come un getter. Questa opzione non può essere utilizzata con l'opzionesetter
. Default: false.setter
<boolean> Setrue
,object[methodName]
viene trattato come un setter. Questa opzione non può essere utilizzata con l'opzionegetter
. Default: false.times
<integer> Il numero di volte in cui la simulazione utilizzerà il comportamento diimplementation
. Una volta che il metodo simulato è stato chiamatotimes
volte, ripristinerà automaticamente il comportamento originale. Questo valore deve essere un intero maggiore di zero. Default:Infinity
.
Restituisce: <Proxy> Il metodo simulato. Il metodo simulato contiene una proprietà speciale
mock
, che è un'istanza diMockFunctionContext
, e può essere utilizzata per ispezionare e modificare il comportamento del metodo simulato.
Questa funzione viene utilizzata per creare una simulazione su un metodo di oggetto esistente. L'esempio seguente mostra come viene creata una simulazione su un metodo di oggetto esistente.
test('spia su un metodo di oggetto', t => {
const number = {
value: 5,
subtract(a) {
return this.value - a
},
}
t.mock.method(number, 'subtract')
assert.strictEqual(number.subtract.mock.callCount(), 0)
assert.strictEqual(number.subtract(3), 2)
assert.strictEqual(number.subtract.mock.callCount(), 1)
const call = number.subtract.mock.calls[0]
assert.deepStrictEqual(call.arguments, [3])
assert.strictEqual(call.result, 2)
assert.strictEqual(call.error, undefined)
assert.strictEqual(call.target, undefined)
assert.strictEqual(call.this, number)
})
mock.module(specifier[, options])
Aggiunto in: v22.3.0, v20.18.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1.0 - Sviluppo iniziale
specifier
<string> | <URL> Una stringa che identifica il modulo da simulare.options
<Object> Opzioni di configurazione facoltative per il modulo simulato. Sono supportate le seguenti proprietà:cache
<boolean> Sefalse
, ogni chiamata arequire()
oimport()
genera un nuovo modulo simulato. Setrue
, le chiamate successive restituiranno la stessa simulazione del modulo e la simulazione del modulo viene inserita nella cache CommonJS. Default: false.defaultExport
<any> Un valore facoltativo utilizzato come esportazione predefinita del modulo simulato. Se questo valore non viene fornito, le simulazioni ESM non includono un'esportazione predefinita. Se la simulazione è un modulo CommonJS o incorporato, questa impostazione viene utilizzata come valore dimodule.exports
. Se questo valore non viene fornito, le simulazioni CJS e incorporate utilizzano un oggetto vuoto come valore dimodule.exports
.namedExports
<Object> Un oggetto facoltativo le cui chiavi e valori vengono utilizzati per creare le esportazioni denominate del modulo simulato. Se la simulazione è un modulo CommonJS o incorporato, questi valori vengono copiati sumodule.exports
. Pertanto, se una simulazione viene creata sia con esportazioni denominate che con un'esportazione predefinita non di tipo oggetto, la simulazione genererà un'eccezione quando utilizzata come modulo CJS o incorporato.
Restituisce: <MockModuleContext> Un oggetto che può essere utilizzato per manipolare la simulazione.
Questa funzione viene utilizzata per simulare le esportazioni di moduli ECMAScript, moduli CommonJS e moduli incorporati di Node.js. Qualsiasi riferimento al modulo originale prima della simulazione non viene influenzato. Per abilitare la simulazione dei moduli, Node.js deve essere avviato con il flag della riga di comando --experimental-test-module-mocks
.
L'esempio seguente mostra come viene creata una simulazione per un modulo.
test('simula un modulo incorporato in entrambi i sistemi di moduli', async t => {
// Crea una simulazione di 'node:readline' con un'esportazione denominata 'fn', che
// non esiste nel modulo 'node:readline' originale.
const mock = t.mock.module('node:readline', {
namedExports: {
fn() {
return 42
},
},
})
let esmImpl = await import('node:readline')
let cjsImpl = require('node:readline')
// cursorTo() è un'esportazione del modulo 'node:readline' originale.
assert.strictEqual(esmImpl.cursorTo, undefined)
assert.strictEqual(cjsImpl.cursorTo, undefined)
assert.strictEqual(esmImpl.fn(), 42)
assert.strictEqual(cjsImpl.fn(), 42)
mock.restore()
// La simulazione viene ripristinata, quindi viene restituito il modulo incorporato originale.
esmImpl = await import('node:readline')
cjsImpl = require('node:readline')
assert.strictEqual(typeof esmImpl.cursorTo, 'function')
assert.strictEqual(typeof cjsImpl.cursorTo, 'function')
assert.strictEqual(esmImpl.fn, undefined)
assert.strictEqual(cjsImpl.fn, undefined)
})
mock.reset()
Aggiunto in: v19.1.0, v18.13.0
Questa funzione ripristina il comportamento predefinito di tutte le mock precedentemente create da questo MockTracker
e dissocia le mock dall'istanza MockTracker
. Una volta dissociate, le mock possono ancora essere utilizzate, ma l'istanza MockTracker
non può più essere utilizzata per ripristinare il loro comportamento o interagire con esse in altro modo.
Dopo il completamento di ogni test, questa funzione viene chiamata sul MockTracker
del contesto del test. Se il MockTracker
globale viene utilizzato estesamente, si consiglia di chiamare manualmente questa funzione.
mock.restoreAll()
Aggiunto in: v19.1.0, v18.13.0
Questa funzione ripristina il comportamento predefinito di tutte le mock precedentemente create da questo MockTracker
. A differenza di mock.reset()
, mock.restoreAll()
non dissocia le mock dall'istanza MockTracker
.
mock.setter(oggetto, methodName[, implementazione][, opzioni])
Aggiunto in: v19.3.0, v18.13.0
Questa funzione è sintatticamente equivalente a MockTracker.method
con options.setter
impostato su true
.
Classe: MockTimers
[Cronologia]
Versione | Modifiche |
---|---|
v23.1.0 | I Mock Timers sono ora stabili. |
v20.4.0, v18.19.0 | Aggiunto in: v20.4.0, v18.19.0 |
[Stabile: 2 - Stabile]
Stabile: 2 Stabilità: 2 - Stabile
Il mocking dei timer è una tecnica comunemente usata nei test software per simulare e controllare il comportamento dei timer, come setInterval
e setTimeout
, senza dover effettivamente attendere gli intervalli di tempo specificati.
MockTimers è anche in grado di mockare l'oggetto Date
.
Il MockTracker
fornisce un'esportazione timers
di livello superiore che è un'istanza MockTimers
.
timers.enable([enableOptions])
[Cronologia]
Versione | Modifiche |
---|---|
v21.2.0, v20.11.0 | Parametri aggiornati per essere un oggetto opzione con API disponibili e l'epoca iniziale predefinita. |
v20.4.0, v18.19.0 | Aggiunto in: v20.4.0, v18.19.0 |
Abilita il mocking dei timer per i timer specificati.
enableOptions
<Oggetto> Opzioni di configurazione facoltative per abilitare il mocking dei timer. Sono supportate le seguenti proprietà:apis
<Array> Un array facoltativo contenente i timer da mockare. I valori timer attualmente supportati sono'setInterval'
,'setTimeout'
,'setImmediate'
e'Date'
. Predefinito:['setInterval', 'setTimeout', 'setImmediate', 'Date']
. Se non viene fornito alcun array, tutte le API relative al tempo ('setInterval'
,'clearInterval'
,'setTimeout'
,'clearTimeout'
,'setImmediate'
,'clearImmediate'
e'Date'
) saranno mockate per impostazione predefinita.now
<numero> | <Data> Un numero o un oggetto Date facoltativo che rappresenta il tempo iniziale (in millisecondi) da utilizzare come valore perDate.now()
. Predefinito:0
.
Nota: Quando si abilita il mocking per un timer specifico, la sua funzione di cancellazione associata verrà anche implicitamente mockata.
Nota: Il mocking di Date
influenzerà il comportamento dei timer mockati poiché utilizzano lo stesso orologio interno.
Esempio di utilizzo senza impostare il tempo iniziale:
import { mock } from 'node:test'
mock.timers.enable({ apis: ['setInterval'] })
const { mock } = require('node:test')
mock.timers.enable({ apis: ['setInterval'] })
L'esempio precedente abilita il mocking per il timer setInterval
e implicitamente mocka la funzione clearInterval
. Solo le funzioni setInterval
e clearInterval
da node:timers, node:timers/promises e globalThis
saranno mockate.
Esempio di utilizzo con tempo iniziale impostato
import { mock } from 'node:test'
mock.timers.enable({ apis: ['Date'], now: 1000 })
const { mock } = require('node:test')
mock.timers.enable({ apis: ['Date'], now: 1000 })
Esempio di utilizzo con oggetto Date iniziale impostato come tempo
import { mock } from 'node:test'
mock.timers.enable({ apis: ['Date'], now: new Date() })
const { mock } = require('node:test')
mock.timers.enable({ apis: ['Date'], now: new Date() })
In alternativa, se si chiama mock.timers.enable()
senza parametri:
Tutti i timer ('setInterval'
, 'clearInterval'
, 'setTimeout'
, 'clearTimeout'
, 'setImmediate'
e 'clearImmediate'
) saranno mockati. Le funzioni setInterval
, clearInterval
, setTimeout
, clearTimeout
, setImmediate
e clearImmediate
da node:timers
, node:timers/promises
e globalThis
saranno mockate. Così come l'oggetto globale Date
.
timers.reset()
Aggiunto in: v20.4.0, v18.19.0
Questa funzione ripristina il comportamento predefinito di tutte le mock precedentemente create da questa istanza MockTimers
e dissocia le mock dall'istanza MockTracker
.
Nota: Dopo il completamento di ogni test, questa funzione viene chiamata sul MockTracker
del contesto del test.
import { mock } from 'node:test'
mock.timers.reset()
const { mock } = require('node:test')
mock.timers.reset()
timers[Symbol.dispose]()
Chiama timers.reset()
.
timers.tick([milliseconds])
Aggiunto in: v20.4.0, v18.19.0
Fa avanzare il tempo per tutti i timer simulati.
milliseconds
<number> La quantità di tempo, in millisecondi, di cui far avanzare i timer. Predefinito:1
.
Nota: Questo diverge dal modo in cui setTimeout
in Node.js si comporta e accetta solo numeri positivi. In Node.js, setTimeout
con numeri negativi è supportato solo per motivi di compatibilità web.
L'esempio seguente simula una funzione setTimeout
e, usando .tick
, fa avanzare il tempo attivando tutti i timer in sospeso.
import assert from 'node:assert'
import { test } from 'node:test'
test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
const fn = context.mock.fn()
context.mock.timers.enable({ apis: ['setTimeout'] })
setTimeout(fn, 9999)
assert.strictEqual(fn.mock.callCount(), 0)
// Avanzamento del tempo
context.mock.timers.tick(9999)
assert.strictEqual(fn.mock.callCount(), 1)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
const fn = context.mock.fn()
context.mock.timers.enable({ apis: ['setTimeout'] })
setTimeout(fn, 9999)
assert.strictEqual(fn.mock.callCount(), 0)
// Avanzamento del tempo
context.mock.timers.tick(9999)
assert.strictEqual(fn.mock.callCount(), 1)
})
In alternativa, la funzione .tick
può essere chiamata più volte
import assert from 'node:assert'
import { test } from 'node:test'
test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
const fn = context.mock.fn()
context.mock.timers.enable({ apis: ['setTimeout'] })
const nineSecs = 9000
setTimeout(fn, nineSecs)
const threeSeconds = 3000
context.mock.timers.tick(threeSeconds)
context.mock.timers.tick(threeSeconds)
context.mock.timers.tick(threeSeconds)
assert.strictEqual(fn.mock.callCount(), 1)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
const fn = context.mock.fn()
context.mock.timers.enable({ apis: ['setTimeout'] })
const nineSecs = 9000
setTimeout(fn, nineSecs)
const threeSeconds = 3000
context.mock.timers.tick(threeSeconds)
context.mock.timers.tick(threeSeconds)
context.mock.timers.tick(threeSeconds)
assert.strictEqual(fn.mock.callCount(), 1)
})
Far avanzare il tempo usando .tick
farà anche avanzare il tempo per qualsiasi oggetto Date
creato dopo che la simulazione è stata abilitata (se Date
è stato anche impostato per essere simulato).
import assert from 'node:assert'
import { test } from 'node:test'
test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
const fn = context.mock.fn()
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
setTimeout(fn, 9999)
assert.strictEqual(fn.mock.callCount(), 0)
assert.strictEqual(Date.now(), 0)
// Avanzamento del tempo
context.mock.timers.tick(9999)
assert.strictEqual(fn.mock.callCount(), 1)
assert.strictEqual(Date.now(), 9999)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('mocks setTimeout to be executed synchronously without having to actually wait for it', context => {
const fn = context.mock.fn()
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
setTimeout(fn, 9999)
assert.strictEqual(fn.mock.callCount(), 0)
assert.strictEqual(Date.now(), 0)
// Avanzamento del tempo
context.mock.timers.tick(9999)
assert.strictEqual(fn.mock.callCount(), 1)
assert.strictEqual(Date.now(), 9999)
})
Utilizzo di funzioni clear
Come accennato, tutte le funzioni clear
dei timer (clearTimeout
, clearInterval
e clearImmediate
) sono implicitamente mockate. Osserva questo esempio usando setTimeout
:
import assert from 'node:assert'
import { test } from 'node:test'
test('mocks setTimeout per essere eseguito sincronicamente senza dover effettivamente attendere', context => {
const fn = context.mock.fn()
// Opzionalmente scegli cosa mockare
context.mock.timers.enable({ apis: ['setTimeout'] })
const id = setTimeout(fn, 9999)
// Implicitamente mockato anche
clearTimeout(id)
context.mock.timers.tick(9999)
// Poiché quel setTimeout è stato cancellato, la funzione mock non verrà mai chiamata
assert.strictEqual(fn.mock.callCount(), 0)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('mocks setTimeout per essere eseguito sincronicamente senza dover effettivamente attendere', context => {
const fn = context.mock.fn()
// Opzionalmente scegli cosa mockare
context.mock.timers.enable({ apis: ['setTimeout'] })
const id = setTimeout(fn, 9999)
// Implicitamente mockato anche
clearTimeout(id)
context.mock.timers.tick(9999)
// Poiché quel setTimeout è stato cancellato, la funzione mock non verrà mai chiamata
assert.strictEqual(fn.mock.callCount(), 0)
})
Lavorare con i moduli timer di Node.js
Una volta abilitato il mocking dei timer, i moduli node:timers, node:timers/promises e i timer dal contesto globale di Node.js sono abilitati:
Nota: Le funzioni di de-strutturazione come import { setTimeout } from 'node:timers'
non sono attualmente supportate da questa API.
import assert from 'node:assert'
import { test } from 'node:test'
import nodeTimers from 'node:timers'
import nodeTimersPromises from 'node:timers/promises'
test('mocks setTimeout per essere eseguito sincronicamente senza dover effettivamente attendere', async context => {
const globalTimeoutObjectSpy = context.mock.fn()
const nodeTimerSpy = context.mock.fn()
const nodeTimerPromiseSpy = context.mock.fn()
// Opzionalmente scegli cosa mockare
context.mock.timers.enable({ apis: ['setTimeout'] })
setTimeout(globalTimeoutObjectSpy, 9999)
nodeTimers.setTimeout(nodeTimerSpy, 9999)
const promise = nodeTimersPromises.setTimeout(9999).then(nodeTimerPromiseSpy)
// Avanzamento nel tempo
context.mock.timers.tick(9999)
assert.strictEqual(globalTimeoutObjectSpy.mock.callCount(), 1)
assert.strictEqual(nodeTimerSpy.mock.callCount(), 1)
await promise
assert.strictEqual(nodeTimerPromiseSpy.mock.callCount(), 1)
})
const assert = require('node:assert')
const { test } = require('node:test')
const nodeTimers = require('node:timers')
const nodeTimersPromises = require('node:timers/promises')
test('mocks setTimeout per essere eseguito sincronicamente senza dover effettivamente attendere', async context => {
const globalTimeoutObjectSpy = context.mock.fn()
const nodeTimerSpy = context.mock.fn()
const nodeTimerPromiseSpy = context.mock.fn()
// Opzionalmente scegli cosa mockare
context.mock.timers.enable({ apis: ['setTimeout'] })
setTimeout(globalTimeoutObjectSpy, 9999)
nodeTimers.setTimeout(nodeTimerSpy, 9999)
const promise = nodeTimersPromises.setTimeout(9999).then(nodeTimerPromiseSpy)
// Avanzamento nel tempo
context.mock.timers.tick(9999)
assert.strictEqual(globalTimeoutObjectSpy.mock.callCount(), 1)
assert.strictEqual(nodeTimerSpy.mock.callCount(), 1)
await promise
assert.strictEqual(nodeTimerPromiseSpy.mock.callCount(), 1)
})
In Node.js, setInterval
da node:timers/promises è un AsyncGenerator
ed è anche supportato da questa API:
import assert from 'node:assert'
import { test } from 'node:test'
import nodeTimersPromises from 'node:timers/promises'
test("dovrebbe ticchettare cinque volte testando un caso d'uso reale", async context => {
context.mock.timers.enable({ apis: ['setInterval'] })
const expectedIterations = 3
const interval = 1000
const startedAt = Date.now()
async function run() {
const times = []
for await (const time of nodeTimersPromises.setInterval(interval, startedAt)) {
times.push(time)
if (times.length === expectedIterations) break
}
return times
}
const r = run()
context.mock.timers.tick(interval)
context.mock.timers.tick(interval)
context.mock.timers.tick(interval)
const timeResults = await r
assert.strictEqual(timeResults.length, expectedIterations)
for (let it = 1; it < expectedIterations; it++) {
assert.strictEqual(timeResults[it - 1], startedAt + interval * it)
}
})
const assert = require('node:assert')
const { test } = require('node:test')
const nodeTimersPromises = require('node:timers/promises')
test("dovrebbe ticchettare cinque volte testando un caso d'uso reale", async context => {
context.mock.timers.enable({ apis: ['setInterval'] })
const expectedIterations = 3
const interval = 1000
const startedAt = Date.now()
async function run() {
const times = []
for await (const time of nodeTimersPromises.setInterval(interval, startedAt)) {
times.push(time)
if (times.length === expectedIterations) break
}
return times
}
const r = run()
context.mock.timers.tick(interval)
context.mock.timers.tick(interval)
context.mock.timers.tick(interval)
const timeResults = await r
assert.strictEqual(timeResults.length, expectedIterations)
for (let it = 1; it < expectedIterations; it++) {
assert.strictEqual(timeResults[it - 1], startedAt + interval * it)
}
})
timers.runAll()
Aggiunto in: v20.4.0, v18.19.0
Attiva immediatamente tutti i timer simulati in sospeso. Se anche l'oggetto Date
è simulato, farà anche avanzare l'oggetto Date
all'ora del timer più lontano.
L'esempio seguente attiva immediatamente tutti i timer in sospeso, facendoli eseguire senza alcun ritardo.
import assert from 'node:assert'
import { test } from 'node:test'
test('runAll functions following the given order', context => {
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
const results = []
setTimeout(() => results.push(1), 9999)
// Notice that if both timers have the same timeout,
// the order of execution is guaranteed
setTimeout(() => results.push(3), 8888)
setTimeout(() => results.push(2), 8888)
assert.deepStrictEqual(results, [])
context.mock.timers.runAll()
assert.deepStrictEqual(results, [3, 2, 1])
// The Date object is also advanced to the furthest timer's time
assert.strictEqual(Date.now(), 9999)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('runAll functions following the given order', context => {
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
const results = []
setTimeout(() => results.push(1), 9999)
// Notice that if both timers have the same timeout,
// the order of execution is guaranteed
setTimeout(() => results.push(3), 8888)
setTimeout(() => results.push(2), 8888)
assert.deepStrictEqual(results, [])
context.mock.timers.runAll()
assert.deepStrictEqual(results, [3, 2, 1])
// The Date object is also advanced to the furthest timer's time
assert.strictEqual(Date.now(), 9999)
})
Nota: La funzione runAll()
è specificamente progettata per attivare i timer nel contesto della simulazione dei timer. Non ha alcun effetto sugli orologi di sistema in tempo reale o sui timer effettivi al di fuori dell'ambiente di simulazione.
timers.setTime(milliseconds)
Aggiunto in: v21.2.0, v20.11.0
Imposta il timestamp Unix corrente che verrà utilizzato come riferimento per tutti gli oggetti Date
simulati.
import assert from 'node:assert'
import { test } from 'node:test'
test('runAll functions following the given order', context => {
const now = Date.now()
const setTime = 1000
// Date.now is not mocked
assert.deepStrictEqual(Date.now(), now)
context.mock.timers.enable({ apis: ['Date'] })
context.mock.timers.setTime(setTime)
// Date.now is now 1000
assert.strictEqual(Date.now(), setTime)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('setTime replaces current time', context => {
const now = Date.now()
const setTime = 1000
// Date.now is not mocked
assert.deepStrictEqual(Date.now(), now)
context.mock.timers.enable({ apis: ['Date'] })
context.mock.timers.setTime(setTime)
// Date.now is now 1000
assert.strictEqual(Date.now(), setTime)
})
Date e Timer che lavorano insieme
Gli oggetti Date e timer sono dipendenti l'uno dall'altro. Se si utilizza setTime()
per passare l'ora corrente all'oggetto Date
simulato, i timer impostati con setTimeout
e setInterval
non saranno influenzati.
Tuttavia, il metodo tick
farà avanzare l'oggetto Date
simulato.
import assert from 'node:assert'
import { test } from 'node:test'
test('runAll functions following the given order', context => {
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
const results = []
setTimeout(() => results.push(1), 9999)
assert.deepStrictEqual(results, [])
context.mock.timers.setTime(12000)
assert.deepStrictEqual(results, [])
// The date is advanced but the timers don't tick
assert.strictEqual(Date.now(), 12000)
})
const assert = require('node:assert')
const { test } = require('node:test')
test('runAll functions following the given order', context => {
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] })
const results = []
setTimeout(() => results.push(1), 9999)
assert.deepStrictEqual(results, [])
context.mock.timers.setTime(12000)
assert.deepStrictEqual(results, [])
// The date is advanced but the timers don't tick
assert.strictEqual(Date.now(), 12000)
})
Classe: TestsStream
[Cronologia]
Versione | Modifiche |
---|---|
v20.0.0, v19.9.0, v18.17.0 | aggiunto tipo agli eventi test:pass e test:fail per quando il test è una suite. |
v18.9.0, v16.19.0 | Aggiunto in: v18.9.0, v16.19.0 |
- Estende <Readable>
Una chiamata riuscita al metodo run()
restituirà un nuovo oggetto <TestsStream>, trasmettendo in streaming una serie di eventi che rappresentano l'esecuzione dei test. TestsStream
emetterà eventi, nell'ordine della definizione dei test.
Alcuni eventi sono garantiti per essere emessi nello stesso ordine in cui i test sono definiti, mentre altri sono emessi nell'ordine in cui i test vengono eseguiti.
Evento: 'test:coverage'
data
<Oggetto>summary
<Oggetto> Un oggetto contenente il report di copertura.files
<Array> Una matrice di report di copertura per singoli file. Ogni report è un oggetto con lo schema seguente:path
<stringa> Il percorso assoluto del file.totalLineCount
<numero> Il numero totale di righe.totalBranchCount
<numero> Il numero totale di rami.totalFunctionCount
<numero> Il numero totale di funzioni.coveredLineCount
<numero> Il numero di righe coperte.coveredBranchCount
<numero> Il numero di rami coperti.coveredFunctionCount
<numero> Il numero di funzioni coperte.coveredLinePercent
<numero> La percentuale di righe coperte.coveredBranchPercent
<numero> La percentuale di rami coperti.coveredFunctionPercent
<numero> La percentuale di funzioni coperte.functions
<Array> Una matrice di funzioni che rappresentano la copertura delle funzioni.name
<stringa> Il nome della funzione.line
<numero> Il numero di riga in cui è definita la funzione.count
<numero> Il numero di volte in cui è stata chiamata la funzione.branches
<Array> Una matrice di rami che rappresentano la copertura dei rami.line
<numero> Il numero di riga in cui è definito il ramo.count
<numero> Il numero di volte in cui è stato percorso il ramo.lines
<Array> Una matrice di righe che rappresentano i numeri di riga e il numero di volte in cui sono state coperte.line
<numero> Il numero di riga.count
<numero> Il numero di volte in cui è stata coperta la riga.thresholds
<Oggetto> Un oggetto contenente se la copertura per ogni tipo di copertura è soddisfatta o meno.function
<numero> La soglia di copertura della funzione.branch
<numero> La soglia di copertura del ramo.line
<numero> La soglia di copertura della riga.totals
<Oggetto> Un oggetto contenente un riepilogo della copertura per tutti i file.totalLineCount
<numero> Il numero totale di righe.totalBranchCount
<numero> Il numero totale di rami.totalFunctionCount
<numero> Il numero totale di funzioni.coveredLineCount
<numero> Il numero di righe coperte.coveredBranchCount
<numero> Il numero di rami coperti.coveredFunctionCount
<numero> Il numero di funzioni coperte.coveredLinePercent
<numero> La percentuale di righe coperte.coveredBranchPercent
<numero> La percentuale di rami coperti.coveredFunctionPercent
<numero> La percentuale di funzioni coperte.workingDirectory
<stringa> La directory di lavoro quando è iniziata la copertura del codice. Questo è utile per visualizzare i nomi dei percorsi relativi nel caso in cui i test abbiano modificato la directory di lavoro del processo Node.js.nesting
<numero> Il livello di annidamento del test.
Emesso quando la copertura del codice è abilitata e tutti i test sono completati.
Evento: 'test:complete'
data
<Oggetto>column
<numero> | <undefined> Il numero di colonna in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.details
<Oggetto> Metadati di esecuzione aggiuntivi.passed
<booleano> Se il test è riuscito o meno.duration_ms
<numero> La durata del test in millisecondi.error
<Errore> | <undefined> Un errore che racchiude l'errore generato dal test se non è riuscito.cause
<Errore> L'errore effettivo generato dal test.type
<stringa> | <undefined> Il tipo di test, utilizzato per indicare se si tratta di una suite.file
<stringa> | <undefined> Il percorso del file di test,undefined
se il test è stato eseguito tramite REPL.line
<numero> | <undefined> Il numero di riga in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.name
<stringa> Il nome del test.nesting
<numero> Il livello di annidamento del test.testNumber
<numero> Il numero ordinale del test.todo
<stringa> | <booleano> | <undefined> Presente se viene chiamatacontext.todo
skip
<stringa> | <booleano> | <undefined> Presente se viene chiamatacontext.skip
Emesso quando un test completa la sua esecuzione. Questo evento non viene emesso nello stesso ordine in cui i test sono definiti. Gli eventi corrispondenti ordinati per dichiarazione sono 'test:pass'
e 'test:fail'
.
Evento: 'test:dequeue'
data
<Oggetto>column
<numero> | <undefined> Il numero di colonna in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.file
<stringa> | <undefined> Il percorso del file di test,undefined
se il test è stato eseguito tramite REPL.line
<numero> | <undefined> Il numero di riga in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.name
<stringa> Il nome del test.nesting
<numero> Il livello di annidamento del test.
Emesso quando un test viene estratto dalla coda, subito prima della sua esecuzione. Non è garantito che questo evento venga emesso nello stesso ordine in cui i test sono definiti. L'evento corrispondente ordinato per dichiarazione è 'test:start'
.
Evento: 'test:diagnostic'
data
<Oggetto>column
<numero> | <undefined> Il numero di colonna in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.file
<stringa> | <undefined> Il percorso del file di test,undefined
se il test è stato eseguito tramite REPL.line
<numero> | <undefined> Il numero di riga in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.message
<stringa> Il messaggio diagnostico.nesting
<numero> Il livello di annidamento del test.
Emesso quando viene chiamato context.diagnostic
. Questo evento viene emesso nello stesso ordine in cui i test sono definiti.
Evento: 'test:enqueue'
data
<Object>column
<number> | <undefined> Il numero di colonna in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.file
<string> | <undefined> Il percorso del file di test,undefined
se il test è stato eseguito tramite REPL.line
<number> | <undefined> Il numero di riga in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.name
<string> Il nome del test.nesting
<number> Il livello di annidamento del test.
Emesso quando un test viene messo in coda per l'esecuzione.
Evento: 'test:fail'
data
<Object>column
<number> | <undefined> Il numero di colonna in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.details
<Object> Metadati di esecuzione aggiuntivi.duration_ms
<number> La durata del test in millisecondi.error
<Error> Un errore che racchiude l'errore generato dal test.cause
<Error> L'errore effettivamente generato dal test.type
<string> | <undefined> Il tipo di test, utilizzato per indicare se si tratta di una suite.file
<string> | <undefined> Il percorso del file di test,undefined
se il test è stato eseguito tramite REPL.line
<number> | <undefined> Il numero di riga in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.name
<string> Il nome del test.nesting
<number> Il livello di annidamento del test.testNumber
<number> Il numero ordinale del test.todo
<string> | <boolean> | <undefined> Presente se viene chiamatocontext.todo
skip
<string> | <boolean> | <undefined> Presente se viene chiamatocontext.skip
Emesso quando un test fallisce. Questo evento viene garantito essere emesso nello stesso ordine in cui i test sono definiti. L'evento corrispondente ordinato per esecuzione è 'test:complete'
.
Evento: 'test:pass'
data
<Oggetto>column
<numero> | <undefined> Il numero di colonna in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.details
<Oggetto> Metadati di esecuzione aggiuntivi.duration_ms
<numero> La durata del test in millisecondi.type
<stringa> | <undefined> Il tipo di test, utilizzato per indicare se si tratta di una suite.file
<stringa> | <undefined> Il percorso del file di test,undefined
se il test è stato eseguito tramite REPL.line
<numero> | <undefined> Il numero di riga in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.name
<stringa> Il nome del test.nesting
<numero> Il livello di annidamento del test.testNumber
<numero> Il numero ordinale del test.todo
<stringa> | <booleano> | <undefined> Presente se viene chiamatocontext.todo
skip
<stringa> | <booleano> | <undefined> Presente se viene chiamatocontext.skip
Emesso quando un test viene superato. Questo evento viene garantito per essere emesso nello stesso ordine in cui i test sono definiti. L'evento corrispondente ordinato per esecuzione è 'test:complete'
.
Evento: 'test:plan'
data
<Oggetto>column
<numero> | <undefined> Il numero di colonna in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.file
<stringa> | <undefined> Il percorso del file di test,undefined
se il test è stato eseguito tramite REPL.line
<numero> | <undefined> Il numero di riga in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.nesting
<numero> Il livello di annidamento del test.count
<numero> Il numero di sottotest eseguiti.
Emetto quando tutti i sottotest sono completati per un dato test. Questo evento è garantito di essere emesso nello stesso ordine in cui i test sono definiti.
Evento: 'test:start'
data
<Oggetto>column
<numero> | <undefined> Il numero di colonna in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.file
<stringa> | <undefined> Il percorso del file di test,undefined
se il test è stato eseguito tramite REPL.line
<numero> | <undefined> Il numero di riga in cui è definito il test, oundefined
se il test è stato eseguito tramite REPL.name
<stringa> Il nome del test.nesting
<numero> Il livello di annidamento del test.
Emetto quando un test inizia a segnalare il proprio stato e quello dei suoi sottotest. Questo evento è garantito di essere emesso nello stesso ordine in cui i test sono definiti. L'evento corrispondente ordinato di esecuzione è 'test:dequeue'
.
Evento: 'test:stderr'
data
<Oggetto>
Emesso quando un test in esecuzione scrive su stderr
. Questo evento viene emesso solo se viene passato il flag --test
. Non è garantito che questo evento venga emesso nello stesso ordine in cui i test sono definiti.
Evento: 'test:stdout'
data
<Oggetto>
Emesso quando un test in esecuzione scrive su stdout
. Questo evento viene emesso solo se viene passato il flag --test
. Non è garantito che questo evento venga emesso nello stesso ordine in cui i test sono definiti.
Evento: 'test:summary'
data
<Oggetto>counts
<Oggetto> Un oggetto contenente il conteggio di vari risultati dei test.cancelled
<numero> Il numero totale di test annullati.failed
<numero> Il numero totale di test falliti.passed
<numero> Il numero totale di test superati.skipped
<numero> Il numero totale di test saltati.suites
<numero> Il numero totale di suite eseguite.tests
<numero> Il numero totale di test eseguiti, escluse le suite.todo
<numero> Il numero totale di test TODO.topLevel
<numero> Il numero totale di test e suite di livello superiore.duration_ms
<numero> La durata dell'esecuzione del test in millisecondi.file
<stringa> | <undefined> Il percorso del file di test che ha generato il riepilogo. Se il riepilogo corrisponde a più file, questo valore èundefined
.success
<booleano> Indica se l'esecuzione del test è considerata riuscita o meno. Se si verifica una condizione di errore, come un test non riuscito o una soglia di copertura non soddisfatta, questo valore verrà impostato sufalse
.
Emesso al completamento di un'esecuzione di test. Questo evento contiene metriche relative all'esecuzione del test completata ed è utile per determinare se un'esecuzione del test è riuscita o meno. Se viene utilizzato l'isolamento del test a livello di processo, viene generato un evento 'test:summary'
per ogni file di test oltre a un riepilogo cumulativo finale.
Evento: 'test:watch:drained'
Emesso quando non ci sono più test in coda per l'esecuzione in modalità watch.
Classe: TestContext
[Cronologia]
Versione | Modifiche |
---|---|
v20.1.0, v18.17.0 | Aggiunta la funzione before a TestContext. |
v18.0.0, v16.17.0 | Aggiunta in: v18.0.0, v16.17.0 |
Un'istanza di TestContext
viene passata a ciascuna funzione di test per interagire con il test runner. Tuttavia, il costruttore TestContext
non è esposto come parte dell'API.
context.before([fn][, options])
Aggiunto in: v20.1.0, v18.17.0
fn
<Function> | <AsyncFunction> La funzione hook. Il primo argomento di questa funzione è un oggettoTestContext
. Se l'hook utilizza callback, la funzione callback viene passata come secondo argomento. Default: Una funzione no-op.options
<Object> Opzioni di configurazione per l'hook. Sono supportate le seguenti proprietà:signal
<AbortSignal> Consente di interrompere un hook in corso.timeout
<number> Un numero di millisecondi dopo il quale l'hook fallirà. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:Infinity
.
Questa funzione viene utilizzata per creare un hook che viene eseguito prima del sottotest del test corrente.
context.beforeEach([fn][, options])
Aggiunto in: v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La funzione hook. Il primo argomento di questa funzione è un oggettoTestContext
. Se l'hook utilizza callback, la funzione callback viene passata come secondo argomento. Default: Una funzione no-op.options
<Object> Opzioni di configurazione per l'hook. Sono supportate le seguenti proprietà:signal
<AbortSignal> Consente di interrompere un hook in corso.timeout
<number> Un numero di millisecondi dopo il quale l'hook fallirà. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:Infinity
.
Questa funzione viene utilizzata per creare un hook che viene eseguito prima di ogni sottotest del test corrente.
test('test di livello superiore', async t => {
t.beforeEach(t => t.diagnostic(`in procinto di eseguire ${t.name}`))
await t.test('Questo è un sottotest', t => {
assert.ok('qualche asserzione rilevante qui')
})
})
context.after([fn][, options])
Aggiunto in: v19.3.0, v18.13.0
fn
<Function> | <AsyncFunction> La funzione hook. Il primo argomento di questa funzione è un oggettoTestContext
. Se l'hook utilizza callback, la funzione callback viene passata come secondo argomento. Default: Una funzione no-op.options
<Object> Opzioni di configurazione per l'hook. Sono supportate le seguenti proprietà:signal
<AbortSignal> Consente di interrompere un hook in corso.timeout
<number> Un numero di millisecondi dopo il quale l'hook fallirà. Se non specificato, i subtest ereditano questo valore dal loro padre. Default:Infinity
.
Questa funzione viene utilizzata per creare un hook che viene eseguito dopo la fine del test corrente.
test('top level test', async t => {
t.after(t => t.diagnostic(`finished running ${t.name}`))
assert.ok('some relevant assertion here')
})
context.afterEach([fn][, options])
Aggiunto in: v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La funzione hook. Il primo argomento di questa funzione è un oggettoTestContext
. Se l'hook utilizza callback, la funzione callback viene passata come secondo argomento. Default: Una funzione no-op.options
<Object> Opzioni di configurazione per l'hook. Sono supportate le seguenti proprietà:signal
<AbortSignal> Consente di interrompere un hook in corso.timeout
<number> Un numero di millisecondi dopo il quale l'hook fallirà. Se non specificato, i subtest ereditano questo valore dal loro padre. Default:Infinity
.
Questa funzione viene utilizzata per creare un hook che viene eseguito dopo ogni subtest del test corrente.
test('top level test', async t => {
t.afterEach(t => t.diagnostic(`finished running ${t.name}`))
await t.test('This is a subtest', t => {
assert.ok('some relevant assertion here')
})
})
context.assert
Aggiunto in: v22.2.0, v20.15.0
Un oggetto contenente metodi di asserzione legati a context
. Le funzioni di livello superiore del modulo node:assert
sono esposte qui allo scopo di creare piani di test.
test('test', t => {
t.plan(1)
t.assert.strictEqual(true, true)
})
context.assert.snapshot(value[, options])
Aggiunto in: v22.3.0
[Stabile: 1 - Sperimentale]
Stabile: 1 Stabilità: 1.0 - Sviluppo iniziale
value
<any> Un valore da serializzare in una stringa. Se Node.js è stato avviato con il flag--test-update-snapshots
, il valore serializzato viene scritto nel file snapshot. Altrimenti, il valore serializzato viene confrontato con il valore corrispondente nel file snapshot esistente.options
<Object> Opzioni di configurazione facoltative. Sono supportate le seguenti proprietà:serializers
<Array> Una matrice di funzioni sincrone utilizzate per serializzarevalue
in una stringa.value
viene passato come unico argomento alla prima funzione serializer. Il valore di ritorno di ogni serializer viene passato come input al serializer successivo. Una volta che tutti i serializer sono stati eseguiti, il valore risultante viene convertito in una stringa. Predefinito: Se non vengono forniti serializer, vengono utilizzati i serializer predefiniti del test runner.
Questa funzione implementa asserzioni per i test snapshot.
test('snapshot test con serializzazione predefinita', t => {
t.assert.snapshot({ value1: 1, value2: 2 })
})
test('snapshot test con serializzazione personalizzata', t => {
t.assert.snapshot(
{ value3: 3, value4: 4 },
{
serializers: [value => JSON.stringify(value)],
}
)
})
context.diagnostic(message)
Aggiunto in: v18.0.0, v16.17.0
message
<string> Messaggio da segnalare.
Questa funzione viene utilizzata per scrivere diagnosi nell'output. Qualsiasi informazione diagnostica è inclusa alla fine dei risultati del test. Questa funzione non restituisce alcun valore.
test('top level test', t => {
t.diagnostic('Un messaggio diagnostico')
})
context.filePath
Aggiunto in: v22.6.0, v20.16.0
Il percorso assoluto del file di test che ha creato il test corrente. Se un file di test importa moduli aggiuntivi che generano test, i test importati restituiranno il percorso del file di test principale.
context.fullName
Aggiunto in: v22.3.0
Il nome del test e di ciascuno dei suoi antenati, separati da \>
.
context.name
Aggiunto in: v18.8.0, v16.18.0
Il nome del test.
context.plan(count)
[Cronologia]
Versione | Modifiche |
---|---|
v23.4.0 | Questa funzione non è più sperimentale. |
v22.2.0, v20.15.0 | Aggiunto in: v22.2.0, v20.15.0 |
count
<number> Il numero di asserzioni e sottotest che si prevede verranno eseguiti.
Questa funzione viene utilizzata per impostare il numero di asserzioni e sottotest che si prevede verranno eseguiti all'interno del test. Se il numero di asserzioni e sottotest eseguiti non corrisponde al conteggio previsto, il test avrà esito negativo.
test('top level test', (t) => {
t.plan(2);
t.assert.ok('un'asserzione pertinente qui');
t.test('sottotest', () => {});
});
Quando si lavora con codice asincrono, la funzione plan
può essere utilizzata per garantire che venga eseguito il numero corretto di asserzioni:
test('pianificazione con stream', (t, done) => {
function* generate() {
yield 'a'
yield 'b'
yield 'c'
}
const expected = ['a', 'b', 'c']
t.plan(expected.length)
const stream = Readable.from(generate())
stream.on('data', chunk => {
t.assert.strictEqual(chunk, expected.shift())
})
stream.on('end', () => {
done()
})
})
context.runOnly(shouldRunOnlyTests)
Aggiunto in: v18.0.0, v16.17.0
shouldRunOnlyTests
<boolean> Indica se eseguire solo i test con l'opzioneonly
.
Se shouldRunOnlyTests
è truthy, il contesto del test eseguirà solo i test che hanno impostato l'opzione only
. Altrimenti, vengono eseguiti tutti i test. Se Node.js non è stato avviato con l'opzione della riga di comando --test-only
, questa funzione è una no-op.
test('test di livello superiore', t => {
// Il contesto del test può essere impostato per eseguire sottotest con l'opzione 'only'.
t.runOnly(true)
return Promise.all([
t.test('questo sottotest è ora saltato'),
t.test('questo sottotest viene eseguito', { only: true }),
])
})
context.signal
Aggiunto in: v18.7.0, v16.17.0
- Tipo: <AbortSignal>
Può essere utilizzato per interrompere i sottocompiti di test quando il test è stato interrotto.
test('test di livello superiore', async t => {
await fetch('some/uri', { signal: t.signal })
})
context.skip([message])
Aggiunto in: v18.0.0, v16.17.0
message
<string> Messaggio di skip opzionale.
Questa funzione fa sì che l'output del test indichi il test come saltato. Se viene fornito message
, è incluso nell'output. La chiamata a skip()
non termina l'esecuzione della funzione di test. Questa funzione non restituisce alcun valore.
test('test di livello superiore', t => {
// Assicurarsi di restituire anche qui se il test contiene logica aggiuntiva.
t.skip('questo è saltato')
})
context.todo([message])
Aggiunto in: v18.0.0, v16.17.0
message
<string> MessaggioTODO
opzionale.
Questa funzione aggiunge una direttiva TODO
all'output del test. Se viene fornito message
, è incluso nell'output. La chiamata a todo()
non termina l'esecuzione della funzione di test. Questa funzione non restituisce alcun valore.
test('test di livello superiore', t => {
// Questo test è contrassegnato come `TODO`
t.todo('questo è un todo')
})
context.test([name][, options][, fn])
[Cronologia]
Versione | Modifiche |
---|---|
v18.8.0, v16.18.0 | Aggiunta opzione signal . |
v18.7.0, v16.17.0 | Aggiunta opzione timeout . |
v18.0.0, v16.17.0 | Aggiunto in: v18.0.0, v16.17.0 |
name
<string> Il nome del sottotest, visualizzato nella reportistica dei risultati del test. Default: La proprietàname
difn
, o'\<anonymous\>'
sefn
non ha un nome.options
<Object> Opzioni di configurazione per il sottotest. Sono supportate le seguenti proprietà:concurrency
<number> | <boolean> | <null> Se viene fornito un numero, tanti test verranno eseguiti in parallelo nel thread dell'applicazione. Setrue
, eseguirà tutti i sottotest in parallelo. Sefalse
, eseguirà un solo test alla volta. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:null
.only
<boolean> Se vero, e il contesto del test è configurato per eseguire solo i testonly
, allora questo test verrà eseguito. Altrimenti, il test viene saltato. Default:false
.signal
<AbortSignal> Permette di abortire un test in corso.skip
<boolean> | <string> Se vero, il test viene saltato. Se viene fornita una stringa, quella stringa viene visualizzata nei risultati del test come motivo per cui il test è stato saltato. Default:false
.todo
<boolean> | <string> Se vero, il test è contrassegnato comeTODO
. Se viene fornita una stringa, quella stringa viene visualizzata nei risultati del test come motivo per cui il test èTODO
. Default:false
.timeout
<number> Un numero di millisecondi dopo il quale il test fallirà. Se non specificato, i sottotest ereditano questo valore dal loro padre. Default:Infinity
.plan
<number> Il numero di asserzioni e sottotest previsti per essere eseguiti nel test. Se il numero di asserzioni eseguite nel test non corrisponde al numero specificato nel piano, il test fallirà. Default:undefined
.
fn
<Function> | <AsyncFunction> La funzione sottoposta a test. Il primo argomento di questa funzione è un oggettoTestContext
. Se il test utilizza callback, la funzione di callback viene passata come secondo argomento. Default: Una funzione no-op.Restituisce: <Promise> Risolta con
undefined
una volta completato il test.
Questa funzione viene utilizzata per creare sottotest all'interno del test corrente. Questa funzione si comporta allo stesso modo della funzione di livello superiore test()
.
test('test di livello superiore', async t => {
await t.test('Questo è un sottotest', { only: false, skip: false, concurrency: 1, todo: false, plan: 1 }, t => {
t.assert.ok("un'asserzione rilevante qui")
})
})
Classe: SuiteContext
Aggiunto in: v18.7.0, v16.17.0
Un'istanza di SuiteContext
viene passata a ciascuna funzione suite per interagire con il test runner. Tuttavia, il costruttore SuiteContext
non è esposto come parte dell'API.
context.filePath
Aggiunto in: v22.6.0
Il percorso assoluto del file di test che ha creato la suite corrente. Se un file di test importa moduli aggiuntivi che generano suite, le suite importate restituiranno il percorso del file di test principale.
context.name
Aggiunto in: v18.8.0, v16.18.0
Il nome della suite.
context.signal
Aggiunto in: v18.7.0, v16.17.0
- Tipo: <AbortSignal>
Può essere usato per interrompere i sottocompiti del test quando il test è stato interrotto.