Lanceur de tests
[Historique]
Version | Modifications |
---|---|
v20.0.0 | Le lanceur de tests est maintenant stable. |
v18.0.0, v16.17.0 | Ajouté dans : v18.0.0, v16.17.0 |
[Stable: 2 - Stable]
Stable: 2 Stability: 2 - Stable
Code source : lib/test.js
Le module node:test
facilite la création de tests JavaScript. Pour y accéder :
import test from 'node:test';
const test = require('node:test');
Ce module est uniquement disponible sous le schéma node:
.
Les tests créés via le module test
consistent en une seule fonction qui est traitée de l’une des trois manières suivantes :
L’exemple suivant illustre la façon dont les tests sont écrits à l’aide du module test
.
test('test synchrone réussi', (t) => {
// Ce test réussit car il ne lève pas d'exception.
assert.strictEqual(1, 1);
});
test('test synchrone échoué', (t) => {
// Ce test échoue car il lève une exception.
assert.strictEqual(1, 2);
});
test('test asynchrone réussi', async (t) => {
// Ce test réussit car la Promise renvoyée par la fonction asynchrone
// est résolue et non rejetée.
assert.strictEqual(1, 1);
});
test('test asynchrone échoué', async (t) => {
// Ce test échoue car la Promise renvoyée par la fonction asynchrone
// est rejetée.
assert.strictEqual(1, 2);
});
test('test échoué utilisant des Promises', (t) => {
// Les Promises peuvent également être utilisées directement.
return new Promise((resolve, reject) => {
setImmediate(() => {
reject(new Error('cela entraînera l'échec du test'));
});
});
});
test('test de réussite de rappel', (t, done) => {
// done() est la fonction de rappel. Lorsque setImmediate() s'exécute, il appelle
// done() sans arguments.
setImmediate(done);
});
test('test d'échec de rappel', (t, done) => {
// Lorsque setImmediate() s'exécute, done() est appelé avec un objet Error et
// le test échoue.
setImmediate(() => {
done(new Error('échec de rappel'));
});
});
Si des tests échouent, le code de sortie du processus est défini sur 1
.
Sous-tests
La méthode test()
du contexte de test permet de créer des sous-tests. Elle vous permet de structurer vos tests de manière hiérarchique, où vous pouvez créer des tests imbriqués dans un test plus grand. Cette méthode se comporte de manière identique à la fonction test()
de niveau supérieur. L'exemple suivant illustre la création d'un test de niveau supérieur avec deux sous-tests.
test('test de niveau supérieur', async (t) => {
await t.test('sous-test 1', (t) => {
assert.strictEqual(1, 1);
});
await t.test('sous-test 2', (t) => {
assert.strictEqual(2, 2);
});
});
Dans cet exemple, await
est utilisé pour garantir que les deux sous-tests sont terminés. Ceci est nécessaire car les tests n'attendent pas la fin de leurs sous-tests, contrairement aux tests créés dans les suites. Tous les sous-tests qui sont toujours en cours d'exécution lorsque leur parent se termine sont annulés et traités comme des échecs. Tout échec de sous-test entraîne l'échec du test parent.
Ignorer des tests
Les tests individuels peuvent être ignorés en passant l'option skip
au test, ou en appelant la méthode skip()
du contexte de test comme indiqué dans l'exemple suivant.
// L'option skip est utilisée, mais aucun message n'est fourni.
test('option skip', { skip: true }, (t) => {
// Ce code n'est jamais exécuté.
});
// L'option skip est utilisée et un message est fourni.
test('option skip avec message', { skip: 'ceci est ignoré' }, (t) => {
// Ce code n'est jamais exécuté.
});
test('méthode skip()', (t) => {
// Assurez-vous de retourner ici également si le test contient une logique supplémentaire.
t.skip();
});
test('méthode skip() avec message', (t) => {
// Assurez-vous de retourner ici également si le test contient une logique supplémentaire.
t.skip('ceci est ignoré');
});
Tests TODO
Les tests individuels peuvent être marqués comme instables ou incomplets en passant l'option todo
au test, ou en appelant la méthode todo()
du contexte de test, comme indiqué dans l'exemple suivant. Ces tests représentent une implémentation en attente ou un bogue qui doit être corrigé. Les tests TODO sont exécutés, mais ne sont pas traités comme des échecs de test et n'affectent donc pas le code de sortie du processus. Si un test est marqué à la fois comme TODO et ignoré, l'option TODO est ignorée.
// L'option todo est utilisée, mais aucun message n'est fourni.
test('option todo', { todo: true }, (t) => {
// Ce code est exécuté, mais n'est pas traité comme un échec.
throw new Error('ceci ne fait pas échouer le test');
});
// L'option todo est utilisée et un message est fourni.
test('option todo avec message', { todo: 'ceci est un test todo' }, (t) => {
// Ce code est exécuté.
});
test('méthode todo()', (t) => {
t.todo();
});
test('méthode todo() avec message', (t) => {
t.todo('ceci est un test todo et n\'est pas traité comme un échec');
throw new Error('ceci ne fait pas échouer le test');
});
Alias describe()
et it()
Les suites et les tests peuvent également être écrits à l'aide des fonctions describe()
et it()
. describe()
est un alias pour suite()
, et it()
est un alias pour test()
.
describe('Une chose', () => {
it('devrait fonctionner', () => {
assert.strictEqual(1, 1);
});
it('devrait être ok', () => {
assert.strictEqual(2, 2);
});
describe('une chose imbriquée', () => {
it('devrait fonctionner', () => {
assert.strictEqual(3, 3);
});
});
});
describe()
et it()
sont importés depuis le module node:test
.
import { describe, it } from 'node:test';
const { describe, it } = require('node:test');
Tests only
Si Node.js est démarré avec l'option de ligne de commande --test-only
, ou si l'isolation des tests est désactivée, il est possible de passer outre tous les tests à l'exception d'un sous-ensemble sélectionné en passant l'option only
aux tests qui doivent être exécutés. Lorsqu'un test avec l'option only
est défini, tous les sous-tests sont également exécutés. Si une suite a l'option only
définie, tous les tests dans la suite sont exécutés, à moins qu'elle n'ait des descendants avec l'option only
définie, auquel cas seuls ces tests sont exécutés.
Lors de l'utilisation de sous-tests dans un test()
/it()
, il est nécessaire de marquer tous les tests ancêtres avec l'option only
pour exécuter uniquement un sous-ensemble sélectionné de tests.
La méthode runOnly()
du contexte de test peut être utilisée pour implémenter le même comportement au niveau du sous-test. Les tests qui ne sont pas exécutés sont omis de la sortie de l'exécuteur de tests.
// Supposons que Node.js est exécuté avec l'option de ligne de commande --test-only.
// L'option 'only' de la suite est définie, donc ces tests sont exécutés.
test('ce test est exécuté', { only: true }, async (t) => {
// Dans ce test, tous les sous-tests sont exécutés par défaut.
await t.test('exécution du sous-test');
// Le contexte de test peut être mis à jour pour exécuter les sous-tests avec l'option 'only'.
t.runOnly(true);
await t.test('ce sous-test est maintenant ignoré');
await t.test('ce sous-test est exécuté', { only: true });
// Rebasculer le contexte pour exécuter tous les tests.
t.runOnly(false);
await t.test('ce sous-test est maintenant exécuté');
// Ne pas exécuter explicitement ces tests.
await t.test('sous-test ignoré 3', { only: false });
await t.test('sous-test ignoré 4', { skip: true });
});
// L'option 'only' n'est pas définie, donc ce test est ignoré.
test('ce test n'est pas exécuté', () => {
// Ce code n'est pas exécuté.
throw new Error('fail');
});
describe('une suite', () => {
// L'option 'only' est définie, donc ce test est exécuté.
it('ce test est exécuté', { only: true }, () => {
// Ce code est exécuté.
});
it('ce test n'est pas exécuté', () => {
// Ce code n'est pas exécuté.
throw new Error('fail');
});
});
describe.only('une suite', () => {
// L'option 'only' est définie, donc ce test est exécuté.
it('ce test est exécuté', () => {
// Ce code est exécuté.
});
it('ce test est exécuté', () => {
// Ce code est exécuté.
});
});
Filtrer les tests par nom
L'option de ligne de commande --test-name-pattern
peut être utilisée pour exécuter uniquement les tests dont le nom correspond au modèle fourni, et l'option --test-skip-pattern
peut être utilisée pour ignorer les tests dont le nom correspond au modèle fourni. Les modèles de noms de test sont interprétés comme des expressions régulières JavaScript. Les options --test-name-pattern
et --test-skip-pattern
peuvent être spécifiées plusieurs fois afin d'exécuter des tests imbriqués. Pour chaque test exécuté, tous les hooks de test correspondants, tels que beforeEach()
, sont également exécutés. Les tests qui ne sont pas exécutés sont omis de la sortie de l'exécuteur de tests.
Étant donné le fichier de test suivant, le démarrage de Node.js avec l'option --test-name-pattern="test [1-3]"
entraînerait l'exécution de test 1
, test 2
et test 3
par l'exécuteur de tests. Si test 1
ne correspond pas au modèle de nom de test, ses sous-tests ne s'exécuteraient pas, bien qu'ils correspondent au modèle. Le même ensemble de tests pourrait également être exécuté en passant --test-name-pattern
plusieurs fois (par exemple, --test-name-pattern="test 1"
, --test-name-pattern="test 2"
, etc.).
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');
});
Les modèles de noms de test peuvent également être spécifiés à l'aide de littéraux d'expression régulière. Cela permet d'utiliser les drapeaux d'expression régulière. Dans l'exemple précédent, le démarrage de Node.js avec --test-name-pattern="/test [4-5]/i"
(ou --test-skip-pattern="/test [4-5]/i"
) correspondrait à Test 4
et Test 5
car le modèle est insensible à la casse.
Pour correspondre à un seul test avec un modèle, vous pouvez le préfixer avec tous les noms de ses tests ancêtres séparés par un espace, pour vous assurer qu'il est unique. Par exemple, étant donné le fichier de test suivant :
describe('test 1', (t) => {
it('some test');
});
describe('test 2', (t) => {
it('some test');
});
Le démarrage de Node.js avec --test-name-pattern="test 1 some test"
ne correspondrait qu'à some test
dans test 1
.
Les modèles de noms de test ne modifient pas l'ensemble des fichiers que l'exécuteur de tests exécute.
Si --test-name-pattern
et --test-skip-pattern
sont tous les deux fournis, les tests doivent satisfaire aux deux exigences pour être exécutés.
Activité asynchrone superflue
Une fois qu'une fonction de test a fini de s'exécuter, les résultats sont rapportés aussi rapidement que possible tout en conservant l'ordre des tests. Cependant, il est possible que la fonction de test génère une activité asynchrone qui lui survive. L'exécuteur de test gère ce type d'activité, mais ne retarde pas le rapport des résultats du test pour la prendre en compte.
Dans l'exemple suivant, un test se termine avec deux opérations setImmediate()
toujours en suspens. La première setImmediate()
tente de créer un nouveau sous-test. Étant donné que le test parent est déjà terminé et a affiché ses résultats, le nouveau sous-test est immédiatement marqué comme ayant échoué, et rapporté ultérieurement au <TestsStream>.
La deuxième setImmediate()
crée un événement uncaughtException
. Les événements uncaughtException
et unhandledRejection
provenant d'un test terminé sont marqués comme ayant échoué par le module test
et rapportés comme avertissements de diagnostic au niveau supérieur par le <TestsStream>.
test('un test qui crée une activité asynchrone', (t) => {
setImmediate(() => {
t.test('sous-test créé trop tard', (t) => {
throw new Error('erreur1');
});
});
setImmediate(() => {
throw new Error('erreur2');
});
// Le test se termine après cette ligne.
});
Mode Surveillance
Ajouté dans : v19.2.0, v18.13.0
[Stable: 1 - Expérimental]
Stable: 1 Stabilité : 1 - Expérimental
L'exécuteur de tests Node.js prend en charge l'exécution en mode surveillance en passant l'indicateur --watch
:
node --test --watch
En mode surveillance, l'exécuteur de tests surveillera les modifications apportées aux fichiers de test et à leurs dépendances. Lorsqu'une modification est détectée, l'exécuteur de tests réexécutera les tests affectés par la modification. L'exécuteur de tests continuera à s'exécuter jusqu'à ce que le processus soit terminé.
Exécution des tests à partir de la ligne de commande
L'exécuteur de tests Node.js peut être invoqué à partir de la ligne de commande en passant l'indicateur --test
:
node --test
Par défaut, Node.js exécutera tous les fichiers correspondant à ces modèles :
**/*.test.{cjs,mjs,js}
**/*-test.{cjs,mjs,js}
**/*_test.{cjs,mjs,js}
**/test-*.{cjs,mjs,js}
**/test.{cjs,mjs,js}
**/test/**/*.{cjs,mjs,js}
Lorsque --experimental-strip-types
est fourni, les modèles supplémentaires suivants sont mis en correspondance :
**/*.test.{cts,mts,ts}
**/*-test.{cts,mts,ts}
**/*_test.{cts,mts,ts}
**/test-*.{cts,mts,ts}
**/test.{cts,mts,ts}
**/test/**/*.{cts,mts,ts}
Alternativement, un ou plusieurs modèles glob peuvent être fournis comme argument(s) final(aux) à la commande Node.js, comme indiqué ci-dessous. Les modèles glob suivent le comportement de glob(7)
. Les modèles glob doivent être placés entre guillemets doubles sur la ligne de commande pour éviter l'expansion du shell, ce qui peut réduire la portabilité entre les systèmes.
node --test "**/*.test.js" "**/*.spec.js"
Les fichiers correspondants sont exécutés en tant que fichiers de test. Plus d'informations sur l'exécution des fichiers de test peuvent être trouvées dans la section modèle d'exécution de l'exécuteur de test.
Modèle d'exécution du lanceur de tests
Lorsque l'isolation des tests au niveau du processus est activée, chaque fichier de test correspondant est exécuté dans un processus enfant distinct. Le nombre maximal de processus enfants exécutés à un moment donné est contrôlé par l'indicateur --test-concurrency
. Si le processus enfant se termine avec un code de sortie de 0, le test est considéré comme réussi. Sinon, le test est considéré comme un échec. Les fichiers de test doivent être exécutables par Node.js, mais ne sont pas tenus d'utiliser le module node:test
en interne.
Chaque fichier de test est exécuté comme s'il s'agissait d'un script ordinaire. C'est-à-dire que si le fichier de test lui-même utilise node:test
pour définir des tests, tous ces tests seront exécutés au sein d'un seul thread d'application, quelle que soit la valeur de l'option concurrency
de test()
.
Lorsque l'isolation des tests au niveau du processus est désactivée, chaque fichier de test correspondant est importé dans le processus du lanceur de tests. Une fois que tous les fichiers de test ont été chargés, les tests de niveau supérieur sont exécutés avec une concurrence de un. Étant donné que tous les fichiers de test sont exécutés dans le même contexte, il est possible que les tests interagissent les uns avec les autres d'une manière qui n'est pas possible lorsque l'isolation est activée. Par exemple, si un test repose sur un état global, il est possible que cet état soit modifié par un test provenant d'un autre fichier.
Collecte de la couverture du code
[Stable: 1 - Expérimental]
Stable: 1 Stability: 1 - Expérimental
Lorsque Node.js est démarré avec l'indicateur de ligne de commande --experimental-test-coverage
, la couverture du code est collectée et des statistiques sont rapportées une fois que tous les tests sont terminés. Si la variable d'environnement NODE_V8_COVERAGE
est utilisée pour spécifier un répertoire de couverture du code, les fichiers de couverture V8 générés sont écrits dans ce répertoire. Les modules de base de Node.js et les fichiers dans les répertoires node_modules/
ne sont pas inclus par défaut dans le rapport de couverture. Cependant, ils peuvent être explicitement inclus via l'indicateur --test-coverage-include
. Par défaut, tous les fichiers de test correspondants sont exclus du rapport de couverture. Les exclusions peuvent être remplacées en utilisant l'indicateur --test-coverage-exclude
. Si la couverture est activée, le rapport de couverture est envoyé à tous les rapporteurs de test via l'événement 'test:coverage'
.
La couverture peut être désactivée sur une série de lignes en utilisant la syntaxe de commentaire suivante :
/* node:coverage disable */
if (anAlwaysFalseCondition) {
// Le code dans cette branche ne sera jamais exécuté, mais les lignes sont ignorées
// à des fins de couverture. Toutes les lignes suivant le commentaire 'disable' sont
// ignorées jusqu'à ce qu'un commentaire 'enable' correspondant soit rencontré.
console.log('this is never executed');
}
/* node:coverage enable */
La couverture peut également être désactivée pour un nombre de lignes spécifié. Après le nombre de lignes spécifié, la couverture sera automatiquement réactivée. Si le nombre de lignes n'est pas explicitement fourni, une seule ligne est ignorée.
/* node:coverage ignore next */
if (anAlwaysFalseCondition) { console.log('this is never executed'); }
/* node:coverage ignore next 3 */
if (anAlwaysFalseCondition) {
console.log('this is never executed');
}
Rapporteurs de couverture
Les rapporteurs tap et spec imprimeront un résumé des statistiques de couverture. Il existe également un rapporteur lcov qui générera un fichier lcov pouvant être utilisé comme rapport de couverture approfondi.
node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info
- Aucun résultat de test n'est rapporté par ce rapporteur.
- Ce rapporteur devrait idéalement être utilisé en parallèle d'un autre rapporteur.
Simulation (Mocking)
Le module node:test
prend en charge la simulation pendant les tests via un objet mock
de niveau supérieur. L'exemple suivant crée un espion sur une fonction qui additionne deux nombres. L'espion est ensuite utilisé pour vérifier que la fonction a été appelée comme prévu.
import assert from 'node:assert';
import { mock, test } from 'node:test';
test('espionne une fonction', () => {
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);
// Réinitialise les mocks suivis globalement.
mock.reset();
});
'use strict';
const assert = require('node:assert');
const { mock, test } = require('node:test');
test('espionne une fonction', () => {
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);
// Réinitialise les mocks suivis globalement.
mock.reset();
});
La même fonctionnalité de simulation est également exposée sur l'objet TestContext
de chaque test. L'exemple suivant crée un espion sur une méthode d'objet en utilisant l'API exposée sur le TestContext
. L'avantage de la simulation via le contexte de test est que l'exécuteur de test restaurera automatiquement toutes les fonctionnalités simulées une fois le test terminé.
test('espionne une méthode d'objet', (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);
});
Minuteurs
La simulation de minuteurs est une technique couramment utilisée dans les tests logiciels pour simuler et contrôler le comportement des minuteurs, tels que setInterval
et setTimeout
, sans attendre réellement les intervalles de temps spécifiés.
Référez-vous à la classe MockTimers
pour une liste complète des méthodes et fonctionnalités.
Cela permet aux développeurs d'écrire des tests plus fiables et prévisibles pour les fonctionnalités dépendant du temps.
L'exemple ci-dessous montre comment simuler setTimeout
. En utilisant .enable({ apis: ['setTimeout'] });
, cela simulera les fonctions setTimeout
dans les modules node:timers et node:timers/promises, ainsi que depuis le contexte global de Node.js.
Remarque : La déstructuration de fonctions telles que import { setTimeout } from 'node:timers'
n'est actuellement pas prise en charge par cette API.
import assert from 'node:assert';
import { mock, test } from 'node:test';
test('simule setTimeout pour qu'il soit exécuté de manière synchrone sans avoir à attendre réellement', () => {
const fn = mock.fn();
// Choisissez éventuellement ce qu'il faut simuler
mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Avance dans le temps
mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
// Réinitialise les mocks suivis globalement.
mock.timers.reset();
// Si vous appelez reset sur une instance de mock, cela réinitialisera également l'instance de timers
mock.reset();
});
const assert = require('node:assert');
const { mock, test } = require('node:test');
test('simule setTimeout pour qu'il soit exécuté de manière synchrone sans avoir à attendre réellement', () => {
const fn = mock.fn();
// Choisissez éventuellement ce qu'il faut simuler
mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Avance dans le temps
mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
// Réinitialise les mocks suivis globalement.
mock.timers.reset();
// Si vous appelez reset sur une instance de mock, cela réinitialisera également l'instance de timers
mock.reset();
});
La même fonctionnalité de simulation est également exposée dans la propriété mock sur l'objet TestContext
de chaque test. L'avantage de la simulation via le contexte de test est que l'exécuteur de test restaurera automatiquement toutes les fonctionnalités de minuteurs simulés une fois le test terminé.
import assert from 'node:assert';
import { test } from 'node:test';
test('simule setTimeout pour qu'il soit exécuté de manière synchrone sans avoir à attendre réellement', (context) => {
const fn = context.mock.fn();
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Avance dans le temps
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
});
const assert = require('node:assert');
const { test } = require('node:test');
test('simule setTimeout pour qu'il soit exécuté de manière synchrone sans avoir à attendre réellement', (context) => {
const fn = context.mock.fn();
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Avance dans le temps
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
});
Dates
L'API de simulation des minuteurs permet également de simuler l'objet Date
. Il s'agit d'une fonctionnalité utile pour tester les fonctionnalités dépendantes du temps ou pour simuler des fonctions de calendrier internes telles que Date.now()
.
L'implémentation des dates fait également partie de la classe MockTimers
. Consultez-la pour obtenir une liste complète des méthodes et des fonctionnalités.
Note : Les dates et les minuteurs sont dépendants lorsqu'ils sont simulés ensemble. Cela signifie que si vous avez à la fois Date
et setTimeout
simulés, l'avancement du temps fera également avancer la date simulée, car ils simulent une seule horloge interne.
L'exemple ci-dessous montre comment simuler l'objet Date
et obtenir la valeur actuelle de Date.now()
.
import assert from 'node:assert';
import { test } from 'node:test';
test('simule l’objet Date', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['Date'] });
// Si non spécifié, la date initiale sera basée sur 0 dans l'époque UNIX
assert.strictEqual(Date.now(), 0);
// L'avance dans le temps fera également avancer la date
context.mock.timers.tick(9999);
assert.strictEqual(Date.now(), 9999);
});
const assert = require('node:assert');
const { test } = require('node:test');
test('simule l’objet Date', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['Date'] });
// Si non spécifié, la date initiale sera basée sur 0 dans l'époque UNIX
assert.strictEqual(Date.now(), 0);
// L'avance dans le temps fera également avancer la date
context.mock.timers.tick(9999);
assert.strictEqual(Date.now(), 9999);
});
S'il n'y a pas d'époque initiale définie, la date initiale sera basée sur 0 dans l'époque Unix. Il s'agit du 1er janvier 1970, 00:00:00 UTC. Vous pouvez définir une date initiale en passant une propriété now
à la méthode .enable()
. Cette valeur sera utilisée comme date initiale pour l'objet Date
simulé. Il peut s'agir d'un entier positif ou d'un autre objet Date.
import assert from 'node:assert';
import { test } from 'node:test';
test('simule l’objet Date avec l’heure initiale', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['Date'], now: 100 });
assert.strictEqual(Date.now(), 100);
// L'avance dans le temps fera également avancer la date
context.mock.timers.tick(200);
assert.strictEqual(Date.now(), 300);
});
const assert = require('node:assert');
const { test } = require('node:test');
test('simule l’objet Date avec l’heure initiale', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['Date'], now: 100 });
assert.strictEqual(Date.now(), 100);
// L'avance dans le temps fera également avancer la date
context.mock.timers.tick(200);
assert.strictEqual(Date.now(), 300);
});
Vous pouvez utiliser la méthode .setTime()
pour déplacer manuellement la date simulée à une autre heure. Cette méthode n'accepte qu'un entier positif.
Note : Cette méthode exécutera tous les minuteurs simulés qui sont dans le passé à partir de la nouvelle heure.
Dans l'exemple ci-dessous, nous définissons une nouvelle heure pour la date simulée.
import assert from 'node:assert';
import { test } from 'node:test';
test('définit l’heure d’un objet Date', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['Date'], now: 100 });
assert.strictEqual(Date.now(), 100);
// L'avance dans le temps fera également avancer la date
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('définit l’heure d’un objet Date', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['Date'], now: 100 });
assert.strictEqual(Date.now(), 100);
// L'avance dans le temps fera également avancer la date
context.mock.timers.setTime(1000);
context.mock.timers.tick(200);
assert.strictEqual(Date.now(), 1200);
});
Si vous avez un minuteur qui est configuré pour s'exécuter dans le passé, il sera exécuté comme si la méthode .tick()
avait été appelée. Ceci est utile si vous souhaitez tester une fonctionnalité dépendante du temps qui est déjà dans le passé.
import assert from 'node:assert';
import { test } from 'node:test';
test('exécute les minuteurs lorsque setTime passe les tics', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const fn = context.mock.fn();
setTimeout(fn, 1000);
context.mock.timers.setTime(800);
// Le minuteur n'est pas exécuté car l'heure n'est pas encore atteinte
assert.strictEqual(fn.mock.callCount(), 0);
assert.strictEqual(Date.now(), 800);
context.mock.timers.setTime(1200);
// Le minuteur est exécuté car l'heure est maintenant atteinte
assert.strictEqual(fn.mock.callCount(), 1);
assert.strictEqual(Date.now(), 1200);
});
const assert = require('node:assert');
const { test } = require('node:test');
test('exécute les minuteurs lorsque setTime passe les tics', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['setTimeout', 'Date'] });
const fn = context.mock.fn();
setTimeout(fn, 1000);
context.mock.timers.setTime(800);
// Le minuteur n'est pas exécuté car l'heure n'est pas encore atteinte
assert.strictEqual(fn.mock.callCount(), 0);
assert.strictEqual(Date.now(), 800);
context.mock.timers.setTime(1200);
// Le minuteur est exécuté car l'heure est maintenant atteinte
assert.strictEqual(fn.mock.callCount(), 1);
assert.strictEqual(Date.now(), 1200);
});
L'utilisation de .runAll()
exécutera tous les minuteurs qui sont actuellement dans la file d'attente. Cela fera également avancer la date simulée à l'heure du dernier minuteur qui a été exécuté comme si le temps était passé.
import assert from 'node:assert';
import { test } from 'node:test';
test('exécute les minuteurs lorsque setTime passe les tics', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
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();
// Tous les minuteurs sont exécutés car l'heure est maintenant atteinte
assert.strictEqual(fn.mock.callCount(), 3);
assert.strictEqual(Date.now(), 3000);
});
const assert = require('node:assert');
const { test } = require('node:test');
test('exécute les minuteurs lorsque setTime passe les tics', (context) => {
// Choisissez éventuellement ce qu'il faut simuler
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();
// Tous les minuteurs sont exécutés car l'heure est maintenant atteinte
assert.strictEqual(fn.mock.callCount(), 3);
assert.strictEqual(Date.now(), 3000);
});
Tests d'instantané
[Stable: 1 - Experimental]
Stable: 1 Stabilité: 1.0 - Développement précoce
Les tests d'instantané permettent de sérialiser des valeurs arbitraires en chaînes de caractères et de les comparer à un ensemble de valeurs de référence. Les valeurs de référence sont appelées instantanés et sont stockées dans un fichier d'instantané. Les fichiers d'instantané sont gérés par l'exécuteur de test, mais sont conçus pour être lisibles par l'homme afin de faciliter le débogage. La meilleure pratique consiste à archiver les fichiers d'instantané dans le système de contrôle de version avec vos fichiers de test.
Les fichiers d'instantané sont générés en démarrant Node.js avec l'indicateur de ligne de commande --test-update-snapshots
. Un fichier d'instantané distinct est généré pour chaque fichier de test. Par défaut, le fichier d'instantané porte le même nom que le fichier de test avec l'extension .snapshot
. Ce comportement peut être configuré à l'aide de la fonction snapshot.setResolveSnapshotPath()
. Chaque assertion d'instantané correspond à une exportation dans le fichier d'instantané.
Un exemple de test d'instantané est présenté ci-dessous. La première fois que ce test est exécuté, il échouera car le fichier d'instantané correspondant n'existe pas.
// test.js
suite('suite de tests d'instantané', () => {
test('test d'instantané', (t) => {
t.assert.snapshot({ value1: 1, value2: 2 });
t.assert.snapshot(5);
});
});
Générez le fichier d'instantané en exécutant le fichier de test avec --test-update-snapshots
. Le test doit réussir et un fichier nommé test.js.snapshot
est créé dans le même répertoire que le fichier de test. Le contenu du fichier d'instantané est présenté ci-dessous. Chaque instantané est identifié par le nom complet du test et un compteur pour différencier les instantanés dans le même test.
exports[`suite de tests d'instantané > test d'instantané 1`] = `
{
"value1": 1,
"value2": 2
}
`;
exports[`suite de tests d'instantané > test d'instantané 2`] = `
5
`;
Une fois le fichier d'instantané créé, exécutez à nouveau les tests sans l'indicateur --test-update-snapshots
. Les tests devraient maintenant réussir.
Rapporteurs de test
[Historique]
Version | Modifications |
---|---|
v19.9.0, v18.17.0 | Les rapporteurs sont désormais exposés à node:test/reporters . |
v19.6.0, v18.15.0 | Ajouté dans : v19.6.0, v18.15.0 |
Le module node:test
prend en charge le passage d'indicateurs --test-reporter
pour que l'exécuteur de tests utilise un rapporteur spécifique.
Les rapporteurs intégrés suivants sont pris en charge :
spec
Le rapporteurspec
affiche les résultats des tests dans un format lisible par l'homme. C'est le rapporteur par défaut.tap
Le rapporteurtap
affiche les résultats des tests au format TAP.dot
Le rapporteurdot
affiche les résultats des tests dans un format compact, où chaque test réussi est représenté par un.
, et chaque test échoué est représenté par unX
.junit
Le rapporteur junit affiche les résultats des tests au format XML jUnitlcov
Le rapporteurlcov
affiche la couverture des tests lorsqu'il est utilisé avec l'indicateur--experimental-test-coverage
.
La sortie exacte de ces rapporteurs est susceptible de changer entre les versions de Node.js, et ne doit pas être utilisée de manière programmatique. Si un accès programmatique à la sortie de l'exécuteur de tests est requis, utilisez les événements émis par la <TestsStream>.
Les rapporteurs sont disponibles via le module node:test/reporters
:
import { tap, spec, dot, junit, lcov } from 'node:test/reporters';
const { tap, spec, dot, junit, lcov } = require('node:test/reporters');
Rapporteurs personnalisés
--test-reporter
peut être utilisé pour spécifier un chemin vers un rapporteur personnalisé. Un rapporteur personnalisé est un module qui exporte une valeur acceptée par stream.compose. Les rapporteurs doivent transformer les événements émis par une <TestsStream>
Exemple de rapporteur personnalisé utilisant <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} mis en file d'attente`);
break;
case 'test:enqueue':
callback(null, `test ${event.data.name} en file d'attente`);
break;
case 'test:watch:drained':
callback(null, 'file d'attente de surveillance des tests vidée');
break;
case 'test:start':
callback(null, `test ${event.data.name} démarré`);
break;
case 'test:pass':
callback(null, `test ${event.data.name} réussi`);
break;
case 'test:fail':
callback(null, `test ${event.data.name} échoué`);
break;
case 'test:plan':
callback(null, 'plan de test');
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, `nombre total de lignes : ${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} mis en file d'attente`);
break;
case 'test:enqueue':
callback(null, `test ${event.data.name} en file d'attente`);
break;
case 'test:watch:drained':
callback(null, 'file d'attente de surveillance des tests vidée');
break;
case 'test:start':
callback(null, `test ${event.data.name} démarré`);
break;
case 'test:pass':
callback(null, `test ${event.data.name} réussi`);
break;
case 'test:fail':
callback(null, `test ${event.data.name} échoué`);
break;
case 'test:plan':
callback(null, 'plan de test');
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, `nombre total de lignes : ${totalLineCount}\n`);
break;
}
}
},
});
module.exports = customReporter;
Exemple de rapporteur personnalisé utilisant une fonction de générateur :
export default async function * customReporter(source) {
for await (const event of source) {
switch (event.type) {
case 'test:dequeue':
yield `test ${event.data.name} mis en file d'attente\n`;
break;
case 'test:enqueue':
yield `test ${event.data.name} en file d'attente\n`;
break;
case 'test:watch:drained':
yield 'file d'attente de surveillance des tests vidée\n';
break;
case 'test:start':
yield `test ${event.data.name} démarré\n`;
break;
case 'test:pass':
yield `test ${event.data.name} réussi\n`;
break;
case 'test:fail':
yield `test ${event.data.name} échoué\n`;
break;
case 'test:plan':
yield 'plan de test\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 `nombre total de lignes : ${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} mis en file d'attente\n`;
break;
case 'test:enqueue':
yield `test ${event.data.name} en file d'attente\n`;
break;
case 'test:watch:drained':
yield 'file d'attente de surveillance des tests vidée\n';
break;
case 'test:start':
yield `test ${event.data.name} démarré\n`;
break;
case 'test:pass':
yield `test ${event.data.name} réussi\n`;
break;
case 'test:fail':
yield `test ${event.data.name} échoué\n`;
break;
case 'test:plan':
yield 'plan de test\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 `nombre total de lignes : ${totalLineCount}\n`;
break;
}
}
}
};
La valeur fournie à --test-reporter
doit être une chaîne de caractères telle que celle utilisée dans un import()
dans le code JavaScript, ou une valeur fournie pour --import
.
Plusieurs rapporteurs
L'option --test-reporter
peut être spécifiée plusieurs fois pour rapporter les résultats des tests dans plusieurs formats. Dans ce cas, il est nécessaire de spécifier une destination pour chaque rapporteur en utilisant --test-reporter-destination
. La destination peut être stdout
, stderr
ou un chemin de fichier. Les rapporteurs et les destinations sont appariés selon l'ordre dans lequel ils ont été spécifiés.
Dans l'exemple suivant, le rapporteur spec
affichera les résultats sur stdout
, et le rapporteur dot
affichera les résultats dans file.txt
:
node --test-reporter=spec --test-reporter=dot --test-reporter-destination=stdout --test-reporter-destination=file.txt
Lorsqu'un seul rapporteur est spécifié, la destination est par défaut stdout
, sauf si une destination est explicitement fournie.
run([options])
[Historique]
Version | Modifications |
---|---|
v23.0.0 | Ajout de l'option cwd . |
v23.0.0 | Ajout des options de couverture. |
v22.8.0 | Ajout de l'option isolation . |
v22.6.0 | Ajout de l'option globPatterns . |
v22.0.0, v20.14.0 | Ajout de l'option forceExit . |
v20.1.0, v18.17.0 | Ajout d'une option testNamePatterns. |
v18.9.0, v16.19.0 | Ajout dans : v18.9.0, v16.19.0 |
options
<Object> Options de configuration pour l'exécution des tests. Les propriétés suivantes sont prises en charge :concurrency
<number> | <boolean> Si un nombre est fourni, ce nombre de processus de test s'exécutera en parallèle, chaque processus correspondant à un fichier de test. Sitrue
,os.availableParallelism() - 1
fichiers de test s'exécuteront en parallèle. Sifalse
, un seul fichier de test sera exécuté à la fois. Par défaut :false
.cwd
: <string> Spécifie le répertoire de travail courant à utiliser par le lanceur de tests. Sert de chemin de base pour la résolution des fichiers selon le modèle d'exécution du lanceur de tests. Par défaut :process.cwd()
.files
: <Array> Un tableau contenant la liste des fichiers à exécuter. Par défaut : fichiers correspondants du modèle d'exécution du lanceur de tests.forceExit
: <boolean> Configure le lanceur de tests pour qu'il quitte le processus une fois que tous les tests connus ont fini de s'exécuter, même si la boucle d'événements devrait autrement rester active. Par défaut :false
.globPatterns
: <Array> Un tableau contenant la liste des modèles glob pour faire correspondre les fichiers de test. Cette option ne peut pas être utilisée avecfiles
. Par défaut : fichiers correspondants du modèle d'exécution du lanceur de tests.inspectPort
<number> | <Function> Définit le port de l'inspecteur du processus enfant de test. Cela peut être un nombre ou une fonction qui ne prend aucun argument et renvoie un nombre. Si une valeur nulle est fournie, chaque processus obtient son propre port, incrémenté à partir duprocess.debugPort
du principal. Cette option est ignorée si l'optionisolation
est définie sur'none'
car aucun processus enfant n'est créé. Par défaut :undefined
.isolation
<string> Configure le type d'isolation des tests. Si elle est définie sur'process'
, chaque fichier de test est exécuté dans un processus enfant séparé. Si elle est définie sur'none'
, tous les fichiers de test sont exécutés dans le processus courant. Par défaut :'process'
.only
: <boolean> Si la valeur est vraie, le contexte de test n'exécutera que les tests qui ont l'optiononly
définie.setup
<Function> Une fonction qui accepte l'instanceTestsStream
et peut être utilisée pour configurer des écouteurs avant l'exécution des tests. Par défaut :undefined
.execArgv
<Array> Un tableau d'options de ligne de commande à passer à l'exécutablenode
lors de la création des sous-processus. Cette option n'a aucun effet lorsqueisolation
est'none'
. Par défaut :[]
argv
<Array> Un tableau d'options de ligne de commande à passer à chaque fichier de test lors de la création des sous-processus. Cette option n'a aucun effet lorsqueisolation
est'none'
. Par défaut :[]
.signal
<AbortSignal> Permet d'abandonner une exécution de test en cours.testNamePatterns
<string> | <RegExp> | <Array> Une chaîne, une expression régulière ou un tableau d'expressions régulières, qui peut être utilisé pour n'exécuter que les tests dont le nom correspond au modèle fourni. Les modèles de nom de test sont interprétés comme des expressions régulières JavaScript. Pour chaque test exécuté, tous les hooks de test correspondants, tels quebeforeEach()
, sont également exécutés. Par défaut :undefined
.testSkipPatterns
<string> | <RegExp> | <Array> Une chaîne, une expression régulière ou un tableau d'expressions régulières, qui peut être utilisé pour exclure l'exécution des tests dont le nom correspond au modèle fourni. Les modèles de nom de test sont interprétés comme des expressions régulières JavaScript. Pour chaque test exécuté, tous les hooks de test correspondants, tels quebeforeEach()
, sont également exécutés. Par défaut :undefined
.timeout
<number> Un nombre de millisecondes après lequel l'exécution du test échouera. Si elle n'est pas spécifiée, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.watch
<boolean> Indique s'il faut exécuter en mode surveillance ou non. Par défaut :false
.shard
<Object> Exécution des tests dans un fragment spécifique. Par défaut :undefined
.coverage
<boolean> activer la collecte de couverture de code. Par défaut :false
.coverageExcludeGlobs
<string> | <Array> Exclut des fichiers spécifiques de la couverture de code à l'aide d'un motif glob, qui peut correspondre aux chemins de fichiers absolus et relatifs. Cette propriété n'est applicable que sicoverage
a été défini surtrue
. SicoverageExcludeGlobs
etcoverageIncludeGlobs
sont fournis, les fichiers doivent répondre aux deux critères pour être inclus dans le rapport de couverture. Par défaut :undefined
.coverageIncludeGlobs
<string> | <Array> Inclut des fichiers spécifiques dans la couverture de code à l'aide d'un motif glob, qui peut correspondre aux chemins de fichiers absolus et relatifs. Cette propriété n'est applicable que sicoverage
a été défini surtrue
. SicoverageExcludeGlobs
etcoverageIncludeGlobs
sont fournis, les fichiers doivent répondre aux deux critères pour être inclus dans le rapport de couverture. Par défaut :undefined
.lineCoverage
<number> Exiger un pourcentage minimum de lignes couvertes. Si la couverture de code n'atteint pas le seuil spécifié, le processus se terminera avec le code1
. Par défaut :0
.branchCoverage
<number> Exiger un pourcentage minimum de branches couvertes. Si la couverture de code n'atteint pas le seuil spécifié, le processus se terminera avec le code1
. Par défaut :0
.functionCoverage
<number> Exiger un pourcentage minimum de fonctions couvertes. Si la couverture de code n'atteint pas le seuil spécifié, le processus se terminera avec le code1
. Par défaut :0
.
Retourne : <TestsStream>
Remarque : shard
est utilisé pour paralléliser horizontalement l'exécution des tests sur plusieurs machines ou processus, ce qui est idéal pour les exécutions à grande échelle dans des environnements variés. Il est incompatible avec le mode watch
, conçu pour une itération rapide du code en réexécutant automatiquement les tests lors des modifications de fichiers.
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])
Ajouté dans : v22.0.0, v20.13.0
name
<string> Le nom de la suite, qui est affiché lors de la communication des résultats des tests. Par défaut : La propriéténame
defn
, ou'\<anonymous\>'
sifn
n’a pas de nom.options
<Object> Options de configuration facultatives pour la suite. Cela prend en charge les mêmes options quetest([name][, options][, fn])
.fn
<Function> | <AsyncFunction> La fonction de suite déclarant les tests et suites imbriqués. Le premier argument de cette fonction est un objetSuiteContext
. Par défaut : Une fonction no-op.- Renvoie : <Promise> Immédiatement résolue avec
undefined
.
La fonction suite()
est importée du module node:test
.
suite.skip([name][, options][, fn])
Ajouté dans : v22.0.0, v20.13.0
Raccourci pour ignorer une suite. Ceci est identique à suite([name], { skip: true }[, fn])
.
suite.todo([name][, options][, fn])
Ajouté dans : v22.0.0, v20.13.0
Raccourci pour marquer une suite comme TODO
. Ceci est identique à suite([name], { todo: true }[, fn])
.
suite.only([name][, options][, fn])
Ajouté dans : v22.0.0, v20.13.0
Raccourci pour marquer une suite comme only
. Ceci est identique à suite([name], { only: true }[, fn])
.
test([name][, options][, fn])
[Historique]
Version | Modifications |
---|---|
v20.2.0, v18.17.0 | Ajout des raccourcis skip , todo et only . |
v18.8.0, v16.18.0 | Ajout d’une option signal . |
v18.7.0, v16.17.0 | Ajout d’une option timeout . |
v18.0.0, v16.17.0 | Ajouté dans : v18.0.0, v16.17.0 |
name
<string> Le nom du test, qui est affiché lors de la communication des résultats des tests. Par défaut : La propriéténame
defn
, ou'\<anonymous\>'
sifn
n’a pas de nom.options
<Object> Options de configuration pour le test. Les propriétés suivantes sont prises en charge :concurrency
<number> | <boolean> Si un nombre est fourni, ce nombre de tests s’exécutera en parallèle dans le thread d’application. Sitrue
, tous les tests asynchrones planifiés s’exécutent simultanément dans le thread. Sifalse
, un seul test s’exécute à la fois. Si non spécifié, les sous-tests héritent de cette valeur de leur parent. Par défaut :false
.only
<boolean> Si la valeur est truthy et que le contexte de test est configuré pour exécuter uniquement les testsonly
, ce test sera exécuté. Sinon, le test est ignoré. Par défaut :false
.signal
<AbortSignal> Permet d’abandonner un test en cours.skip
<boolean> | <string> Si truthy, le test est ignoré. Si une chaîne est fournie, cette chaîne est affichée dans les résultats du test comme raison d’ignorer le test. Par défaut :false
.todo
<boolean> | <string> Si truthy, le test est marqué commeTODO
. Si une chaîne est fournie, cette chaîne est affichée dans les résultats du test comme raison pour laquelle le test estTODO
. Par défaut :false
.timeout
<number> Un nombre de millisecondes après lequel le test échouera. Si non spécifié, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.plan
<number> Le nombre d’assertions et de sous-tests attendus à exécuter dans le test. Si le nombre d’assertions exécutées dans le test ne correspond pas au nombre spécifié dans le plan, le test échouera. Par défaut :undefined
.
fn
<Function> | <AsyncFunction> La fonction testée. Le premier argument de cette fonction est un objetTestContext
. Si le test utilise des rappels, la fonction de rappel est transmise comme deuxième argument. Par défaut : Une fonction no-op.Renvoie : <Promise> Résolue avec
undefined
une fois le test terminé, ou immédiatement si le test s’exécute dans une suite.
La fonction test()
est la valeur importée du module test
. Chaque invocation de cette fonction entraîne le signalement du test au <TestsStream>.
L’objet TestContext
transmis à l’argument fn
peut être utilisé pour effectuer des actions liées au test actuel. Les exemples incluent l’ignorance du test, l’ajout d’informations de diagnostic supplémentaires ou la création de sous-tests.
test()
renvoie une Promise
qui se réalise une fois le test terminé. si test()
est appelé dans une suite, elle se réalise immédiatement. La valeur de retour peut généralement être ignorée pour les tests de niveau supérieur. Cependant, la valeur de retour des sous-tests doit être utilisée pour empêcher le test parent de se terminer en premier et d’annuler le sous-test, comme indiqué dans l’exemple suivant.
test('top level test', async (t) => {
// The setTimeout() in the following subtest would cause it to outlive its
// parent test if 'await' is removed on the next line. Once the parent test
// completes, it will cancel any outstanding subtests.
await t.test('longer running subtest', async (t) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
});
});
L’option timeout
peut être utilisée pour faire échouer le test s’il prend plus de timeout
millisecondes. Cependant, ce n’est pas un mécanisme fiable pour annuler les tests, car un test en cours d’exécution peut bloquer le thread d’application et ainsi empêcher l’annulation planifiée.
test.skip([name][, options][, fn])
Abréviation pour ignorer un test, identique à test([name], { skip: true }[, fn])
.
test.todo([name][, options][, fn])
Abréviation pour marquer un test comme TODO
, identique à test([name], { todo: true }[, fn])
.
test.only([name][, options][, fn])
Abréviation pour marquer un test comme only
, identique à test([name], { only: true }[, fn])
.
describe([name][, options][, fn])
Alias pour suite()
.
La fonction describe()
est importée depuis le module node:test
.
describe.skip([name][, options][, fn])
Abréviation pour ignorer une suite de tests. Ceci est identique à describe([name], { skip: true }[, fn])
.
describe.todo([name][, options][, fn])
Abréviation pour marquer une suite de tests comme TODO
. Ceci est identique à describe([name], { todo: true }[, fn])
.
describe.only([name][, options][, fn])
Ajouté dans : v19.8.0, v18.15.0
Abréviation pour marquer une suite de tests comme only
. Ceci est identique à describe([name], { only: true }[, fn])
.
it([name][, options][, fn])
[Historique]
Version | Modifications |
---|---|
v19.8.0, v18.16.0 | Appeler it() est maintenant équivalent à appeler test() . |
v18.6.0, v16.17.0 | Ajouté dans : v18.6.0, v16.17.0 |
Alias pour test()
.
La fonction it()
est importée depuis le module node:test
.
it.skip([name][, options][, fn])
Abréviation pour ignorer un test, identique à it([name], { skip: true }[, fn])
.
it.todo([name][, options][, fn])
Abréviation pour marquer un test comme TODO
, identique à it([name], { todo: true }[, fn])
.
it.only([name][, options][, fn])
Ajouté dans : v19.8.0, v18.15.0
Abréviation pour marquer un test comme only
, identique à it([name], { only: true }[, fn])
.
before([fn][, options])
Ajouté dans : v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La fonction de hook. Si le hook utilise des rappels (callbacks), la fonction de rappel est passée comme deuxième argument. Par défaut : Une fonction no-op.options
<Object> Options de configuration pour le hook. Les propriétés suivantes sont prises en charge :signal
<AbortSignal> Permet d’abandonner un hook en cours.timeout
<number> Un nombre de millisecondes après lequel le hook échouera. S’il n’est pas spécifié, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.
Cette fonction crée un hook qui s’exécute avant l’exécution d’une suite.
describe('tests', async () => {
before(() => console.log('sur le point d\'exécuter un test'));
it('est un sous-test', () => {
assert.ok('une assertion pertinente ici');
});
});
after([fn][, options])
Ajouté dans : v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La fonction de hook. Si le hook utilise des rappels (callbacks), la fonction de rappel est passée comme deuxième argument. Par défaut : Une fonction no-op.options
<Object> Options de configuration pour le hook. Les propriétés suivantes sont prises en charge :signal
<AbortSignal> Permet d’abandonner un hook en cours.timeout
<number> Un nombre de millisecondes après lequel le hook échouera. S’il n’est pas spécifié, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.
Cette fonction crée un hook qui s’exécute après l’exécution d’une suite.
describe('tests', async () => {
after(() => console.log('exécution des tests terminée'));
it('est un sous-test', () => {
assert.ok('une assertion pertinente ici');
});
});
Remarque : Le hook after
est garanti d’être exécuté, même si les tests au sein de la suite échouent.
beforeEach([fn][, options])
Ajouté dans : v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La fonction de hook. Si le hook utilise des rappels, la fonction de rappel est passée en deuxième argument. Par défaut : Une fonction no-op.options
<Object> Options de configuration pour le hook. Les propriétés suivantes sont prises en charge :signal
<AbortSignal> Permet d’abandonner un hook en cours.timeout
<number> Un nombre de millisecondes après lequel le hook échouera. Si elle n’est pas spécifiée, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.
Cette fonction crée un hook qui s’exécute avant chaque test dans la suite actuelle.
describe('tests', async () => {
beforeEach(() => console.log('about to run a test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
afterEach([fn][, options])
Ajouté dans : v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La fonction de hook. Si le hook utilise des rappels, la fonction de rappel est passée en deuxième argument. Par défaut : Une fonction no-op.options
<Object> Options de configuration pour le hook. Les propriétés suivantes sont prises en charge :signal
<AbortSignal> Permet d’abandonner un hook en cours.timeout
<number> Un nombre de millisecondes après lequel le hook échouera. Si elle n’est pas spécifiée, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.
Cette fonction crée un hook qui s’exécute après chaque test dans la suite actuelle. Le hook afterEach()
est exécuté même si le test échoue.
describe('tests', async () => {
afterEach(() => console.log('finished running a test'));
it('is a subtest', () => {
assert.ok('some relevant assertion here');
});
});
snapshot
Ajouté dans: v22.3.0
[Stable: 1 - Expérimental]
Stable: 1 Stabilité: 1.0 - Développement précoce
Un objet dont les méthodes sont utilisées pour configurer les paramètres de snapshot par défaut dans le processus actuel. Il est possible d'appliquer la même configuration à tous les fichiers en plaçant le code de configuration commun dans un module préchargé avec --require
ou --import
.
snapshot.setDefaultSnapshotSerializers(serializers)
Ajouté dans: v22.3.0
[Stable: 1 - Expérimental]
Stable: 1 Stabilité: 1.0 - Développement précoce
serializers
<Array> Un tableau de fonctions synchrones utilisées comme sérialiseurs par défaut pour les tests de snapshot.
Cette fonction est utilisée pour personnaliser le mécanisme de sérialisation par défaut utilisé par l'exécuteur de tests. Par défaut, l'exécuteur de tests effectue la sérialisation en appelant JSON.stringify(value, null, 2)
sur la valeur fournie. JSON.stringify()
a des limitations concernant les structures circulaires et les types de données pris en charge. Si un mécanisme de sérialisation plus robuste est requis, cette fonction doit être utilisée.
snapshot.setResolveSnapshotPath(fn)
Ajouté dans: v22.3.0
[Stable: 1 - Expérimental]
Stable: 1 Stabilité: 1.0 - Développement précoce
fn
<Function> Une fonction utilisée pour calculer l'emplacement du fichier de snapshot. La fonction reçoit le chemin du fichier de test comme seul argument. Si le test n'est pas associé à un fichier (par exemple dans le REPL), l'entrée est indéfinie.fn()
doit renvoyer une chaîne spécifiant l'emplacement du fichier de snapshot.
Cette fonction est utilisée pour personnaliser l'emplacement du fichier de snapshot utilisé pour les tests de snapshot. Par défaut, le nom de fichier du snapshot est le même que le nom de fichier du point d'entrée avec une extension de fichier .snapshot
.
Classe : MockFunctionContext
Ajoutée dans : v19.1.0, v18.13.0
La classe MockFunctionContext
est utilisée pour inspecter ou manipuler le comportement des mocks créés via les API MockTracker
.
ctx.calls
Ajoutée dans : v19.1.0, v18.13.0
Un getter qui renvoie une copie du tableau interne utilisé pour suivre les appels au mock. Chaque entrée du tableau est un objet avec les propriétés suivantes.
arguments
<Array> Un tableau des arguments passés à la fonction mockée.error
<any> Si la fonction mockée a levé une exception, cette propriété contient la valeur levée. Par défaut :undefined
.result
<any> La valeur renvoyée par la fonction mockée.stack
<Error> Un objetError
dont la pile peut être utilisée pour déterminer le site d’appel de l’invocation de la fonction mockée.target
<Function> | <undefined> Si la fonction mockée est un constructeur, ce champ contient la classe en cours de construction. Sinon, il seraundefined
.this
<any> La valeurthis
de la fonction mockée.
ctx.callCount()
Ajoutée dans : v19.1.0, v18.13.0
- Renvoie : <integer> Le nombre de fois où ce mock a été invoqué.
Cette fonction renvoie le nombre de fois où ce mock a été invoqué. Cette fonction est plus efficace que de vérifier ctx.calls.length
, car ctx.calls
est un getter qui crée une copie du tableau interne de suivi des appels.
ctx.mockImplementation(implementation)
Ajouté dans : v19.1.0, v18.13.0
implementation
<Function> | <AsyncFunction> La fonction à utiliser comme nouvelle implémentation du mock.
Cette fonction est utilisée pour modifier le comportement d'un mock existant.
L'exemple suivant crée une fonction mock à l'aide de t.mock.fn()
, appelle la fonction mock, puis modifie l'implémentation du mock par une fonction différente.
test('modifie le comportement d\'un 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])
Ajouté dans : v19.1.0, v18.13.0
implementation
<Function> | <AsyncFunction> La fonction à utiliser comme implémentation du mock pour le numéro d'appel spécifié paronCall
.onCall
<integer> Le numéro d'appel qui utiliseraimplementation
. Si l'appel spécifié a déjà eu lieu, une exception est levée. Par défaut : Le numéro de l'appel suivant.
Cette fonction est utilisée pour modifier le comportement d'un mock existant pour un seul appel. Une fois l'appel onCall
effectué, le mock reviendra au comportement qu'il aurait utilisé si mockImplementationOnce()
n'avait pas été appelé.
L'exemple suivant crée une fonction mock à l'aide de t.mock.fn()
, appelle la fonction mock, modifie l'implémentation du mock par une fonction différente pour l'appel suivant, puis reprend son comportement précédent.
test('modifie le comportement d\'un mock une seule fois', (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()
Ajouté dans : v19.3.0, v18.13.0
Réinitialise l’historique des appels de la fonction mock.
ctx.restore()
Ajouté dans : v19.1.0, v18.13.0
Réinitialise l’implémentation de la fonction mock à son comportement original. Le mock peut toujours être utilisé après avoir appelé cette fonction.
Class: MockModuleContext
Ajouté dans : v22.3.0, v20.18.0
La classe MockModuleContext
est utilisée pour manipuler le comportement des mocks de modules créés via les API MockTracker
.
ctx.restore()
Ajouté dans : v22.3.0, v20.18.0
Réinitialise l’implémentation du module mock.
Class: MockTracker
Ajouté dans : v19.1.0, v18.13.0
La classe MockTracker
est utilisée pour gérer la fonctionnalité de mocking. Le module d’exécution de test fournit une exportation mock
de niveau supérieur qui est une instance MockTracker
. Chaque test fournit également sa propre instance MockTracker
via la propriété mock
du contexte de test.
mock.fn([original[, implementation]][, options])
Ajouté dans : v19.1.0, v18.13.0
original
<Function> | <AsyncFunction> Une fonction optionnelle pour créer un mock sur. Par défaut : Une fonction no-op.implementation
<Function> | <AsyncFunction> Une fonction optionnelle utilisée comme implémentation de mock pouroriginal
. Ceci est utile pour créer des mocks qui présentent un comportement pendant un nombre spécifié d’appels, puis restaurer le comportement deoriginal
. Par défaut : La fonction spécifiée paroriginal
.options
<Object> Options de configuration facultatives pour la fonction mock. Les propriétés suivantes sont prises en charge :times
<integer> Le nombre de fois où le mock utilisera le comportement deimplementation
. Une fois que la fonction mock a été appeléetimes
fois, elle restaurera automatiquement le comportement deoriginal
. Cette valeur doit être un entier supérieur à zéro. Par défaut :Infinity
.
Retourne : <Proxy> La fonction mockée. La fonction mockée contient une propriété spéciale
mock
, qui est une instance deMockFunctionContext
, et peut être utilisée pour inspecter et modifier le comportement de la fonction mockée.
Cette fonction est utilisée pour créer une fonction mock.
L’exemple suivant crée une fonction mock qui incrémente un compteur de un à chaque invocation. L’option times
est utilisée pour modifier le comportement du mock de telle sorte que les deux premières invocations ajoutent deux au compteur au lieu de un.
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])
Ajouté dans : v19.3.0, v18.13.0
Cette fonction est un sucre syntaxique pour MockTracker.method
avec options.getter
défini sur true
.
mock.method(object, methodName[, implementation][, options])
Ajouté dans : v19.1.0, v18.13.0
object
<Object> L’objet dont la méthode est simulée.methodName
<string> | <symbol> L’identifiant de la méthode surobject
à simuler. Siobject[methodName]
n’est pas une fonction, une erreur est levée.implementation
<Function> | <AsyncFunction> Une fonction optionnelle utilisée comme implémentation de simulation pourobject[methodName]
. Par défaut : La méthode originale spécifiée parobject[methodName]
.options
<Object> Options de configuration optionnelles pour la méthode simulée. Les propriétés suivantes sont prises en charge :getter
<boolean> Sitrue
,object[methodName]
est traité comme un getter. Cette option ne peut pas être utilisée avec l’optionsetter
. Par défaut : false.setter
<boolean> Sitrue
,object[methodName]
est traité comme un setter. Cette option ne peut pas être utilisée avec l’optiongetter
. Par défaut : false.times
<integer> Le nombre de fois que le mock utilisera le comportement deimplementation
. Une fois que la méthode simulée a été appeléetimes
fois, elle restaurera automatiquement le comportement original. Cette valeur doit être un entier supérieur à zéro. Par défaut :Infinity
.
Retourne : <Proxy> La méthode simulée. La méthode simulée contient une propriété spéciale
mock
, qui est une instance deMockFunctionContext
, et peut être utilisée pour inspecter et modifier le comportement de la méthode simulée.
Cette fonction est utilisée pour créer un mock sur une méthode d’objet existante. L’exemple suivant montre comment un mock est créé sur une méthode d’objet existante.
test('espionne une méthode d’objet', (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])
Ajouté dans : v22.3.0, v20.18.0
[Stable: 1 - Experimental]
Stable: 1 Stable : 1.0 - Développement précoce
specifier
<string> | <URL> Une chaîne identifiant le module à simuler.options
<Object> Options de configuration facultatives pour le module simulé. Les propriétés suivantes sont prises en charge :cache
<boolean> Sifalse
, chaque appel àrequire()
ouimport()
génère un nouveau module simulé. Sitrue
, les appels suivants renverront le même module simulé, et le module simulé est inséré dans le cache CommonJS. Par défaut : false.defaultExport
<any> Une valeur facultative utilisée comme exportation par défaut du module simulé. Si cette valeur n’est pas fournie, les simulations ESM n’incluent pas d’exportation par défaut. Si la simulation est un module CommonJS ou intégré, ce paramètre est utilisé comme valeur demodule.exports
. Si cette valeur n’est pas fournie, les simulations CJS et intégrées utilisent un objet vide comme valeur demodule.exports
.namedExports
<Object> Un objet facultatif dont les clés et les valeurs sont utilisées pour créer les exportations nommées du module simulé. Si la simulation est un module CommonJS ou intégré, ces valeurs sont copiées surmodule.exports
. Par conséquent, si une simulation est créée avec à la fois des exportations nommées et une exportation par défaut non-objet, la simulation lèvera une exception lorsqu’elle sera utilisée comme module CJS ou intégré.
Retourne : <MockModuleContext> Un objet qui peut être utilisé pour manipuler la simulation.
Cette fonction est utilisée pour simuler les exportations des modules ECMAScript, des modules CommonJS et des modules intégrés Node.js. Toutes les références au module original avant la simulation ne sont pas affectées. Afin d’activer la simulation de module, Node.js doit être démarré avec l’indicateur de ligne de commande --experimental-test-module-mocks
.
L’exemple suivant montre comment une simulation est créée pour un module.
test('simule un module intégré dans les deux systèmes de module', async (t) => {
// Crée une simulation de 'node:readline' avec une exportation nommée 'fn', qui
// n’existe pas dans le module original 'node:readline'.
const mock = t.mock.module('node:readline', {
namedExports: { fn() { return 42; } },
});
let esmImpl = await import('node:readline');
let cjsImpl = require('node:readline');
// cursorTo() est une exportation du module original 'node:readline'.
assert.strictEqual(esmImpl.cursorTo, undefined);
assert.strictEqual(cjsImpl.cursorTo, undefined);
assert.strictEqual(esmImpl.fn(), 42);
assert.strictEqual(cjsImpl.fn(), 42);
mock.restore();
// La simulation est restaurée, donc le module intégré original est retourné.
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()
Ajouté dans : v19.1.0, v18.13.0
Cette fonction restaure le comportement par défaut de toutes les simulations qui ont été précédemment créées par ce MockTracker
et dissocie les simulations de l’instance MockTracker
. Une fois dissociées, les simulations peuvent toujours être utilisées, mais l’instance MockTracker
ne peut plus être utilisée pour réinitialiser leur comportement ou interagir avec elles de quelque manière que ce soit.
Une fois chaque test terminé, cette fonction est appelée sur le MockTracker
du contexte de test. Si le MockTracker
global est largement utilisé, il est recommandé d’appeler cette fonction manuellement.
mock.restoreAll()
Ajouté dans : v19.1.0, v18.13.0
Cette fonction restaure le comportement par défaut de toutes les simulations qui ont été précédemment créées par ce MockTracker
. Contrairement à mock.reset()
, mock.restoreAll()
ne dissocie pas les simulations de l’instance MockTracker
.
mock.setter(object, methodName[, implementation][, options])
Ajouté dans : v19.3.0, v18.13.0
Cette fonction est un sucre syntaxique pour MockTracker.method
avec options.setter
défini sur true
.
Classe : MockTimers
[Historique]
Version | Modifications |
---|---|
v23.1.0 | Les Mock Timers sont désormais stables. |
v20.4.0, v18.19.0 | Ajouté dans : v20.4.0, v18.19.0 |
[Stable : 2 - Stable]
Stable : 2 Stabilité : 2 - Stable
La simulation de timers est une technique couramment utilisée dans les tests logiciels pour simuler et contrôler le comportement des timers, tels que setInterval
et setTimeout
, sans réellement attendre les intervalles de temps spécifiés.
MockTimers est également capable de simuler l’objet Date
.
Le MockTracker
fournit une exportation timers
de niveau supérieur qui est une instance MockTimers
.
timers.enable([enableOptions])
[Historique]
Version | Modifications |
---|---|
v21.2.0, v20.11.0 | Paramètres mis à jour pour être un objet d’options avec les API disponibles et l’époque initiale par défaut. |
v20.4.0, v18.19.0 | Ajouté dans : v20.4.0, v18.19.0 |
Active la simulation de timers pour les timers spécifiés.
enableOptions
<Object> Options de configuration facultatives pour activer la simulation de timers. Les propriétés suivantes sont prises en charge :apis
<Array> Un tableau facultatif contenant les timers à simuler. Les valeurs de timer actuellement prises en charge sont'setInterval'
,'setTimeout'
,'setImmediate'
et'Date'
. Par défaut :['setInterval', 'setTimeout', 'setImmediate', 'Date']
. Si aucun tableau n’est fourni, toutes les API liées au temps ('setInterval'
,'clearInterval'
,'setTimeout'
,'clearTimeout'
,'setImmediate'
,'clearImmediate'
et'Date'
) seront simulées par défaut.now
<number> | <Date> Un nombre ou un objet Date facultatif représentant l’heure initiale (en millisecondes) à utiliser comme valeur pourDate.now()
. Par défaut :0
.
Remarque : Lorsque vous activez la simulation pour un timer spécifique, sa fonction de suppression associée sera également simulée implicitement.
Remarque : La simulation de Date
affectera le comportement des timers simulés car ils utilisent la même horloge interne.
Exemple d’utilisation sans définir l’heure initiale :
import { mock } from 'node:test';
mock.timers.enable({ apis: ['setInterval'] });
const { mock } = require('node:test');
mock.timers.enable({ apis: ['setInterval'] });
L’exemple ci-dessus active la simulation pour le timer setInterval
et simule implicitement la fonction clearInterval
. Seules les fonctions setInterval
et clearInterval
de node:timers, node:timers/promises et globalThis
seront simulées.
Exemple d’utilisation avec l’heure initiale définie
import { mock } from 'node:test';
mock.timers.enable({ apis: ['Date'], now: 1000 });
const { mock } = require('node:test');
mock.timers.enable({ apis: ['Date'], now: 1000 });
Exemple d’utilisation avec un objet Date initial comme heure définie
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() });
Sinon, si vous appelez mock.timers.enable()
sans aucun paramètre :
Tous les timers ('setInterval'
, 'clearInterval'
, 'setTimeout'
, 'clearTimeout'
, 'setImmediate'
et 'clearImmediate'
) seront simulés. Les fonctions setInterval
, clearInterval
, setTimeout
, clearTimeout
, setImmediate
et clearImmediate
de node:timers
, node:timers/promises
et globalThis
seront simulées. Ainsi que l’objet Date
global.
timers.reset()
Ajouté dans : v20.4.0, v18.19.0
Cette fonction restaure le comportement par défaut de toutes les simulations qui ont été précédemment créées par cette instance MockTimers
et dissocie les simulations de l’instance MockTracker
.
Note : Après chaque fin de test, cette fonction est appelée sur le MockTracker
du contexte de test.
import { mock } from 'node:test';
mock.timers.reset();
const { mock } = require('node:test');
mock.timers.reset();
timers[Symbol.dispose]()
Appelle timers.reset()
.
timers.tick([milliseconds])
Ajouté dans : v20.4.0, v18.19.0
Avance le temps pour tous les minuteurs simulés.
milliseconds
<number> Le temps, en millisecondes, d’avancer les minuteurs. Par défaut :1
.
Note : Ceci diffère du comportement de setTimeout
dans Node.js et accepte uniquement les nombres positifs. Dans Node.js, setTimeout
avec des nombres négatifs n’est pris en charge que pour des raisons de compatibilité web.
L’exemple suivant simule une fonction setTimeout
et, en utilisant .tick
, avance dans le temps en déclenchant tous les minuteurs en attente.
import assert from 'node:assert';
import { test } from 'node:test';
test('simule setTimeout pour qu’il soit exécuté de manière synchrone sans avoir à attendre réellement', (context) => {
const fn = context.mock.fn();
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Avancer dans le temps
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
});
const assert = require('node:assert');
const { test } = require('node:test');
test('simule setTimeout pour qu’il soit exécuté de manière synchrone sans avoir à attendre réellement', (context) => {
const fn = context.mock.fn();
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(fn, 9999);
assert.strictEqual(fn.mock.callCount(), 0);
// Avancer dans le temps
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
});
Alternativement, la fonction .tick
peut être appelée plusieurs fois
import assert from 'node:assert';
import { test } from 'node:test';
test('simule setTimeout pour qu’il soit exécuté de manière synchrone sans avoir à attendre réellement', (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('simule setTimeout pour qu’il soit exécuté de manière synchrone sans avoir à attendre réellement', (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);
});
Avancer dans le temps en utilisant .tick
avancera également dans le temps pour tout objet Date
créé après l’activation de la simulation (si Date
a également été défini pour être simulé).
import assert from 'node:assert';
import { test } from 'node:test';
test('simule setTimeout pour qu’il soit exécuté de manière synchrone sans avoir à attendre réellement', (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);
// Avancer dans le temps
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('simule setTimeout pour qu’il soit exécuté de manière synchrone sans avoir à attendre réellement', (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);
// Avancer dans le temps
context.mock.timers.tick(9999);
assert.strictEqual(fn.mock.callCount(), 1);
assert.strictEqual(Date.now(), 9999);
});
Utilisation des fonctions clear
Comme mentionné, toutes les fonctions clear des minuteurs (clearTimeout
, clearInterval
et clearImmediate
) sont implicitement simulées. Regardez cet exemple utilisant setTimeout
:
import assert from 'node:assert';
import { test } from 'node:test';
test('simule setTimeout pour être exécuté de manière synchrone sans avoir à attendre réellement', (context) => {
const fn = context.mock.fn();
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['setTimeout'] });
const id = setTimeout(fn, 9999);
// Implicitement simulé également
clearTimeout(id);
context.mock.timers.tick(9999);
// Étant donné que setTimeout a été effacé, la fonction simulée ne sera jamais appelée
assert.strictEqual(fn.mock.callCount(), 0);
});
const assert = require('node:assert');
const { test } = require('node:test');
test('simule setTimeout pour être exécuté de manière synchrone sans avoir à attendre réellement', (context) => {
const fn = context.mock.fn();
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['setTimeout'] });
const id = setTimeout(fn, 9999);
// Implicitement simulé également
clearTimeout(id);
context.mock.timers.tick(9999);
// Étant donné que setTimeout a été effacé, la fonction simulée ne sera jamais appelée
assert.strictEqual(fn.mock.callCount(), 0);
});
Travailler avec les modules de minuteurs Node.js
Une fois que vous avez activé la simulation des minuteurs, les modules node:timers, node:timers/promises et les minuteurs du contexte global Node.js sont activés :
Remarque : La déstructuration des fonctions telles que import { setTimeout } from 'node:timers'
n’est actuellement pas prise en charge par cette API.
import assert from 'node:assert';
import { test } from 'node:test';
import nodeTimers from 'node:timers';
import nodeTimersPromises from 'node:timers/promises';
test('simule setTimeout pour être exécuté de manière synchrone sans avoir à attendre réellement', async (context) => {
const globalTimeoutObjectSpy = context.mock.fn();
const nodeTimerSpy = context.mock.fn();
const nodeTimerPromiseSpy = context.mock.fn();
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(globalTimeoutObjectSpy, 9999);
nodeTimers.setTimeout(nodeTimerSpy, 9999);
const promise = nodeTimersPromises.setTimeout(9999).then(nodeTimerPromiseSpy);
// Avance dans le temps
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('simule setTimeout pour être exécuté de manière synchrone sans avoir à attendre réellement', async (context) => {
const globalTimeoutObjectSpy = context.mock.fn();
const nodeTimerSpy = context.mock.fn();
const nodeTimerPromiseSpy = context.mock.fn();
// Choisissez éventuellement ce qu'il faut simuler
context.mock.timers.enable({ apis: ['setTimeout'] });
setTimeout(globalTimeoutObjectSpy, 9999);
nodeTimers.setTimeout(nodeTimerSpy, 9999);
const promise = nodeTimersPromises.setTimeout(9999).then(nodeTimerPromiseSpy);
// Avance dans le temps
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);
});
Dans Node.js, setInterval
de node:timers/promises est un AsyncGenerator
et est également pris en charge par cette API :
import assert from 'node:assert';
import { test } from 'node:test';
import nodeTimersPromises from 'node:timers/promises';
test('devrait cocher cinq fois en testant un cas d’utilisation réel', 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('devrait cocher cinq fois en testant un cas d’utilisation réel', 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()
Ajouté dans : v20.4.0, v18.19.0
Déclenche immédiatement tous les temporisateurs simulés en attente. Si l’objet Date
est également simulé, il avancera également l’objet Date
à l’heure du temporisateur le plus éloigné.
L’exemple ci-dessous déclenche immédiatement tous les temporisateurs en attente, ce qui les fait s’exécuter sans délai.
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);
});
Note : La fonction runAll()
est spécialement conçue pour déclencher les temporisateurs dans le contexte de la simulation de temporisateur. Elle n’a aucun effet sur les horloges système en temps réel ou les temporisateurs réels en dehors de l’environnement de simulation.
timers.setTime(milliseconds)
Ajouté dans : v21.2.0, v20.11.0
Définit l’horodatage Unix actuel qui sera utilisé comme référence pour tous les objets Date
simulés.
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);
});
Dates et minuteurs travaillant ensemble
Les dates et les objets minuteurs sont dépendants les uns des autres. Si vous utilisez setTime()
pour passer l'heure actuelle à l'objet Date
simulé, les minuteurs définis avec setTimeout
et setInterval
ne seront pas affectés.
Cependant, la méthode tick
fera avancer l'objet Date
simulé.
import assert from 'node:assert';
import { test } from 'node:test';
test('exécuter toutes les fonctions dans l\'ordre donné', (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, []);
// La date est avancée mais les minuteurs ne s'égrènent pas
assert.strictEqual(Date.now(), 12000);
});
const assert = require('node:assert');
const { test } = require('node:test');
test('exécuter toutes les fonctions dans l\'ordre donné', (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, []);
// La date est avancée mais les minuteurs ne s'égrènent pas
assert.strictEqual(Date.now(), 12000);
});
Classe : TestsStream
[Historique]
Version | Modifications |
---|---|
v20.0.0, v19.9.0, v18.17.0 | type ajouté aux événements test :pass et test :fail lorsque le test est une suite. |
v18.9.0, v16.19.0 | Ajouté dans : v18.9.0, v16.19.0 |
- Étend <Readable>
Un appel réussi à la méthode run()
renverra un nouvel objet <TestsStream>, diffusant en continu une série d'événements représentant l'exécution des tests. TestsStream
émettra des événements, dans l'ordre de la définition des tests.
Certains événements sont garantis d'être émis dans le même ordre que les tests sont définis, tandis que d'autres sont émis dans l'ordre dans lequel les tests s'exécutent.
Événement : 'test:coverage'
data
<Object>summary
<Object> Un objet contenant le rapport de couverture.files
<Array> Un tableau de rapports de couverture pour les fichiers individuels. Chaque rapport est un objet avec le schéma suivant :path
<string> Le chemin absolu du fichier.totalLineCount
<number> Le nombre total de lignes.totalBranchCount
<number> Le nombre total de branches.totalFunctionCount
<number> Le nombre total de fonctions.coveredLineCount
<number> Le nombre de lignes couvertes.coveredBranchCount
<number> Le nombre de branches couvertes.coveredFunctionCount
<number> Le nombre de fonctions couvertes.coveredLinePercent
<number> Le pourcentage de lignes couvertes.coveredBranchPercent
<number> Le pourcentage de branches couvertes.coveredFunctionPercent
<number> Le pourcentage de fonctions couvertes.functions
<Array> Un tableau de fonctions représentant la couverture des fonctions.name
<string> Le nom de la fonction.line
<number> Le numéro de la ligne où la fonction est définie.count
<number> Le nombre de fois que la fonction a été appelée.branches
<Array> Un tableau de branches représentant la couverture des branches.line
<number> Le numéro de la ligne où la branche est définie.count
<number> Le nombre de fois que la branche a été empruntée.lines
<Array> Un tableau de lignes représentant les numéros de ligne et le nombre de fois qu'elles ont été couvertes.line
<number> Le numéro de ligne.count
<number> Le nombre de fois que la ligne a été couverte.thresholds
<Object> Un objet indiquant si la couverture pour chaque type de couverture a été atteinte.function
<number> Le seuil de couverture des fonctions.branch
<number> Le seuil de couverture des branches.line
<number> Le seuil de couverture des lignes.totals
<Object> Un objet contenant un résumé de la couverture pour tous les fichiers.totalLineCount
<number> Le nombre total de lignes.totalBranchCount
<number> Le nombre total de branches.totalFunctionCount
<number> Le nombre total de fonctions.coveredLineCount
<number> Le nombre de lignes couvertes.coveredBranchCount
<number> Le nombre de branches couvertes.coveredFunctionCount
<number> Le nombre de fonctions couvertes.coveredLinePercent
<number> Le pourcentage de lignes couvertes.coveredBranchPercent
<number> Le pourcentage de branches couvertes.coveredFunctionPercent
<number> Le pourcentage de fonctions couvertes.workingDirectory
<string> Le répertoire de travail lorsque la couverture du code a commencé. Ceci est utile pour afficher les noms de chemin relatifs au cas où les tests auraient modifié le répertoire de travail du processus Node.js.nesting
<number> Le niveau d'imbrication du test.
Émis lorsque la couverture du code est activée et que tous les tests sont terminés.
Événement: 'test:complete'
data
<Object>column
<number> | <undefined> Le numéro de la colonne où le test est défini, ouundefined
si le test a été exécuté via le REPL.details
<Object> Métadonnées d'exécution supplémentaires.passed
<boolean> Indique si le test a réussi ou non.duration_ms
<number> La durée du test en millisecondes.error
<Error> | <undefined> Une erreur encapsulant l'erreur levée par le test s'il n'a pas réussi.cause
<Error> L'erreur réelle levée par le test.type
<string> | <undefined> Le type de test, utilisé pour indiquer s'il s'agit d'une suite.file
<string> | <undefined> Le chemin du fichier de test,undefined
si le test a été exécuté via le REPL.line
<number> | <undefined> Le numéro de ligne où le test est défini, ouundefined
si le test a été exécuté via le REPL.name
<string> Le nom du test.nesting
<number> Le niveau d'imbrication du test.testNumber
<number> Le numéro d'ordre du test.todo
<string> | <boolean> | <undefined> Présent sicontext.todo
est appeléskip
<string> | <boolean> | <undefined> Présent sicontext.skip
est appelé
Émis lorsqu'un test termine son exécution. Cet événement n'est pas émis dans le même ordre que les tests sont définis. Les événements de déclaration ordonnés correspondants sont 'test:pass'
et 'test:fail'
.
Événement : 'test:dequeue'
data
<Object>column
<number> | <undefined> Le numéro de la colonne où le test est défini, ouundefined
si le test a été exécuté via le REPL.file
<string> | <undefined> Le chemin d’accès au fichier de test,undefined
si le test a été exécuté via le REPL.line
<number> | <undefined> Le numéro de la ligne où le test est défini, ouundefined
si le test a été exécuté via le REPL.name
<string> Le nom du test.nesting
<number> Le niveau d’imbrication du test.
Émis lorsqu’un test est retiré de la file d’attente, juste avant son exécution. Il n’est pas garanti que cet événement soit émis dans le même ordre que les tests sont définis. L’événement ordonné de déclaration correspondant est 'test:start'
.
Événement : 'test:diagnostic'
data
<Object>column
<number> | <undefined> Le numéro de la colonne où le test est défini, ouundefined
si le test a été exécuté via le REPL.file
<string> | <undefined> Le chemin d’accès au fichier de test,undefined
si le test a été exécuté via le REPL.line
<number> | <undefined> Le numéro de la ligne où le test est défini, ouundefined
si le test a été exécuté via le REPL.message
<string> Le message de diagnostic.nesting
<number> Le niveau d’imbrication du test.
Émis lorsque context.diagnostic
est appelé. Il est garanti que cet événement sera émis dans le même ordre que les tests sont définis.
Événement : 'test:enqueue'
data
<Object>column
<number> | <undefined> Le numéro de colonne où le test est défini, ouundefined
si le test a été exécuté via le REPL.file
<string> | <undefined> Le chemin du fichier de test,undefined
si le test a été exécuté via le REPL.line
<number> | <undefined> Le numéro de ligne où le test est défini, ouundefined
si le test a été exécuté via le REPL.name
<string> Le nom du test.nesting
<number> Le niveau d'imbrication du test.
Émis lorsqu'un test est mis en file d'attente pour l'exécution.
Événement : 'test:fail'
data
<Object>column
<number> | <undefined> Le numéro de colonne où le test est défini, ouundefined
si le test a été exécuté via le REPL.details
<Object> Métadonnées d'exécution supplémentaires.duration_ms
<number> La durée du test en millisecondes.error
<Error> Une erreur encapsulant l'erreur lancée par le test.cause
<Error> L'erreur réelle lancée par le test.type
<string> | <undefined> Le type du test, utilisé pour indiquer s'il s'agit d'une suite.file
<string> | <undefined> Le chemin du fichier de test,undefined
si le test a été exécuté via le REPL.line
<number> | <undefined> Le numéro de ligne où le test est défini, ouundefined
si le test a été exécuté via le REPL.name
<string> Le nom du test.nesting
<number> Le niveau d'imbrication du test.testNumber
<number> Le numéro d'ordre du test.todo
<string> | <boolean> | <undefined> Présent sicontext.todo
est appeléskip
<string> | <boolean> | <undefined> Présent sicontext.skip
est appelé
Émis lorsqu'un test échoue. Cet événement est garanti d'être émis dans le même ordre que les tests sont définis. L'événement d'exécution correspondant est 'test:complete'
.
Événement : 'test:pass'
data
<Objet>column
<nombre> | <indéfini> Le numéro de colonne où le test est défini, ouundefined
si le test a été exécuté via le REPL.details
<Objet> Métadonnées d’exécution supplémentaires.duration_ms
<nombre> La durée du test en millisecondes.type
<chaîne de caractères> | <indéfini> Le type du test, utilisé pour indiquer s’il s’agit d’une suite.file
<chaîne de caractères> | <indéfini> Le chemin du fichier de test,undefined
si le test a été exécuté via le REPL.line
<nombre> | <indéfini> Le numéro de ligne où le test est défini, ouundefined
si le test a été exécuté via le REPL.name
<chaîne de caractères> Le nom du test.nesting
<nombre> Le niveau d’imbrication du test.testNumber
<nombre> Le numéro d’ordre du test.todo
<chaîne de caractères> | <booléen> | <indéfini> Présent sicontext.todo
est appeléskip
<chaîne de caractères> | <booléen> | <indéfini> Présent sicontext.skip
est appelé
Émis lorsqu’un test réussit. Cet événement est garanti d’être émis dans le même ordre que les tests sont définis. L’événement ordonné d’exécution correspondant est 'test:complete'
.
Événement : 'test:plan'
data
<Object>column
<number> | <undefined> Le numéro de colonne où le test est défini, ouundefined
si le test a été exécuté via le REPL.file
<string> | <undefined> Le chemin d'accès au fichier de test,undefined
si le test a été exécuté via le REPL.line
<number> | <undefined> Le numéro de ligne où le test est défini, ouundefined
si le test a été exécuté via le REPL.nesting
<number> Le niveau d'imbrication du test.count
<number> Le nombre de sous-tests qui ont été exécutés.
Émis lorsque tous les sous-tests d'un test donné sont terminés. Cet événement est garanti d'être émis dans le même ordre que les tests sont définis.
Événement : 'test:start'
data
<Object>column
<number> | <undefined> Le numéro de colonne où le test est défini, ouundefined
si le test a été exécuté via le REPL.file
<string> | <undefined> Le chemin d'accès au fichier de test,undefined
si le test a été exécuté via le REPL.line
<number> | <undefined> Le numéro de ligne où le test est défini, ouundefined
si le test a été exécuté via le REPL.name
<string> Le nom du test.nesting
<number> Le niveau d'imbrication du test.
Émis lorsqu'un test commence à signaler son propre statut et celui de ses sous-tests. Cet événement est garanti d'être émis dans le même ordre que les tests sont définis. L'événement ordonné d'exécution correspondant est 'test:dequeue'
.
Événement : 'test:stderr'
data
<Object>
Émis lorsqu'un test en cours d'exécution écrit dans stderr
. Cet événement n'est émis que si l'indicateur --test
est passé. Il n'est pas garanti que cet événement soit émis dans le même ordre que celui dans lequel les tests sont définis.
Événement : 'test:stdout'
data
<Object>
Émis lorsqu'un test en cours d'exécution écrit dans stdout
. Cet événement n'est émis que si l'indicateur --test
est passé. Il n'est pas garanti que cet événement soit émis dans le même ordre que celui dans lequel les tests sont définis.
Événement : 'test:summary'
data
<Object>counts
<Object> Un objet contenant les nombres des différents résultats de test.cancelled
<number> Le nombre total de tests annulés.failed
<number> Le nombre total de tests ayant échoué.passed
<number> Le nombre total de tests réussis.skipped
<number> Le nombre total de tests ignorés.suites
<number> Le nombre total de suites exécutées.tests
<number> Le nombre total de tests exécutés, à l'exclusion des suites.todo
<number> Le nombre total de tests TODO.topLevel
<number> Le nombre total de tests et de suites de niveau supérieur.duration_ms
<number> La durée de l'exécution du test en millisecondes.file
<string> | <undefined> Le chemin d'accès du fichier de test qui a généré le résumé. Si le résumé correspond à plusieurs fichiers, cette valeur estundefined
.success
<boolean> Indique si l'exécution du test est considérée comme réussie ou non. Si une condition d'erreur se produit, telle qu'un test échoué ou un seuil de couverture non atteint, cette valeur sera définie surfalse
.
Émis lorsqu'une exécution de test se termine. Cet événement contient des mesures relatives à l'exécution du test terminée et est utile pour déterminer si une exécution de test a réussi ou échoué. Si l'isolation des tests au niveau du processus est utilisée, un événement 'test:summary'
est généré pour chaque fichier de test en plus d'un résumé cumulatif final.
Événement : 'test:watch:drained'
Émis lorsqu’il n’y a plus de tests en file d’attente pour être exécutés en mode surveillance.
Classe : TestContext
[Historique]
Version | Modifications |
---|---|
v20.1.0, v18.17.0 | La fonction before a été ajoutée à TestContext. |
v18.0.0, v16.17.0 | Ajouté dans : v18.0.0, v16.17.0 |
Une instance de TestContext
est transmise à chaque fonction de test afin d’interagir avec l’exécuteur de tests. Toutefois, le constructeur TestContext
n’est pas exposé dans le cadre de l’API.
context.before([fn][, options])
Ajouté dans : v20.1.0, v18.17.0
fn
<Function> | <AsyncFunction> La fonction de hook. Le premier argument de cette fonction est un objetTestContext
. Si le hook utilise des rappels, la fonction de rappel est transmise comme deuxième argument. Par défaut : une fonction no-op.options
<Object> Options de configuration pour le hook. Les propriétés suivantes sont prises en charge :signal
<AbortSignal> Permet d’abandonner un hook en cours.timeout
<number> Nombre de millisecondes après lequel le hook échouera. Si elle n’est pas spécifiée, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.
Cette fonction est utilisée pour créer un hook s’exécutant avant le sous-test du test actuel.
context.beforeEach([fn][, options])
Ajouté dans : v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La fonction de hook. Le premier argument de cette fonction est un objetTestContext
. Si le hook utilise des rappels, la fonction de rappel est transmise comme deuxième argument. Par défaut : une fonction no-op.options
<Object> Options de configuration pour le hook. Les propriétés suivantes sont prises en charge :signal
<AbortSignal> Permet d’abandonner un hook en cours.timeout
<number> Nombre de millisecondes après lequel le hook échouera. Si elle n’est pas spécifiée, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.
Cette fonction est utilisée pour créer un hook s’exécutant avant chaque sous-test du test actuel.
test('test de niveau supérieur', async (t) => {
t.beforeEach((t) => t.diagnostic(`sur le point d’exécuter ${t.name}`));
await t.test(
'Il s’agit d’un sous-test',
(t) => {
assert.ok('une assertion pertinente ici');
},
);
});
context.after([fn][, options])
Ajouté dans : v19.3.0, v18.13.0
fn
<Function> | <AsyncFunction> La fonction de hook. Le premier argument de cette fonction est un objetTestContext
. Si le hook utilise des rappels, la fonction de rappel est transmise en tant que deuxième argument. Par défaut : une fonction no-op.options
<Object> Options de configuration pour le hook. Les propriétés suivantes sont prises en charge :signal
<AbortSignal> Permet d’abandonner un hook en cours.timeout
<number> Un nombre de millisecondes après lequel le hook échouera. S’il n’est pas spécifié, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.
Cette fonction est utilisée pour créer un hook qui s’exécute après la fin du test actuel.
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])
Ajouté dans : v18.8.0, v16.18.0
fn
<Function> | <AsyncFunction> La fonction de hook. Le premier argument de cette fonction est un objetTestContext
. Si le hook utilise des rappels, la fonction de rappel est transmise en tant que deuxième argument. Par défaut : une fonction no-op.options
<Object> Options de configuration pour le hook. Les propriétés suivantes sont prises en charge :signal
<AbortSignal> Permet d’abandonner un hook en cours.timeout
<number> Un nombre de millisecondes après lequel le hook échouera. S’il n’est pas spécifié, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.
Cette fonction est utilisée pour créer un hook qui s’exécute après chaque sous-test du test actuel.
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
Ajouté dans : v22.2.0, v20.15.0
Un objet contenant des méthodes d’assertion liées à context
. Les fonctions de niveau supérieur du module node:assert
sont exposées ici dans le but de créer des plans de test.
test('test', (t) => {
t.plan(1);
t.assert.strictEqual(true, true);
});
context.assert.snapshot(value[, options])
Ajouté dans : v22.3.0
[Stable: 1 - Experimental]
Stable: 1 Stability: 1.0 - Développement précoce
value
<any> Une valeur à sérialiser en chaîne. Si Node.js a été démarré avec l’indicateur--test-update-snapshots
, la valeur sérialisée est écrite dans le fichier d’instantané. Sinon, la valeur sérialisée est comparée à la valeur correspondante dans le fichier d’instantané existant.options
<Object> Options de configuration facultatives. Les propriétés suivantes sont prises en charge :serializers
<Array> Un tableau de fonctions synchrones utilisées pour sérialiservalue
en une chaîne.value
est passé comme seul argument à la première fonction de sérialisation. La valeur de retour de chaque sérialiseur est passée comme entrée au sérialiseur suivant. Une fois que tous les sérialiseurs ont été exécutés, la valeur résultante est forcée en une chaîne. Par défaut : Si aucun sérialiseur n’est fourni, les sérialiseurs par défaut de l’exécuteur de test sont utilisés.
Cette fonction implémente des assertions pour les tests d’instantané.
test('test d’instantané avec sérialisation par défaut', (t) => {
t.assert.snapshot({ value1: 1, value2: 2 });
});
test('test d’instantané avec sérialisation personnalisée', (t) => {
t.assert.snapshot({ value3: 3, value4: 4 }, {
serializers: [(value) => JSON.stringify(value)],
});
});
context.diagnostic(message)
Ajouté dans : v18.0.0, v16.17.0
message
<string> Message à signaler.
Cette fonction sert à écrire des diagnostics dans la sortie. Toute information de diagnostic est incluse à la fin des résultats du test. Cette fonction ne renvoie pas de valeur.
test('test de niveau supérieur', (t) => {
t.diagnostic('Un message de diagnostic');
});
context.filePath
Ajouté dans : v22.6.0, v20.16.0
Le chemin absolu du fichier de test qui a créé le test actuel. Si un fichier de test importe des modules supplémentaires qui génèrent des tests, les tests importés renverront le chemin du fichier de test racine.
context.fullName
Ajouté dans : v22.3.0
Le nom du test et de chacun de ses ancêtres, séparés par \>
.
context.name
Ajouté dans : v18.8.0, v16.18.0
Le nom du test.
context.plan(count)
[Historique]
Version | Modifications |
---|---|
v23.4.0 | Cette fonction n'est plus expérimentale. |
v22.2.0, v20.15.0 | Ajouté dans : v22.2.0, v20.15.0 |
count
<number> Le nombre d'assertions et de sous-tests qui doivent être exécutés.
Cette fonction sert à définir le nombre d'assertions et de sous-tests qui doivent être exécutés dans le test. Si le nombre d'assertions et de sous-tests qui sont exécutés ne correspond pas au nombre prévu, le test échouera.
test('test de niveau supérieur', (t) => {
t.plan(2);
t.assert.ok('une assertion pertinente ici');
t.test('sous-test', () => {});
});
Lorsque vous travaillez avec du code asynchrone, la fonction plan
peut être utilisée pour garantir que le nombre correct d'assertions est exécuté :
test('planification avec des flux', (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)
Ajouté dans : v18.0.0, v16.17.0
shouldRunOnlyTests
<boolean> Indique s'il faut exécuter ou non les testsonly
.
Si shouldRunOnlyTests
est truthy, le contexte de test n'exécutera que les tests pour lesquels l'option only
est définie. Sinon, tous les tests sont exécutés. Si Node.js n'a pas été démarré avec l'option de ligne de commande --test-only
, cette fonction est sans effet.
test('top level test', (t) => {
// Le contexte de test peut être configuré pour exécuter des sous-tests avec l'option 'only'.
t.runOnly(true);
return Promise.all([
t.test('this subtest is now skipped'),
t.test('this subtest is run', { only: true }),
]);
});
context.signal
Ajouté dans : v18.7.0, v16.17.0
- Type : <AbortSignal>
Peut être utilisé pour annuler les sous-tâches de test lorsque le test a été annulé.
test('top level test', async (t) => {
await fetch('some/uri', { signal: t.signal });
});
context.skip([message])
Ajouté dans : v18.0.0, v16.17.0
message
<string> Message de skip optionnel.
Cette fonction fait que la sortie du test indique que le test est ignoré. Si message
est fourni, il est inclus dans la sortie. L'appel de skip()
ne met pas fin à l'exécution de la fonction de test. Cette fonction ne renvoie pas de valeur.
test('top level test', (t) => {
// Assurez-vous de revenir ici également si le test contient une logique supplémentaire.
t.skip('this is skipped');
});
context.todo([message])
Ajouté dans : v18.0.0, v16.17.0
message
<string> MessageTODO
optionnel.
Cette fonction ajoute une directive TODO
à la sortie du test. Si message
est fourni, il est inclus dans la sortie. L'appel de todo()
ne met pas fin à l'exécution de la fonction de test. Cette fonction ne renvoie pas de valeur.
test('top level test', (t) => {
// Ce test est marqué comme `TODO`
t.todo('this is a todo');
});
context.test([name][, options][, fn])
[Historique]
Version | Modifications |
---|---|
v18.8.0, v16.18.0 | Ajout d'une option signal . |
v18.7.0, v16.17.0 | Ajout d'une option timeout . |
v18.0.0, v16.17.0 | Ajouté dans : v18.0.0, v16.17.0 |
name
<string> Le nom du sous-test, qui s'affiche lors du signalement des résultats des tests. Par défaut : la propriéténame
defn
, ou'\<anonymous\>'
sifn
n'a pas de nom.options
<Object> Options de configuration pour le sous-test. Les propriétés suivantes sont prises en charge :concurrency
<number> | <boolean> | <null> Si un nombre est fourni, ce nombre de tests s'exécuterait en parallèle au sein du thread d'application. Sitrue
, tous les sous-tests s'exécuteraient en parallèle. Sifalse
, un seul test s'exécuterait à la fois. Si non spécifié, les sous-tests héritent de cette valeur de leur parent. Par défaut :null
.only
<boolean> Si vrai, et que le contexte de test est configuré pour exécuter uniquement les testsonly
, ce test sera exécuté. Sinon, le test est ignoré. Par défaut :false
.signal
<AbortSignal> Permet d'abandonner un test en cours.skip
<boolean> | <string> Si vrai, le test est ignoré. Si une chaîne est fournie, cette chaîne est affichée dans les résultats du test comme motif d'ignorance du test. Par défaut :false
.todo
<boolean> | <string> Si vrai, le test est marqué commeTODO
. Si une chaîne est fournie, cette chaîne est affichée dans les résultats du test comme motif pour lequel le test estTODO
. Par défaut :false
.timeout
<number> Un nombre de millisecondes après lequel le test échouera. Si non spécifié, les sous-tests héritent de cette valeur de leur parent. Par défaut :Infinity
.plan
<number> Le nombre d'assertions et de sous-tests attendus lors de l'exécution du test. Si le nombre d'assertions exécutées dans le test ne correspond pas au nombre spécifié dans le plan, le test échouera. Par défaut :undefined
.
fn
<Function> | <AsyncFunction> La fonction testée. Le premier argument de cette fonction est un objetTestContext
. Si le test utilise des rappels, la fonction de rappel est passée en deuxième argument. Par défaut : une fonction no-op.Retourne : <Promise> Remplie avec
undefined
une fois le test terminé.
Cette fonction est utilisée pour créer des sous-tests dans le test actuel. Cette fonction se comporte de la même manière que la fonction test()
de niveau supérieur.
test('test de niveau supérieur', async (t) => {
await t.test(
'Ceci est un sous-test',
{ only: false, skip: false, concurrency: 1, todo: false, plan: 1 },
(t) => {
t.assert.ok('assertion pertinente ici');
},
);
});
Classe : SuiteContext
Ajoutée dans : v18.7.0, v16.17.0
Une instance de SuiteContext
est passée à chaque fonction de suite afin d’interagir avec le lanceur de test. Cependant, le constructeur SuiteContext
n’est pas exposé dans le cadre de l’API.
context.filePath
Ajoutée dans : v22.6.0
Le chemin absolu du fichier de test qui a créé la suite actuelle. Si un fichier de test importe des modules supplémentaires qui génèrent des suites, les suites importées renvoient le chemin du fichier de test racine.
context.name
Ajoutée dans : v18.8.0, v16.18.0
Le nom de la suite.
context.signal
Ajoutée dans : v18.7.0, v16.17.0
- Type : <AbortSignal>
Peut être utilisé pour abandonner les sous-tâches de test lorsque le test a été abandonné.