vi
Vitest met à disposition des fonctions utilitaires via son assistant vi
. Vous pouvez y accéder globalement (si la configuration globale est activée) ou l'importer directement depuis vitest
:
import { vi } from 'vitest';
Simulation de modules
Cette section décrit l'API que vous pouvez utiliser pour simuler un module. Notez que Vitest ne prend pas en charge la simulation des modules importés avec require()
.
vi.mock
- Type :
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Type :
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
Remplace toutes les importations du path
spécifié par un autre module. Vous pouvez utiliser les alias Vite configurés dans le chemin. L'appel à vi.mock
est remonté (hoisted), il sera donc toujours exécuté avant toutes les importations, quel que soit l'endroit où vous l'appelez. Si vous avez besoin de référencer des variables externes à sa portée, vous pouvez les définir à l'intérieur de vi.hoisted
et les référencer dans vi.mock
.
WARNING
vi.mock
ne fonctionne que pour les modules importés avec le mot-clé import
. Il ne fonctionne pas avec require
.
Pour remonter vi.mock
, Vitest analyse statiquement vos fichiers. Cela signifie que vi
, s'il n'est pas directement importé du package vitest
(par exemple, depuis un fichier utilitaire), ne peut pas être utilisé. Utilisez vi.mock
avec vi
importé de vitest
, ou activez l'option de configuration globals
.
Vitest ne simulera pas les modules importés dans un fichier de setup car ils sont déjà mis en cache lors de l'exécution du fichier de test. Vous pouvez appeler vi.resetModules()
à l'intérieur de vi.hoisted
pour effacer tous les caches de modules avant d'exécuter un fichier de test.
Si la fonction factory
est définie, toutes les importations retourneront son résultat. Vitest n'appelle la factory qu'une seule fois et met en cache les résultats pour les importations ultérieures jusqu'à ce que vi.unmock
ou vi.doUnmock
soit appelé.
Contrairement à jest
, la factory peut être asynchrone. Vous pouvez utiliser vi.importActual
ou un helper où la factory est passée en premier argument, et obtenir le module original à l'intérieur.
Depuis Vitest 2.1, vous pouvez également fournir un objet avec une propriété spy
au lieu d'une fonction factory. Si spy
est true
, Vitest simulera automatiquement le module, mais ne remplacera pas l'implémentation des exports. Ceci est utile si vous souhaitez simplement vous assurer qu'une méthode exportée a été appelée correctement par une autre méthode.
import { calculator } from './src/calculator.ts';
vi.mock('./src/calculator.ts', { spy: true });
// appelle l'implémentation originale,
// mais permet de vérifier le comportement plus tard
const result = calculator(1, 2);
expect(result).toBe(3);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);
Vitest prend également en charge une promesse de module plutôt qu'une simple chaîne de caractères dans les méthodes vi.mock
et vi.doMock
pour un meilleur support IDE. Lorsque le fichier est déplacé, le chemin sera mis à jour, et importOriginal
hérite automatiquement du type. L'utilisation de cette signature forcera également le type de retour de la factory à être compatible avec le module original (tout en conservant les exports facultatifs).
// @filename: ./path/to/module.js
export declare function total(...numbers: number[]): number;
// @filename: test.js
import { vi } from 'vitest';
// ---cut---
vi.mock(import('./path/to/module.js'), async importOriginal => {
const mod = await importOriginal(); // le type est inféré
// ^?
return {
...mod,
// remplacer certains exports
total: vi.fn(),
};
});
En interne, Vitest travaille toujours avec une chaîne de caractères et non avec un objet module.
Si vous utilisez TypeScript avec des alias paths
configurés dans tsconfig.json
, le compilateur ne pourra pas résoudre correctement les types d'importation. Pour que cela fonctionne, assurez-vous de remplacer toutes les importations utilisant des alias par leurs chemins relatifs correspondants. Par exemple, utilisez import('./path/to/module.js')
au lieu de import('@/module')
.
WARNING
vi.mock
est remonté (c'est-à-dire déplacé) en haut du fichier. Cela signifie que peu importe où vous l'écrivez (que ce soit à l'intérieur de beforeEach
ou test
), il sera en fait appelé avant ces blocs.
Cela signifie également que vous ne pouvez pas utiliser de variables définies en dehors de la factory à l'intérieur de celle-ci.
Si vous avez besoin d'utiliser des variables à l'intérieur de la factory, essayez vi.doMock
. Il fonctionne de la même manière mais n'est pas remonté. Sachez qu'il ne simulera que les importations qui suivent son appel.
Vous pouvez également référencer des variables définies par la méthode vi.hoisted
:
import { namedExport } from './path/to/module.js';
const mocks = vi.hoisted(() => {
return {
namedExport: vi.fn(),
};
});
vi.mock('./path/to/module.js', () => {
return {
namedExport: mocks.namedExport,
};
});
vi.mocked(namedExport).mockReturnValue(100);
expect(namedExport()).toBe(100);
expect(namedExport).toBe(mocks.namedExport);
WARNING
Si vous simulez un module avec un export par défaut, vous devrez fournir une clé default
dans l'objet retourné par la fonction factory. Il s'agit d'une spécificité des modules ES ; par conséquent, la documentation de jest
peut différer car jest
utilise des modules CommonJS. Par exemple,
vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
// etc...
};
});
S'il existe un dossier __mocks__
à côté d'un fichier que vous simulez, et que la factory n'est pas fournie, Vitest essaiera de trouver un fichier du même nom dans le sous-dossier __mocks__
et de l'utiliser comme module effectif. Si vous simulez une dépendance, Vitest essaiera de trouver un dossier __mocks__
à la racine du projet (par défaut, process.cwd()
). Vous pouvez spécifier à Vitest où se trouvent les dépendances via l'option de configuration deps.moduleDirectories
.
Par exemple, vous avez cette structure de fichiers :
- __mocks__
- axios.js
- src
__mocks__
- increment.js
- increment.js
- tests
- increment.test.js
Si vous appelez vi.mock
dans un fichier de test sans factory ni options fournies, il trouvera un fichier dans le dossier __mocks__
à utiliser comme module :
// increment.test.js
import { vi } from 'vitest';
// axios est un export par défaut de `__mocks__/axios.js`
import axios from 'axios';
// increment est un export nommé de `src/__mocks__/increment.js`
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
Notez que si vous n'appelez pas vi.mock
, les modules ne sont pas simulés automatiquement. Pour reproduire le comportement d'automocking de Jest (simulation automatique), vous pouvez appeler vi.mock
pour chaque module requis à l'intérieur de setupFiles
.
S'il n'y a pas de dossier __mocks__
ou de factory fournie, Vitest importera le module original et simulera automatiquement toutes ses exportations. Pour les règles appliquées, voir algorithme.
vi.doMock
- Type :
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Type :
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
Identique à vi.mock
, mais il n'est pas remonté en haut du fichier, vous pouvez donc référencer des variables définies dans la portée globale du fichier. La prochaine importation dynamique de ce module sera simulée.
WARNING
Cela ne simulera pas les modules qui ont été importés avant l'appel de cette méthode. N'oubliez pas que toutes les importations statiques en ESM sont toujours remontées, donc placer cet appel avant une importation statique ne garantit pas qu'il sera exécuté avant l'importation :
vi.doMock('./increment.js'); // ceci sera appelé _après_ l'instruction import
import { increment } from './increment.js';
// ./increment.js
export function increment(number) {
return number + 1;
}
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';
// le module n'est pas simulé, car vi.doMock n'est pas encore appelé
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// vous pouvez accéder aux variables à l'intérieur d'une factory
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('l\'importation du module suivant importe le module simulé', async () => {
// l'importation originale N'A PAS ÉTÉ SIMULÉE, car vi.doMock est évalué APRÈS les importations
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// la nouvelle importation dynamique retourne le module simulé
expect(mockedIncrement(1)).toBe(101);
expect(mockedIncrement(1)).toBe(102);
expect(mockedIncrement(1)).toBe(103);
});
vi.mocked
- Type :
<T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>
- Type :
<T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>
Fonction utilitaire de typage pour TypeScript. Retourne simplement l'objet qui a été passé.
Lorsque partial
est true
, le type de retour attendu sera Partial<T>
. Par défaut, cela indique à TypeScript que seules les valeurs de premier niveau sont simulées. Vous pouvez passer { deep: true }
comme deuxième argument pour indiquer à TypeScript que l'objet entier est simulé.
// example.ts
export function add(x: number, y: number): number {
return x + y;
}
export function fetchSomething(): Promise<Response> {
return fetch('https://vitest.dev/');
}
// example.test.ts
import * as example from './example';
vi.mock('./example');
test('1 + 1 est égal à 10', async () => {
vi.mocked(example.add).mockReturnValue(10);
expect(example.add(1, 1)).toBe(10);
});
test('simuler la valeur de retour avec un typage seulement partiellement correct', async () => {
vi.mocked(example.fetchSomething).mockResolvedValue(new Response('hello'));
vi.mocked(example.fetchSomething, { partial: true }).mockResolvedValue({
ok: false,
});
// vi.mocked(example.someFn).mockResolvedValue({ ok: false }) // ceci est une erreur de type
});
vi.importActual
- Type :
<T>(path: string) => Promise<T>
Importe un module, en ignorant toute simulation. Peut être utile si vous souhaitez simuler un module partiellement.
vi.mock('./example.js', async () => {
const axios = await vi.importActual('./example.js');
return { ...axios, get: vi.fn() };
});
vi.importMock
- Type :
<T>(path: string) => Promise<MaybeMockedDeep<T>>
Importe un module dont toutes les propriétés (y compris les propriétés imbriquées) sont simulées. Suit les mêmes règles que vi.mock
. Pour les règles appliquées, voir algorithme.
vi.unmock
- Type :
(path: string | Promise<Module>) => void
Supprime le module de la liste des modules simulés. Toute importation ultérieure de ce module retournera le module original même s'il a été simulé auparavant. Cet appel est remonté en haut du fichier, il ne désactivera donc la simulation que pour les modules définis dans les setupFiles
, par exemple.
vi.doUnmock
- Type :
(path: string | Promise<Module>) => void
Identique à vi.unmock
, mais n'est pas remonté en haut du fichier. La prochaine importation du module importera le module original au lieu du module simulé. Cela ne désactivera pas la simulation des modules précédemment importés.
// ./increment.js
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// increment est déjà simulé, car vi.mock est remonté
increment(1) === 100;
// ceci est remonté, et la factory est appelée avant l'importation à la ligne 1
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// tous les appels sont simulés, et `increment` retourne toujours 100
increment(1) === 100;
increment(30) === 100;
// ceci n'est pas remonté, donc une autre importation retournera un module non simulé
vi.doUnmock('./increment.js');
// ceci retourne TOUJOURS 100, car `vi.doUnmock` ne réévalue pas un module
increment(1) === 100;
increment(30) === 100;
// la prochaine importation n'est pas simulée, maintenant `increment` est la fonction originale qui retourne count + 1
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- Type :
() => Vitest
Réinitialise la liste des modules en vidant le cache de tous les modules. Cela permet aux modules d'être réévalués lors d'une nouvelle importation. Les importations de niveau supérieur ne peuvent pas être réévaluées. Peut être utile pour isoler les modules dont l'état local entre en conflit entre les tests.
import { vi } from 'vitest';
import { data } from './data.js'; // Ne sera pas réévalué avant chaque test
beforeEach(() => {
vi.resetModules();
});
test('changer l\'état', async () => {
const mod = await import('./some/path.js'); // Sera réévalué
mod.changeLocalState('nouvelle valeur');
expect(mod.getLocalState()).toBe('nouvelle valeur');
});
test('le module a l\'ancien état', async () => {
const mod = await import('./some/path.js'); // Sera réévalué
expect(mod.getLocalState()).toBe('ancienne valeur');
});
WARNING
Ne réinitialise pas la liste des mocks. Pour effacer la liste des mocks, utilisez vi.unmock
ou vi.doUnmock
.
vi.dynamicImportSettled
Attend que toutes les importations dynamiques soient chargées. Utile si vous avez un appel synchrone qui déclenche l'importation d'un module et que vous ne pouvez pas attendre sa résolution autrement.
import { expect, test } from 'vitest';
// impossible de suivre l'importation car la Promesse n'est pas retournée
function renderComponent() {
import('./component.js').then(({ render }) => {
render();
});
}
test('les opérations sont résolues', async () => {
renderComponent();
await vi.dynamicImportSettled();
expect(document.querySelector('.component')).not.toBeNull();
});
TIP
Si lors d'une importation dynamique une autre importation dynamique est lancée, cette méthode attendra que toutes soient résolues.
Cette méthode attendra également le prochain tick setTimeout
après la résolution de l'importation, afin que toutes les opérations synchrones soient terminées au moment où elle est résolue.
Simulation de fonctions et d'objets
Cette section décrit comment travailler avec les mocks de méthodes et remplacer les variables d'environnement et globales.
vi.fn
- Type :
(fn?: Function) => Mock
Crée un espion sur une fonction, bien qu'il puisse être créé sans fonction spécifique. Chaque fois qu'une fonction est invoquée, elle enregistre ses arguments d'appel, ses valeurs de retour et ses instances. De plus, vous pouvez manipuler son comportement avec des méthodes. Si aucune fonction n'est donnée, le mock retournera undefined
lorsqu'il est invoqué.
const getApples = vi.fn(() => 0);
getApples();
expect(getApples).toHaveBeenCalled();
expect(getApples).toHaveReturnedWith(0);
getApples.mockReturnValueOnce(5);
const res = getApples();
expect(res).toBe(5);
expect(getApples).toHaveNthReturnedWith(2, 5);
vi.isMockFunction
- Type :
(fn: Function) => boolean
Vérifie qu'un paramètre donné est une fonction mock. Si vous utilisez TypeScript, cela permettra également d'affiner son type.
vi.clearAllMocks
Appellera .mockClear()
sur tous les espions. Cela effacera l'historique des appels des mocks, mais ne réinitialisera pas leur implémentation à celle par défaut.
vi.resetAllMocks
Appellera .mockReset()
sur tous les espions. Cela effacera l'historique des appels des mocks et réinitialisera leur implémentation à une fonction vide (qui retournera undefined
).
vi.restoreAllMocks
Appellera .mockRestore()
sur tous les espions. Cela effacera l'historique des appels des mocks et réinitialisera leur implémentation à celle d'origine.
vi.spyOn
- Type :
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
Crée un espion sur une méthode ou un getter/setter d'un objet similaire à vi.fn()
. Il retourne une fonction mock.
let apples = 0;
const cart = {
getApples: () => 42,
};
const spy = vi.spyOn(cart, 'getApples').mockImplementation(() => apples);
apples = 1;
expect(cart.getApples()).toBe(1);
expect(spy).toHaveBeenCalled();
expect(spy).toHaveReturnedWith(1);
TIP
Vous pouvez appeler vi.restoreAllMocks
à l'intérieur de afterEach
(ou activer test.restoreMocks
) pour restaurer toutes les méthodes à leurs implémentations d'origine. Cela restaurera le descripteur d'objet d'origine, vous ne pourrez donc pas modifier l'implémentation de la méthode :
const cart = {
getApples: () => 42,
};
const spy = vi.spyOn(cart, 'getApples').mockReturnValue(10);
console.log(cart.getApples()); // 10
vi.restoreAllMocks();
console.log(cart.getApples()); // 42
spy.mockReturnValue(10);
console.log(cart.getApples()); // toujours 42 !
TIP
Il n'est pas possible d'espionner les méthodes exportées en Mode Navigateur. Au lieu de cela, vous pouvez espionner chaque méthode exportée en appelant vi.mock("./file-path.js", { spy: true })
. Cela simulera chaque export tout en conservant son implémentation d'origine, vous permettant de vérifier si la méthode a été appelée correctement.
import { calculator } from './src/calculator.ts';
vi.mock('./src/calculator.ts', { spy: true });
calculator(1, 2);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);
Et bien qu'il soit possible d'espionner les exports dans jsdom
ou d'autres environnements Node.js, cela pourrait changer à l'avenir.
vi.stubEnv
- Type :
<T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => Vitest
Modifie la valeur d'une variable d'environnement dans process.env
et import.meta.env
. Vous pouvez restaurer sa valeur en appelant vi.unstubAllEnvs
.
import { vi } from 'vitest';
// `process.env.NODE_ENV` et `import.meta.env.NODE_ENV`
// sont "development" avant d'appeler "vi.stubEnv"
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
vi.stubEnv('NODE_ENV', undefined);
process.env.NODE_ENV === undefined;
import.meta.env.NODE_ENV === undefined;
// ne modifie pas les autres envs
import.meta.env.MODE === 'development';
TIP
Vous pouvez également modifier la valeur en l'affectant simplement, mais vous ne pourrez pas utiliser vi.unstubAllEnvs
pour restaurer la valeur précédente :
import.meta.env.MODE = 'test';
vi.unstubAllEnvs
- Type :
() => Vitest
Restaure toutes les valeurs import.meta.env
et process.env
qui ont été modifiées avec vi.stubEnv
. Lorsqu'elle est appelée pour la première fois, Vitest se souvient de la valeur d'origine et la conservera jusqu'à ce que unstubAllEnvs
soit appelé à nouveau.
import { vi } from 'vitest';
// `process.env.NODE_ENV` et `import.meta.env.NODE_ENV`
// sont "development" avant d'appeler stubEnv
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
vi.stubEnv('NODE_ENV', 'staging');
process.env.NODE_ENV === 'staging';
import.meta.env.NODE_ENV === 'staging';
vi.unstubAllEnvs();
// restaure à la valeur qui a été stockée avant le premier appel "stubEnv"
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
- Type :
(name: string | number | symbol, value: unknown) => Vitest
Modifie la valeur d'une variable globale. Vous pouvez restaurer sa valeur d'origine en appelant vi.unstubAllGlobals
.
import { vi } from 'vitest';
// `innerWidth` est "0" avant d'appeler stubGlobal
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// si vous utilisez jsdom ou happy-dom
window.innerWidth === 100;
TIP
Vous pouvez également modifier la valeur en l'affectant simplement à globalThis
ou window
(si vous utilisez l'environnement jsdom
ou happy-dom
), mais vous ne pourrez pas utiliser vi.unstubAllGlobals
pour restaurer la valeur d'origine :
globalThis.innerWidth = 100;
// si vous utilisez jsdom ou happy-dom
window.innerWidth = 100;
vi.unstubAllGlobals
- Type :
() => Vitest
Restaure toutes les valeurs globales dans globalThis
/global
(et window
/top
/self
/parent
, si vous utilisez l'environnement jsdom
ou happy-dom
) qui ont été modifiées avec vi.stubGlobal
. Lorsqu'elle est appelée pour la première fois, Vitest se souvient de la valeur d'origine et la conservera jusqu'à ce que unstubAllGlobals
soit appelé à nouveau.
import { vi } from 'vitest';
const Mock = vi.fn();
// IntersectionObserver est "undefined" avant d'appeler "stubGlobal"
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// si vous utilisez jsdom ou happy-dom
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// lève une ReferenceError, car elle n'est pas définie
IntersectionObserver === undefined;
Faux minuteurs
Cette section décrit comment travailler avec les faux minuteurs.
vi.advanceTimersByTime
- Type :
(ms: number) => Vitest
Cette méthode exécutera chaque minuteur démarré jusqu'à ce que le nombre de millisecondes spécifié soit écoulé ou que la file d'attente soit vide - selon ce qui arrive en premier.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersByTime(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersByTimeAsync
- Type :
(ms: number) => Promise<Vitest>
Cette méthode exécutera chaque minuteur démarré jusqu'à ce que le nombre de millisecondes spécifié soit écoulé ou que la file d'attente soit vide - selon ce qui arrive en premier. Cela inclura les minuteurs définis de manière asynchrone.
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersByTimeAsync(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersToNextTimer
- Type :
() => Vitest
Appellera le prochain minuteur disponible. Utile pour faire des assertions entre chaque appel de minuteur. Vous pouvez enchaîner les appels pour gérer les minuteurs vous-même.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer(); // log: 3
vi.advanceTimersToNextTimerAsync
- Type :
() => Promise<Vitest>
Appellera le prochain minuteur disponible et attendra qu'il soit résolu s'il a été défini de manière asynchrone. Utile pour faire des assertions entre chaque appel de minuteur.
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersToNextTimerAsync(); // log: 1
expect(console.log).toHaveBeenCalledWith(1);
await vi.advanceTimersToNextTimerAsync(); // log: 2
await vi.advanceTimersToNextTimerAsync(); // log: 3
vi.advanceTimersToNextFrame 2.1.0+
- Type :
() => Vitest
Similaire à vi.advanceTimersByTime
, mais avancera les minuteurs du nombre de millisecondes nécessaires pour exécuter les callbacks actuellement planifiés avec requestAnimationFrame
.
let frameRendered = false;
requestAnimationFrame(() => {
frameRendered = true;
});
vi.advanceTimersToNextFrame();
expect(frameRendered).toBe(true);
vi.getTimerCount
- Type :
() => number
Obtient le nombre de minuteurs en attente.
vi.clearAllTimers
Supprime tous les minuteurs qui sont planifiés pour s'exécuter. Ces minuteurs ne s'exécuteront jamais à l'avenir.
vi.getMockedSystemTime
- Type :
() => Date | null
Retourne la date actuelle simulée qui a été définie à l'aide de setSystemTime
. Si la date n'est pas simulée, la méthode retournera null
.
vi.getRealSystemTime
- Type :
() => number
Lorsque vous utilisez vi.useFakeTimers
, les appels à Date.now
sont simulés. Si vous avez besoin d'obtenir l'heure réelle en millisecondes, vous pouvez appeler cette fonction.
vi.runAllTicks
- Type :
() => Vitest
Appelle chaque microtâche qui a été mise en file d'attente par process.nextTick
. Cela exécutera également toutes les microtâches planifiées par elles-mêmes.
vi.runAllTimers
- Type :
() => Vitest
Cette méthode exécutera chaque minuteur démarré jusqu'à ce que la file d'attente des minuteurs soit vide. Cela signifie que chaque minuteur appelé pendant runAllTimers
sera déclenché. Si vous avez un intervalle infini, il lèvera une erreur après 10 000 tentatives (peut être configuré avec fakeTimers.loopLimit
).
let i = 0;
setTimeout(() => console.log(++i));
const interval = setInterval(() => {
console.log(++i);
if (i === 3) {
clearInterval(interval);
}
}, 50);
vi.runAllTimers();
// log: 1
// log: 2
// log: 3
vi.runAllTimersAsync
- Type :
() => Promise<Vitest>
Cette méthode exécutera de manière asynchrone chaque minuteur démarré jusqu'à ce que la file d'attente des minuteurs soit vide. Cela signifie que chaque minuteur appelé pendant runAllTimersAsync
sera déclenché, même les minuteurs asynchrones. Si vous avez un intervalle infini, il lèvera une erreur après 10 000 tentatives (peut être configuré avec fakeTimers.loopLimit
).
setTimeout(async () => {
console.log(await Promise.resolve('result'));
}, 100);
await vi.runAllTimersAsync();
// log: result
vi.runOnlyPendingTimers
- Type :
() => Vitest
Cette méthode appellera chaque minuteur qui a été démarré après l'appel de vi.useFakeTimers
. Elle ne déclenchera aucun minuteur qui a été démarré pendant son exécution.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- Type :
() => Promise<Vitest>
Cette méthode appellera de manière asynchrone chaque minuteur qui a été démarré après l'appel de vi.useFakeTimers
, même les asynchrones. Elle ne déclenchera aucun minuteur qui a été démarré pendant son exécution.
setTimeout(() => {
console.log(1);
}, 100);
setTimeout(() => {
Promise.resolve().then(() => {
console.log(2);
setInterval(() => {
console.log(3);
}, 40);
});
}, 10);
await vi.runOnlyPendingTimersAsync();
// log: 2
// log: 3
// log: 3
// log: 1
vi.setSystemTime
- Type :
(date: string | number | Date) => void
Si les faux minuteurs sont activés, cette méthode simule un changement d'horloge système par l'utilisateur (ce qui affectera les API liées à la date comme hrtime
, performance.now
ou new Date()
) - cependant, elle ne déclenchera aucun minuteur. Si les faux minuteurs ne sont pas activés, cette méthode ne simulera que les appels Date.*
.
Utile si vous avez besoin de tester quelque chose qui dépend de la date actuelle - par exemple les appels à Luxon dans votre code.
Accepte les mêmes arguments de chaîne et de nombre que le constructeur Date
.
const date = new Date(1998, 11, 19);
vi.useFakeTimers();
vi.setSystemTime(date);
expect(Date.now()).toBe(date.valueOf());
vi.useRealTimers();
vi.useFakeTimers
- Type :
(config?: FakeTimerInstallOpts) => Vitest
Pour activer la simulation des minuteurs, vous devez appeler cette méthode. Elle interceptera tous les appels ultérieurs aux minuteurs (tels que setTimeout
, setInterval
, clearTimeout
, clearInterval
, setImmediate
, clearImmediate
, et Date
) jusqu'à ce que vi.useRealTimers()
soit appelé.
La simulation de nextTick
n'est pas prise en charge lors de l'exécution de Vitest à l'intérieur de node:child_process
en utilisant --pool=forks
. NodeJS utilise process.nextTick
en interne dans node:child_process
et se bloque lorsqu'il est simulé. La simulation de nextTick
est prise en charge lors de l'exécution de Vitest avec --pool=threads
.
L'implémentation est basée en interne sur @sinonjs/fake-timers
.
TIP
vi.useFakeTimers()
ne simule pas automatiquement process.nextTick
. Mais vous pouvez l'activer en spécifiant l'option dans l'argument toFake
: vi.useFakeTimers({ toFake: ['nextTick'] })
.
vi.isFakeTimers
- Type :
() => boolean
Retourne true
si les faux minuteurs sont activés.
vi.useRealTimers
- Type :
() => Vitest
Lorsque vous avez terminé d'utiliser les faux minuteurs, vous pouvez appeler cette méthode pour restaurer les minuteurs simulés à leurs implémentations d'origine. Tous les minuteurs qui ont été planifiés auparavant seront ignorés.
Divers
Un ensemble de fonctions d'aide utiles fournies par Vitest.
vi.waitFor
- Type :
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
Attend que le callback s'exécute avec succès. Si le callback lève une erreur ou retourne une promesse rejetée, il continuera d'attendre jusqu'à ce qu'il réussisse ou expire.
C'est très utile lorsque vous devez attendre qu'une action asynchrone se termine, par exemple, lorsque vous démarrez un serveur et que vous devez attendre qu'il démarre.
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';
test('Le serveur a démarré avec succès', async () => {
const server = createServer();
await vi.waitFor(
() => {
if (!server.isReady) {
throw new Error('Le serveur n\'a pas démarré');
}
console.log('Le serveur a démarré');
},
{
timeout: 500, // la valeur par défaut est 1000
interval: 20, // la valeur par défaut est 50
}
);
expect(server.isReady).toBe(true);
});
Cela fonctionne également pour les callbacks asynchrones
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';
test('L\'élément existe dans le DOM', async () => {
// commencer à peupler le DOM
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// essayer d'obtenir l'élément jusqu'à ce qu'il existe
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // la valeur par défaut est 1000
interval: 20, // la valeur par défaut est 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
Si vi.useFakeTimers
est utilisé, vi.waitFor
appelle automatiquement vi.advanceTimersByTime(interval)
dans chaque callback de vérification.
vi.waitUntil
- Type :
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
Ceci est similaire à vi.waitFor
, mais si le callback lève des erreurs, l'exécution est immédiatement interrompue et un message d'erreur est reçu. Si le callback retourne une valeur falsy, la prochaine vérification continuera jusqu'à ce qu'une valeur truthy soit retournée. C'est utile lorsque vous devez attendre que quelque chose existe avant de passer à l'étape suivante.
Regardez l'exemple ci-dessous. Nous pouvons utiliser vi.waitUntil
pour attendre que l'élément apparaisse sur la page, puis nous pouvons faire quelque chose avec l'élément.
import { expect, test, vi } from 'vitest';
test('L\'élément s\'affiche correctement', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // la valeur par défaut est 1000
interval: 20, // la valeur par défaut est 50
});
// faire quelque chose avec l'élément
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted
- Type :
<T>(factory: () => T) => T
Toutes les instructions import
statiques dans les modules ES sont remontées en haut du fichier, de sorte que tout code défini avant les importations sera en fait exécuté après l'évaluation des importations.
Cependant, il peut être utile d'invoquer certains effets secondaires comme la simulation de dates avant d'importer un module.
Pour contourner cette limitation, vous pouvez réécrire les importations statiques en importations dynamiques comme ceci :
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
Lors de l'exécution de vitest
, vous pouvez le faire automatiquement en utilisant la méthode vi.hoisted
.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
Cette méthode retourne la valeur qui a été retournée par la factory. Vous pouvez utiliser cette valeur dans vos factories vi.mock
si vous avez besoin d'un accès facile aux variables définies localement :
import { expect, vi } from 'vitest';
import { originalMethod } from './path/to/module.js';
const { mockedMethod } = vi.hoisted(() => {
return { mockedMethod: vi.fn() };
});
vi.mock('./path/to/module.js', () => {
return { originalMethod: mockedMethod };
});
mockedMethod.mockReturnValue(100);
expect(originalMethod()).toBe(100);
Notez que cette méthode peut également être appelée de manière asynchrone même si votre environnement ne prend pas en charge le top-level await :
const promised = await vi.hoisted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
});
vi.setConfig
- Type :
RuntimeConfig
Met à jour la configuration pour le fichier de test actuel. Cette méthode ne prend en charge que les options de configuration qui affecteront le fichier de test actuel :
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// prend en charge l'objet entier
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// prend en charge uniquement "sequence.hooks"
},
});
vi.resetConfig
- Type :
RuntimeConfig
Si vi.setConfig
a été appelé auparavant, cela réinitialisera la configuration à l'état d'origine.