Vi
Vitest fournit des fonctions utilitaires pour vous aider avec son assistant vi
. Vous pouvez y accéder globalement (lorsque la configuration des globales est activée), ou l'importer directement depuis vitest
:
import { vi } from 'vitest';
Modules Mockés
Cette section décrit l'API que vous pouvez utiliser lors du mocking d'un module. Sachez que Vitest ne prend pas en charge le mocking des modules importés via require()
.
vi.mock
- Type:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
Remplace tous les modules importés à partir du chemin
fourni par un autre module. Vous pouvez utiliser les alias Vite configurés à l'intérieur d'un chemin. L'appel à vi.mock
est remonté (hoisted), peu importe où vous l'appelez. Il sera toujours exécuté avant toutes les importations. Si vous devez référencer des variables en dehors de 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 qui ont été importés avec le mot-clé import
. Il ne fonctionne pas avec require
.
Afin de remonter (hoist) vi.mock
, Vitest analyse vos fichiers statiquement. Cela signifie que vi
, qui n'est pas directement importé du paquet vitest
(par exemple, depuis un fichier utilitaire), ne peut pas être utilisé. Utilisez vi.mock
avec vi
importé depuis vitest
, ou activez l'option de configuration globals
.
Vitest ne moquera pas les modules qui ont été importés à l'intérieur d'un fichier de configuration car ils sont mis en cache au moment où un fichier de test est en cours d'exécution. 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.
WARNING
Le mode navigateur ne prend pas actuellement en charge le mocking des modules. Vous pouvez suivre l'avancement de cette fonctionnalité dans l'issue GitHub.
Si factory
est défini, toutes les importations retourneront son résultat. Vitest appelle factory
une seule fois et met en cache les résultats pour toutes les importations suivantes 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 avec la factory passée comme premier argument, et obtenir le module original à l'intérieur.
import { vi } from 'vitest';
// ---cut---
// when using JavaScript
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal();
return {
...mod,
// remplacer certaines exportations
namedExport: vi.fn(),
};
});
// when using TypeScript
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal<typeof import('./path/to/module.js')>();
return {
...mod,
// remplacer certaines exportations
namedExport: vi.fn(),
};
});
WARNING
vi.mock
est remonté (hoisted), c'est-à-dire déplacé, en haut du fichier. Cela signifie que chaque fois que vous l'écrivez (que ce soit à l'intérieur de beforeEach
ou test
), il sera en fait appelé avant cela.
Cela signifie également que vous ne pouvez pas utiliser de variables à l'intérieur de la factory qui sont définies en dehors de la factory.
Si vous devez 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é (hoisted). Sachez qu'il ne moque que les importations suivantes.
Vous pouvez également référencer des variables définies par la méthode vi.hoisted
si elle a été déclarée avant vi.mock
:
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 moquez un module avec une exportation par défaut, vous devrez fournir une clé default
dans l'objet retourné par la fonction factory
. Il s'agit d'une mise en garde spécifique aux 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 moquez, et que la factory n'est pas fournie, Vitest essaiera de trouver un fichier portant le même nom dans le sous-dossier __mocks__
et l'utilisera comme module réel. Si vous moquez une dépendance, Vitest essaiera de trouver un dossier __mocks__
dans la racine du projet (la valeur par défaut est process.cwd()
). Vous pouvez indiquer à 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 fournie, Vitest trouvera un fichier dans le dossier __mocks__
à utiliser comme module :
// increment.test.js
import { vi } from 'vitest';
// axios is a default export from `__mocks__/axios.js`
import axios from 'axios';
// increment is a named export from `src/__mocks__/increment.js`
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
Sachez que si vous n'appelez pas vi.mock
, les modules ne sont pas mockés automatiquement. Pour reproduire le comportement d'automocking de Jest, 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 auto-moquera toutes ses exports. Pour les règles appliquées, voir algorithme.
vi.doMock
- Type:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
Identique à vi.mock
, mais il n'est pas remonté (hoisted) en haut du fichier, vous pouvez donc référencer des variables dans la portée globale du fichier. La prochaine importation dynamique du module sera mockée.
WARNING
Cela ne moquera pas les modules qui ont été importés avant son appel. N'oubliez pas que toutes les importations statiques dans ESM sont toujours remontées (hoisted). Par conséquent, placer ceci avant l'importation statique ne forcera pas son appel avant l'importation :
vi.doMock('./increment.js'); // this will be called _after_ the import statement
import { increment } from './increment.js';
// ./increment.js
export function increment(number) {
return number + 1;
}
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';
// the module is not mocked, because vi.doMock is not called yet
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// you can access variables inside a factory
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('importing the next module imports mocked one', async () => {
// original import WAS NOT MOCKED, because vi.doMock is evaluated AFTER imports
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// new dynamic import returns mocked module
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>
Assistant de type pour TypeScript. Retourne simplement l'objet qui a été passé.
Lorsque partial
est true
, il s'attendra à un Partial<T>
comme valeur de retour. Par défaut, cela fera seulement croire à TypeScript que les valeurs de premier niveau sont mockées. Vous pouvez passer { deep: true }
comme deuxième argument pour indiquer à TypeScript que l'objet entier est mocké en profondeur, si c'est effectivement le cas.
import example from './example.js';
vi.mock('./example.js');
test('1 + 1 equals 10', async () => {
vi.mocked(example.calc).mockReturnValue(10);
expect(example.calc(1, '+', 1)).toBe(10);
});
vi.importActual
- Type:
<T>(path: string) => Promise<T>
Importe le module, en contournant toutes les vérifications pour savoir s'il doit être mocké. Peut être utile si vous voulez mocker 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 avec toutes ses propriétés (y compris les propriétés imbriquées) mockées. Suit les mêmes règles que vi.mock
. Pour les règles appliquées, voir algorithme.
vi.unmock
- Type:
(path: string) => void
Supprime le module du registre mocké. Tous les appels à import
retourneront le module original même s'il a été mocké auparavant. Cet appel est remonté (hoisted) en haut du fichier et ne démoquera donc que les modules qui ont été définis dans setupFiles
, par exemple.
vi.doUnmock
- Type:
(path: string) => void
Identique à vi.unmock
, mais n'est pas remonté (hoisted) en haut du fichier. La prochaine importation du module importera le module original au lieu du mock. Cela ne démoquera pas les modules importés précédemment.
// ./increment.js
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// increment is already mocked, because vi.mock is hoisted
increment(1) === 100;
// this is hoisted, and factory is called before the import on line 1
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// all calls are mocked, and `increment` always returns 100
increment(1) === 100;
increment(30) === 100;
// this is not hoisted, so other import will return unmocked module
vi.doUnmock('./increment.js');
// this STILL returns 100, because `vi.doUnmock` doesn't reevaluate a module
increment(1) === 100;
increment(30) === 100;
// the next import is unmocked, now `increment` is the original function that returns count + 1
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- Type:
() => Vitest
Réinitialise le registre des modules en effaçant le cache de tous les modules. Cela permet aux modules d'être réévalués lors de la réimportation. Les importations de niveau supérieur ne peuvent pas être réévaluées. Cela peut être utile pour isoler les modules où l'état local entre en conflit entre les tests.
import { vi } from 'vitest';
import { data } from './data.js'; // Will not get reevaluated beforeEach test
beforeEach(() => {
vi.resetModules();
});
test('change state', async () => {
const mod = await import('./some/path.js'); // Will get reevaluated
mod.changeLocalState('new value');
expect(mod.getLocalState()).toBe('new value');
});
test('module has old state', async () => {
const mod = await import('./some/path.js'); // Will get reevaluated
expect(mod.getLocalState()).toBe('old value');
});
WARNING
Ne réinitialise pas le registre des mocks. Pour effacer le registre 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 commence à importer un module que vous ne pouvez pas attendre autrement.
import { expect, test } from 'vitest';
// cannot track import because Promise is not returned
function renderComponent() {
import('./component.js').then(({ render }) => {
render();
});
}
test('operations are resolved', async () => {
renderComponent();
await vi.dynamicImportSettled();
expect(document.querySelector('.component')).not.toBeNull();
});
TIP
Si, pendant une importation dynamique, une autre importation dynamique est initié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 de sa résolution.
Mocking des Fonctions et des 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 initialisé sans fonction. Chaque fois qu'une fonction est invoquée, elle stocke ses arguments d'appel, ses retours 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 sera invoqué.
import { expect, vi } from 'vitest';
// ---cut---
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ée. Si vous utilisez TypeScript, il réduira également son type.
vi.clearAllMocks
Appelle .mockClear()
sur tous les espions. Cela supprimera l'historique des mocks, mais ne réinitialisera pas leur implémentation à la valeur par défaut.
vi.resetAllMocks
Appelle .mockReset()
sur tous les espions. Cela supprimera l'historique des mocks et réinitialisera son implémentation à une fonction vide (retournera undefined
).
vi.restoreAllMocks
Appelle .mockRestore()
sur tous les espions. Cela supprimera l'historique des mocks et réinitialisera son 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 accesseur (getter/setter) d'un objet, similaire à vi.fn()
. Il retourne une fonction mockée.
import { expect, vi } from 'vitest';
// ---cut---
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 original, 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()); // still 42!
vi.stubEnv 0.26.0+
- Type:
(name: string, value: string) => Vitest
Modifie la valeur de la 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` and `import.meta.env.NODE_ENV`
// are "development" before calling "vi.stubEnv"
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
// doesn't change other envs
import.meta.env.MODE === 'development';
TIP
Vous pouvez également modifier la valeur en l'assignant simplement, mais vous ne pourrez pas utiliser vi.unstubAllEnvs
pour restaurer la valeur précédente :
import.meta.env.MODE = 'test';
vi.unstubAllEnvs 0.26.0+
- Type:
() => Vitest
Restaure toutes les valeurs de import.meta.env
et process.env
qui ont été modifiées avec vi.stubEnv
. Lorsqu'il est appelé pour la première fois, Vitest mémorise la valeur d'origine et la stocke jusqu'à ce que unstubAllEnvs
soit appelé à nouveau.
import { vi } from 'vitest';
// `process.env.NODE_ENV` and `import.meta.env.NODE_ENV`
// are "development" before calling 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();
// restores to the value that were stored before the first "stubEnv" call
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` is "0" before calling stubGlobal
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// if you are using jsdom or happy-dom
window.innerWidth === 100;
TIP
Vous pouvez également modifier la valeur en l'assignant 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;
// if you are using jsdom or happy-dom
window.innerWidth = 100;
vi.unstubAllGlobals 0.26.0+
- 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'il est appelé pour la première fois, Vitest mémorise la valeur d'origine et la stocke jusqu'à ce que unstubAllGlobals
soit appelé à nouveau.
import { vi } from 'vitest';
const Mock = vi.fn();
// IntersectionObserver is "undefined" before calling "stubGlobal"
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// if you are using jsdom or happy-dom
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// throws ReferenceError, because it's not defined
IntersectionObserver === undefined;
Timers simulés (Fake Timers)
Cette section décrit comment travailler avec les faux temporisateurs.
vi.advanceTimersByTime
- Type:
(ms: number) => Vitest
Cette méthode avance les timers simulés du nombre de millisecondes spécifié, ou jusqu'à ce que la file d'attente des timers soit vide, selon la première éventualité.
import { vi } from 'vitest';
// ---cut---
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 avance de manière asynchrone les timers simulés du nombre de millisecondes spécifié, ou jusqu'à ce que la file d'attente des timers soit vide, selon la première éventualité. Elle inclut les timers définis de manière asynchrone.
import { vi } from 'vitest';
// ---cut---
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
Exécute le prochain timer disponible dans la file d'attente. Utile pour vérifier l'état entre chaque exécution de timer. Vous pouvez chaîner les appels pour contrôler l'exécution des timers manuellement.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer(); // log: 3
vi.advanceTimersToNextTimerAsync
- Type:
() => Promise<Vitest>
Exécute de manière asynchrone le prochain timer disponible et attend sa résolution s'il a été défini de manière asynchrone. Utile pour vérifier l'état entre chaque exécution de timer.
import { expect, vi } from 'vitest';
// ---cut---
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.getTimerCount
- Type:
() => number
Retourne le nombre de timers en attente d'exécution.
vi.clearAllTimers
Supprime tous les timers programmés. Ces timers ne seront pas exécutés.
vi.getMockedSystemTime
- Type:
() => Date | null
Retourne la date simulée actuelle définie avec setSystemTime
. Si la date n'est pas simulée, la méthode retourne null
.
vi.getRealSystemTime
- Type:
() => number
Lorsque vi.useFakeTimers
est utilisé, 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
Exécute toutes les microtâches mises en file d'attente par process.nextTick
. Cela exécutera également toutes les microtâches planifiées par ces dernières.
vi.runAllTimers
- Type:
() => Vitest
Cette méthode exécute tous les timers simulés jusqu'à ce que la file d'attente des timers soit vide. Chaque timer appelé pendant runAllTimers
sera déclenché. Si un intervalle infini est présent, une exception sera levée après 10 000 tentatives (configurable avec fakeTimers.loopLimit
).
import { vi } from 'vitest';
// ---cut---
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écute de manière asynchrone tous les timers simulés jusqu'à ce que la file d'attente des timers soit vide. Chaque timer appelé pendant runAllTimersAsync
sera déclenché, y compris les timers asynchrones. Si un intervalle infini est présent, une exception sera levée après 10 000 tentatives (configurable avec fakeTimers.loopLimit
).
import { vi } from 'vitest';
// ---cut---
setTimeout(async () => {
console.log(await Promise.resolve('result'));
}, 100);
await vi.runAllTimersAsync();
// log: result
vi.runOnlyPendingTimers
- Type:
() => Vitest
Cette méthode exécute uniquement les timers qui ont été initialisés après l'appel de vi.useFakeTimers
. Elle n'exécutera pas les timers initialisés pendant son exécution.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- Type:
() => Promise<Vitest>
Cette méthode exécute de manière asynchrone uniquement les timers qui ont été initialisés après l'appel de vi.useFakeTimers
, y compris les timers asynchrones. Elle n'exécutera pas les timers initialisés pendant son exécution.
import { vi } from 'vitest';
// ---cut---
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 timers simulés sont activés, cette méthode simule la modification de l'horloge système par un utilisateur (affecte les API liées à la date comme hrtime
, performance.now
ou new Date()
). Cependant, elle ne déclenche aucun timer. Si les faux timers ne sont pas activés, cette méthode ne simulera que les appels à Date.*
.
Utile si vous devez tester du code qui dépend de la date actuelle, par exemple, les appels à Luxon dans votre code.
import { expect, vi } from 'vitest';
// ---cut---
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 timers, il est nécessaire d'appeler cette méthode. Elle intercepte tous les appels ultérieurs aux timers (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 lorsque Vitest est exécuté dans 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 sur @sinonjs/fake-timers
.
TIP
Depuis la version 0.35.0
, vi.useFakeTimers()
ne simule plus automatiquement process.nextTick
. Il peut toujours être simulé en spécifiant l'option dans l'argument toFake
: vi.useFakeTimers({ toFake: ['nextTick'] })
.
vi.isFakeTimers 0.34.5+
- Type:
() => boolean
Retourne true
si les faux timers sont activés.
vi.useRealTimers
- Type:
() => Vitest
Lorsque les timers simulés ne sont plus nécessaires, vous pouvez appeler cette méthode pour rétablir les timers à leurs implémentations d'origine. Tous les timers qui ont été programmés seront supprimés.
Divers
Un ensemble de fonctions d'assistance utiles fournies par Vitest.
vi.waitFor 0.34.5+
- Type:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
Attend l'exécution réussie du callback. Si le callback lève une exception ou retourne une promesse rejetée, l'attente continue jusqu'à ce qu'il réussisse ou que le délai d'attente expire.
Particulièrement utile lorsque vous devez attendre la fin d'une action asynchrone, par exemple, lorsque vous démarrez un serveur et que vous devez attendre qu'il soit prêt.
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';
test('Server started successfully', async () => {
const server = createServer();
await vi.waitFor(
() => {
if (!server.isReady) throw new Error('Server not started');
console.log('Server started');
},
{
timeout: 500, // la valeur par défaut est de 1000
interval: 20, // la valeur par défaut est de 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('Element exists in a DOM', async () => {
// start populating DOM
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// try to get the element until it exists
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 de 1000
interval: 20, // la valeur par défaut est de 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 0.34.5+
- Type:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
Similaire à vi.waitFor
, mais si le callback lève une exception, l'exécution est immédiatement interrompue et un message d'erreur est affiché. Si le callback retourne une valeur fausse, la prochaine vérification continue jusqu'à ce qu'une valeur vraie soit retournée. Ceci 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('Element render correctly', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // la valeur par défaut est de 1000
interval: 20, // la valeur par défaut est de 50
});
// do something with the element
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted 0.31.0+
- Type:
<T>(factory: () => T) => T
Dans les modules ES, toutes les instructions import
statiques sont remontées en haut du fichier, de sorte que tout code défini avant les imports sera exécuté après l'évaluation de ces derniers.
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 imports statiques en imports 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 renvoyé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 supporte également les appels asynchrones, même si votre environnement ne prend pas en charge l'attente de niveau supérieur :
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 affectent le fichier de test en cours :
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// supporte l'intégralité de l'objet
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// ne supporte que "sequence.hooks"
},
});
vi.resetConfig
- Type:
RuntimeConfig
Si vi.setConfig
a été appelé précédemment, cela rétablira la configuration à son état initial.