Étendre les Rapporteurs
Vous pouvez importer des rapporteurs depuis vitest/reporters
et les étendre pour créer vos propres rapporteurs personnalisés.
Étendre les Rapporteurs Intégrés
En général, il n'est pas nécessaire de créer votre rapporteur à partir de zéro. vitest
inclut plusieurs rapporteurs par défaut que vous pouvez étendre.
import { DefaultReporter } from 'vitest/reporters';
export default class MyDefaultReporter extends DefaultReporter {
// implémenter votre logique personnalisée
}
Bien sûr, vous pouvez créer votre rapporteur entièrement à partir de zéro. Il suffit d'étendre la classe BaseReporter
et d'implémenter les méthodes dont vous avez besoin.
Voici un exemple de rapporteur personnalisé :
// ./custom-reporter.js
import { BaseReporter } from 'vitest/reporters';
export default class CustomReporter extends BaseReporter {
onCollected() {
const files = this.ctx.state.getFiles(this.watchFilters);
this.reportTestSummary(files);
}
}
Vous pouvez également implémenter l'interface Reporter
:
// ./custom-reporter.js
import { Reporter } from 'vitest/reporters';
export default class CustomReporter implements Reporter {
onCollected() {
// afficher des informations personnalisées
}
}
Ensuite, vous pouvez utiliser votre rapporteur personnalisé dans le fichier vitest.config.ts
:
import { defineConfig } from 'vitest/config';
import CustomReporter from './custom-reporter.js';
export default defineConfig({
test: {
reporters: [new CustomReporter()],
},
});
Tâches Rapportées
WARNING
Il s'agit d'une API expérimentale. Des changements majeurs pourraient ne pas respecter SemVer. Veuillez épingler la version de Vitest lorsque vous l'utilisez.
Vous pouvez accéder à cette API en appelant vitest.state.getReportedEntity(runnerTask)
:
import type { Vitest } from 'vitest/node';
import type { RunnerTestFile } from 'vitest';
import type { Reporter, TestModule } from 'vitest/reporters';
class MyReporter implements Reporter {
ctx!: Vitest;
onInit(ctx: Vitest) {
this.ctx = ctx;
}
onFinished(files: RunnerTestFile[]) {
for (const fileTask of files) {
// notez que l'implémentation précédente de tâche utilise "file" au lieu de "module"
const testModule = this.ctx.state.getReportedEntity(
fileTask
) as TestModule;
for (const task of testModule.children) {
// ^?
console.log('finished', task.type, task.fullName);
}
}
}
}
Nous prévoyons de stabiliser cette API dans Vitest 2.1.
TestCase
TestCase
représente un test unitaire.
declare class TestCase {
readonly type = 'test' | 'custom';
/**
* Instance de la tâche.
* @experimental L'API de tâche publique est expérimentale et ne respecte pas SemVer.
*/
readonly task: RunnerTestCase | RunnerCustomCase;
/**
* Le projet associé au test.
*/
readonly project: TestProject;
/**
* Référence directe au module de test où le test est défini.
*/
readonly module: TestModule;
/**
* Nom du test.
*/
readonly name: string;
/**
* Nom complet du test incluant toutes les suites parentes séparées par `>`.
*/
readonly fullName: string;
/**
* Identifiant unique.
* Cet ID est déterministe et sera le même pour le même test sur plusieurs exécutions.
* L'ID est basé sur le nom du projet, l'ID du module et la position du test.
*/
readonly id: string;
/**
* Emplacement dans le module où le test a été défini.
* Les emplacements ne sont collectés que si `includeTaskLocation` est activé dans la configuration.
*/
readonly location: { line: number; column: number } | undefined;
/**
* Suite parente. Si le test a été appelé directement à l'intérieur du module, le parent sera le module en question.
*/
readonly parent: TestSuite | TestModule;
/**
* Options utilisées pour initier le test.
*/
readonly options: TaskOptions;
/**
* Vérifie si le test a réussi sans échouer la suite.
* Si le test n'est pas encore terminé ou a été ignoré, il retournera `true`.
*/
ok(): boolean;
/**
* Métadonnées personnalisées attachées au test pendant son exécution.
*/
meta(): TaskMeta;
/**
* Résultats du test. Renvoie `undefined` si le test n'est pas encore terminé ou vient d'être collecté.
*/
result(): TestResult | undefined;
/**
* Informations utiles sur le test, telles que la durée, l'utilisation de la mémoire, etc.
*/
diagnostic(): TestDiagnostic | undefined;
}
export type TestResult =
| TestResultPassed
| TestResultFailed
| TestResultSkipped;
export interface TestResultPassed {
/**
* Le test a réussi.
*/
state: 'passed';
/**
* Erreurs levées pendant l'exécution du test.
*
* **Note** : Si le test a été relancé avec succès, les erreurs seront toujours rapportées.
*/
errors: TestError[] | undefined;
}
export interface TestResultFailed {
/**
* Le test n'a pas réussi à s'exécuter.
*/
state: 'failed';
/**
* Erreurs levées pendant l'exécution du test.
*/
errors: TestError[];
}
export interface TestResultSkipped {
/**
* Le test a été ignoré avec les drapeaux `only`, `skip` ou `todo`.
* Vous pouvez voir lequel a été utilisé dans l'option `mode`.
*/
state: 'skipped';
/**
* Les tests ignorés ne génèrent pas d'erreurs.
*/
errors: undefined;
}
export interface TestDiagnostic {
/**
* Si la durée du test dépasse `slowTestThreshold`.
*/
slow: boolean;
/**
* La quantité de mémoire utilisée par le test (en octets).
* Cette valeur n'est disponible que si le test a été exécuté avec le drapeau `logHeapUsage`.
*/
heap: number | undefined;
/**
* Le temps nécessaire à l'exécution du test (en ms).
*/
duration: number;
/**
* L'heure (en ms) à laquelle le test a commencé.
*/
startTime: number;
/**
* Le nombre de fois où le test a été relancé.
*/
retryCount: number;
/**
* Le nombre de fois où le test a été répété, tel que configuré par l'option `repeats`.
* Cette valeur peut être inférieure si le test a échoué pendant la répétition et qu'aucune `retry` n'est configurée.
*/
repeatCount: number;
/**
* Si le test a réussi lors d'une deuxième tentative.
*/
flaky: boolean;
}
TestSuite
TestSuite
représente une suite de tests qui peut contenir d'autres tests et suites.
declare class TestSuite {
readonly type = 'suite';
/**
* Instance de la tâche.
* @experimental L'API de tâche publique est expérimentale et ne respecte pas SemVer.
*/
readonly task: RunnerTestSuite;
/**
* Le projet associé à la suite.
*/
readonly project: TestProject;
/**
* Référence directe au module de test où la suite est définie.
*/
readonly module: TestModule;
/**
* Nom de la suite.
*/
readonly name: string;
/**
* Nom complet de la suite incluant toutes les suites parentes séparées par `>`.
*/
readonly fullName: string;
/**
* Identifiant unique.
* Cet ID est déterministe et sera le même pour la même suite sur plusieurs exécutions.
* L'ID est basé sur le nom du projet, l'ID du module et la position de la suite.
*/
readonly id: string;
/**
* Emplacement dans le module où la suite a été définie.
* Les emplacements ne sont collectés que si `includeTaskLocation` est activé dans la configuration.
*/
readonly location: { line: number; column: number } | undefined;
/**
* Collection de suites et de tests faisant partie de cette suite.
*/
readonly children: TaskCollection;
/**
* Options utilisées pour initier la suite.
*/
readonly options: TaskOptions;
}
TestModule
TestModule
représente un fichier de test unique qui contient des suites et des tests.
declare class TestModule extends SuiteImplementation {
readonly type = 'module';
/**
* Instance de la tâche.
* @experimental L'API de tâche publique est expérimentale et ne respecte pas SemVer.
*/
readonly task: RunnerTestFile;
/**
* Collection de suites et de tests faisant partie de ce module.
*/
readonly children: TestCollection;
/**
* Il s'agit généralement d'un chemin de fichier unix absolu.
* Il peut s'agir d'un ID virtuel si le fichier n'est pas sur le disque.
* Cette valeur correspond à l'identifiant `ModuleGraph` dans Vite.
*/
readonly moduleId: string;
/**
* Informations utiles sur le module (durée, utilisation de la mémoire, etc.).
* Si le module n'a pas encore été exécuté, toutes les valeurs de diagnostic retourneront `0`.
*/
diagnostic(): ModuleDiagnostic;
}
export interface ModuleDiagnostic {
/**
* Le temps nécessaire à l'importation et à l'initialisation d'un environnement.
*/
environmentSetupDuration: number;
/**
* Le temps nécessaire à Vitest pour configurer l'infrastructure de test (runner, mocks, etc.).
*/
prepareDuration: number;
/**
* Le temps nécessaire à l'importation du module de test.
* Cela inclut l'importation de tout dans le module et l'exécution des callbacks de suite.
*/
collectDuration: number;
/**
* Le temps nécessaire à l'importation du module de configuration.
*/
setupDuration: number;
/**
* Durée cumulée de tous les tests et hooks dans le module.
*/
duration: number;
}
TestCollection
TestCollection
représente une collection de suites et de tests. Elle fournit également des méthodes utiles pour itérer sur ses éléments.
declare class TestCollection {
/**
* Retourne le test ou la suite à un index spécifique dans le tableau.
*/
at(index: number): TestCase | TestSuite | undefined;
/**
* Le nombre de tests et de suites dans la collection.
*/
size: number;
/**
* Retourne la collection sous forme de tableau pour une manipulation plus facile.
*/
array(): (TestCase | TestSuite)[];
/**
* Filtre toutes les suites faisant partie de cette collection et de ses enfants.
*/
allSuites(): IterableIterator<TestSuite>;
/**
* Filtre tous les tests faisant partie de cette collection et de ses enfants.
*/
allTests(state?: TestResult['state'] | 'running'): IterableIterator<TestCase>;
/**
* Filtre uniquement les tests faisant partie de cette collection.
*/
tests(state?: TestResult['state'] | 'running'): IterableIterator<TestCase>;
/**
* Filtre uniquement les suites faisant partie de cette collection.
*/
suites(): IterableIterator<TestSuite>;
[Symbol.iterator](): IterableIterator<TestSuite | TestCase>;
}
Par exemple, vous pouvez itérer sur tous les tests à l'intérieur d'un module en appelant testModule.children.allTests()
:
function onFileCollected(testModule: TestModule): void {
console.log('collecting tests in', testModule.moduleId);
// itérer sur tous les tests et suites dans le module
for (const task of testModule.children.allTests()) {
console.log('collected', task.type, task.fullName);
}
}
TestProject
TestProject
est un projet associé au module. Chaque test et suite à l'intérieur de ce module fera référence au même projet.
Le projet est utile pour obtenir la configuration ou le contexte fourni.
declare class TestProject {
/**
* L'instance globale de vitest.
* @experimental L'API publique de Vitest est expérimentale et ne respecte pas SemVer.
*/
readonly vitest: Vitest;
/**
* Le projet de l'espace de travail auquel ce projet de test est associé.
* @experimental L'API publique de Vitest est expérimentale et ne respecte pas SemVer.
*/
readonly workspaceProject: WorkspaceProject;
/**
* Instance du serveur de développement de Vite. Chaque projet d'espace de travail a son propre serveur.
*/
readonly vite: ViteDevServer;
/**
* Configuration du projet résolue.
*/
readonly config: ResolvedProjectConfig;
/**
* Configuration globale résolue. S'il n'y a pas de projets d'espace de travail, ce sera la même chose que `config`.
*/
readonly globalConfig: ResolvedConfig;
/**
* Configuration du projet sérialisée. C'est la configuration que les tests reçoivent.
*/
get serializedConfig(): SerializedConfig;
/**
* Le nom du projet ou une chaîne vide s'il n'est pas défini.
*/
name(): string;
/**
* Contexte personnalisé fourni au projet.
*/
context(): ProvidedContext;
/**
* Fournit un contexte sérialisable personnalisé au projet. Ce contexte sera disponible pour les tests une fois qu'ils s'exécuteront.
*/
provide<T extends keyof ProvidedContext & string>(
key: T,
value: ProvidedContext[T]
): void;
}
Rapporteurs Exportés
vitest
inclut quelques rapporteurs intégrés que vous pouvez utiliser directement.
Rapporteurs intégrés :
BasicReporter
DefaultReporter
DotReporter
JsonReporter
VerboseReporter
TapReporter
JUnitReporter
TapFlatReporter
HangingProcessReporter
Rapporteurs abstraits de base :
BaseReporter
Rapporteurs d'interface :
Reporter