Vi
Vitest fornisce funzioni di utilità tramite l'helper vi
. Puoi accedervi globalmente (quando la configurazione dei globals è abilitata), oppure importarlo direttamente da vitest
:
import { vi } from 'vitest';
Mock dei Moduli
Questa sezione descrive l'API che puoi usare per il mocking di un modulo. Tieni presente che Vitest non supporta il mocking di moduli importati con require()
.
vi.mock
- Tipo:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
Sostituisce tutti i moduli importati dal percorso specificato con un altro modulo. Puoi usare gli alias Vite configurati all'interno del percorso. La chiamata a vi.mock
subisce l'hoisting, quindi non importa dove la chiami, sarà sempre eseguita prima di tutti gli import. Se hai bisogno di fare riferimento a variabili al di fuori del suo scope, puoi definirle all'interno di vi.hoisted
e farvi riferimento in vi.mock
.
WARNING
vi.mock
funziona solo per i moduli importati con la parola chiave import
. Non funziona con require
.
Per consentire l'hoisting di vi.mock
, Vitest analizza staticamente i file. Questo significa che vi
, se non importato direttamente dal pacchetto vitest
(ad esempio, da un file di utilità), non può essere usato. Usa vi.mock
con vi
importato da vitest
, oppure abilita l'opzione di configurazione globals
.
Vitest non effettuerà il mock dei moduli importati all'interno di un file di setup perché sono memorizzati nella cache nel momento in cui un file di test è in esecuzione. Puoi chiamare vi.resetModules()
all'interno di vi.hoisted
per cancellare tutte le cache dei moduli prima di eseguire un file di test.
WARNING
La modalità browser attualmente non supporta il mocking dei moduli. Puoi seguire lo stato di questa funzionalità nella issue su GitHub.
Se factory
è definito, tutti gli import restituiranno il suo risultato. Vitest chiama la factory solo una volta e memorizza nella cache i risultati per tutti gli import successivi fino a quando non viene chiamato vi.unmock
o vi.doUnmock
.
A differenza di jest
, la factory può essere una funzione asincrona. Puoi usare vi.importActual
o un helper con la factory passata come primo argomento, e ottenere il modulo originale al suo interno.
import { vi } from 'vitest';
// ---cut---
// quando si usa JavaScript
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal();
return {
...mod,
// sostituisci alcune esportazioni
namedExport: vi.fn(),
};
});
// quando si usa TypeScript
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal<typeof import('./path/to/module.js')>();
return {
...mod,
// sostituisci alcune esportazioni
namedExport: vi.fn(),
};
});
WARNING
vi.mock
subisce l'hoisting (ovvero, viene spostato) all'inizio del file. Questo significa che ogni volta che lo scrivi (che sia all'interno di beforeEach
o test
), sarà effettivamente chiamato prima di tutto.
Significa anche che non è possibile usare variabili all'interno della factory che siano definite al di fuori di essa.
Se hai bisogno di usare variabili all'interno della factory, prova vi.doMock
. Funziona allo stesso modo ma non viene hoisted. Nota che effettua il mock solo degli import successivi.
Puoi anche fare riferimento a variabili definite con il metodo vi.hoisted
se è stato dichiarato prima di 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
Se stai mockando un modulo con export di default, è necessario fornire una chiave default
all'interno dell'oggetto restituito dalla factory. Questa è un'avvertenza specifica dei moduli ES; pertanto, la documentazione di jest
potrebbe differire poiché jest
usa moduli CommonJS. Per esempio,
vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
// etc...
};
});
Se c'è una cartella __mocks__
accanto a un file di cui stai facendo il mock, e la factory non è fornita, Vitest proverà a trovare un file con lo stesso nome nella sottocartella __mocks__
e lo userà come modulo effettivo. Se stai mockando una dipendenza, Vitest proverà a trovare una cartella __mocks__
nella root del progetto (il default è process.cwd()
). Puoi indicare a Vitest dove si trovano le dipendenze tramite l'opzione di configurazione deps.moduleDirectories.
Per esempio, hai questa struttura di file:
- __mocks__
- axios.js
- src
__mocks__
- increment.js
- increment.js
- tests
- increment.test.js
Se chiami vi.mock
in un file di test senza una factory fornita, troverà un file nella cartella __mocks__
da usare come modulo:
// increment.test.js
import { vi } from 'vitest';
// axios è un export di default da `__mocks__/axios.js`
import axios from 'axios';
// increment è un export con nome da `src/__mocks__/increment.js`
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
Nota che se non chiami vi.mock
, i moduli non vengono mockati automaticamente. Per replicare il comportamento di automocking di Jest, puoi chiamare vi.mock
per ogni modulo richiesto all'interno di setupFiles
.
Se non c'è una cartella __mocks__
o una factory fornita, Vitest importerà il modulo originale e farà l'auto-mock di tutti i suoi export. Per le regole applicate, vedi algoritmo.
vi.doMock
- Tipo:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
Come vi.mock
, ma non viene hoisted all'inizio del file, quindi puoi fare riferimento a variabili nello scope globale del file. Il successivo import dinamico del modulo verrà mockato.
WARNING
Questo non mocka i moduli che sono stati importati prima di questa chiamata. Non dimenticare che tutti gli import statici in ESM sono sempre hoisted, quindi mettere questo prima dell'import static non forzerà la sua chiamata prima dell'import:
vi.doMock('./increment.js'); // questo sarà chiamato _dopo_ l'istruzione 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';
// il modulo non viene mockato, perché vi.doMock non è stato ancora chiamato
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// puoi accedere alle variabili all'interno di una factory
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('importing the next module imports mocked one', async () => {
// l'import originale NON È STATO MOCKATO, perché vi.doMock è valutato DOPO gli import
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// il nuovo import dinamico restituisce il modulo mockato
expect(mockedIncrement(1)).toBe(101);
expect(mockedIncrement(1)).toBe(102);
expect(mockedIncrement(1)).toBe(103);
});
vi.mocked
- Tipo:
<T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>
- Tipo:
<T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>
Helper di tipo per TypeScript. Restituisce semplicemente l'oggetto passato come argomento.
Quando partial
è true
si aspetterà un Partial<T>
come valore di ritorno. Di default, questo farà solo credere a TypeScript che i valori del primo livello siano mockati. Puoi passare { deep: true }
come secondo argomento per dire a TypeScript che l'intero oggetto è mockato, se lo è effettivamente.
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
- Tipo:
<T>(path: string) => Promise<T>
Importa il modulo, bypassando tutti i controlli che verificherebbero se dovrebbe essere mockato. Può essere utile se vuoi mockare il modulo parzialmente.
vi.mock('./example.js', async () => {
const axios = await vi.importActual('./example.js');
return { ...axios, get: vi.fn() };
});
vi.importMock
- Tipo:
<T>(path: string) => Promise<MaybeMockedDeep<T>>
Importa un modulo con tutte le sue proprietà (incluse le proprietà annidate) mockate. Segue le stesse regole di vi.mock
. Per le regole applicate, vedi algoritmo.
vi.unmock
- Tipo:
(path: string) => void
Rimuove il modulo dal registro dei mock. Tutte le chiamate a import restituiranno il modulo originale anche se era stato mockato prima. Questa chiamata subisce l'hoisting all'inizio del file, quindi effettuerà l'unmock solo dei moduli definiti, ad esempio, nei setupFiles
.
vi.doUnmock
- Tipo:
(path: string) => void
Come vi.unmock
, ma non viene hoisted all'inizio del file. Il prossimo import del modulo importerà il modulo originale invece del mock. Questo non effettua l'unmock dei moduli importati precedentemente.
// ./increment.js
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// increment è già mockato, perché vi.mock è hoisted
increment(1) === 100;
// questo è hoisted, e la factory viene chiamata prima dell'import alla riga 1
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// tutte le chiamate sono mockate, e `increment` restituisce sempre 100
increment(1) === 100;
increment(30) === 100;
// questo non è hoisted, quindi l'altro import restituirà il modulo non mockato
vi.doUnmock('./increment.js');
// questo RESTITUISCE ANCORA 100, perché `vi.doUnmock` non rivaluta un modulo
increment(1) === 100;
increment(30) === 100;
// il prossimo import non è mockato, ora `increment` è la funzione originale che restituisce count + 1
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- Tipo:
() => Vitest
Resetta il registro dei moduli cancellando la cache di tutti i moduli. Questo permette ai moduli di essere rivalutati quando vengono reimportati. Le importazioni di primo livello non possono essere rivalutate. Può essere utile per isolare i moduli in cui lo stato locale è in conflitto tra i test.
import { vi } from 'vitest';
import { data } from './data.js'; // Non verrà rivalutato prima di ogni test
beforeEach(() => {
vi.resetModules();
});
test('change state', async () => {
const mod = await import('./some/path.js'); // Verrà rivalutato
mod.changeLocalState('new value');
expect(mod.getLocalState()).toBe('new value');
});
test('module has old state', async () => {
const mod = await import('./some/path.js'); // Verrà rivalutato
expect(mod.getLocalState()).toBe('old value');
});
WARNING
Non resetta il registro dei mock. Per cancellare il registro dei mock, usa vi.unmock
o vi.doUnmock
.
vi.dynamicImportSettled
Attende che tutti gli import dinamici siano stati caricati. Utile se hai una chiamata sincrona che avvia l'importazione di un modulo che altrimenti non potresti attendere.
import { expect, test } from 'vitest';
// non posso tracciare l'import perché Promise non viene restituita
function renderComponent() {
import('./component.js').then(({ render }) => {
render();
});
}
test('operations are resolved', async () => {
renderComponent();
await vi.dynamicImportSettled();
expect(document.querySelector('.component')).not.toBeNull();
});
TIP
Se durante un import dinamico viene avviato un altro import dinamico, questo metodo aspetterà che tutti siano risolti.
Questo metodo aspetterà anche il prossimo tick di setTimeout
dopo che l'import è stato risolto, quindi tutte le operazioni sincrone dovrebbero essere completate nel momento in cui viene risolto.
Mocking di Funzioni e Oggetti
Questa sezione descrive come lavorare con i mock dei metodi e sostituire le variabili ambientali e globali.
vi.fn
- Tipo:
(fn?: Function) => Mock
Crea uno spy su una funzione, ma può essere usata anche senza una funzione di partenza. Ogni volta che una funzione viene invocata, memorizza i suoi argomenti di chiamata, i valori di ritorno e le istanze. Inoltre, puoi manipolare il suo comportamento con i metodi. Se non viene fornita alcuna funzione, il mock restituirà undefined
quando invocato.
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
- Tipo:
(fn: Function) => boolean
Controlla se un dato parametro è una funzione mock. Se si utilizza TypeScript, restringerà anche il suo tipo.
vi.clearAllMocks
Chiama .mockClear()
su tutti gli spy. Questo cancellerà la cronologia dei mock, ma non ripristinerà l'implementazione predefinita.
vi.resetAllMocks
Chiama .mockReset()
su tutti gli spy. Questo cancellerà la cronologia dei mock e ripristinerà l'implementazione a una funzione vuota (che restituirà undefined
).
vi.restoreAllMocks
Chiama .mockRestore()
su tutti gli spy. Questo cancellerà la cronologia dei mock e ripristinerà l'implementazione originale.
vi.spyOn
- Tipo:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
Crea uno spy su un metodo o getter/setter di un oggetto, in modo simile a vi.fn()
. Restituisce una funzione mock.
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
Puoi chiamare vi.restoreAllMocks
all'interno di afterEach
(o abilitare test.restoreMocks
) per ripristinare tutti i metodi alle loro implementazioni originali. Questo ripristinerà il descrittore dell'oggetto originale, quindi non sarai in grado di cambiare l'implementazione del metodo:
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()); // ancora 42!
vi.stubEnv 0.26.0+
- Tipo:
(name: string, value: string) => Vitest
Modifica il valore della variabile d'ambiente in process.env
e import.meta.env
. Puoi ripristinare il suo valore chiamando vi.unstubAllEnvs
.
import { vi } from 'vitest';
// `process.env.NODE_ENV` e `import.meta.env.NODE_ENV`
// sono "development" prima di chiamare "vi.stubEnv"
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
// non cambia altre variabili d'ambiente
import.meta.env.MODE === 'development';
TIP
Puoi anche cambiare il valore semplicemente assegnandolo, ma non sarai in grado di usare vi.unstubAllEnvs
per ripristinare il valore precedente:
import.meta.env.MODE = 'test';
vi.unstubAllEnvs 0.26.0+
- Tipo:
() => Vitest
Ripristina tutti i valori di import.meta.env
e process.env
modificati con vi.stubEnv
. Quando viene chiamato per la prima volta, Vitest ricorda il valore originale e lo memorizzerà, fino a quando unstubAllEnvs
non viene chiamato di nuovo.
import { vi } from 'vitest';
// `process.env.NODE_ENV` e `import.meta.env.NODE_ENV`
// sono "development" prima di chiamare 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();
// ripristina al valore che è stato memorizzato prima della prima chiamata "stubEnv"
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
- Tipo:
(name: string | number | symbol, value: unknown) => Vitest
Modifica il valore della variabile globale. Puoi ripristinare il suo valore originale chiamando vi.unstubAllGlobals
.
import { vi } from 'vitest';
// `innerWidth` ha valore "0" prima di chiamare stubGlobal
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// se stai usando jsdom o happy-dom
window.innerWidth === 100;
TIP
Puoi anche cambiare il valore semplicemente assegnandolo a globalThis
o window
(se stai usando l'ambiente jsdom
o happy-dom
), ma non sarai in grado di usare vi.unstubAllGlobals
per ripristinare il valore originale:
globalThis.innerWidth = 100;
// se stai usando jsdom o happy-dom
window.innerWidth = 100;
vi.unstubAllGlobals 0.26.0+
- Tipo:
() => Vitest
Ripristina tutti i valori globali di globalThis
/global
(e window
/top
/self
/parent
, se si utilizza l'ambiente jsdom
o happy-dom
) modificati con vi.stubGlobal
. Quando viene chiamato per la prima volta, Vitest ricorda il valore originale e lo memorizzerà, fino a quando unstubAllGlobals
non viene chiamato di nuovo.
import { vi } from 'vitest';
const Mock = vi.fn();
// IntersectionObserver è "undefined" prima di chiamare "stubGlobal"
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// se stai usando jsdom o happy-dom
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// lancia ReferenceError, perché non è definito
IntersectionObserver === undefined;
Timer Fittizi
Questa sezione descrive come lavorare con i timer fittizi.
vi.advanceTimersByTime
- Tipo:
(ms: number) => Vitest
Questo metodo avanza i timer simulati del numero specificato di millisecondi (ms
). Esegue tutti i timer in attesa fino a quando non è trascorso il tempo specificato o fino a quando la coda dei timer non è vuota, a seconda di quale condizione si verifica prima.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersByTime(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersByTimeAsync
- Tipo:
(ms: number) => Promise<Vitest>
Simile a vi.advanceTimersByTime
, ma gestisce anche i timer impostati in modo asincrono. Avanza i timer simulati del numero specificato di millisecondi (ms
), eseguendo tutti i timer in attesa, inclusi quelli asincroni, fino a quando non è trascorso il tempo specificato o fino a quando la coda dei timer non è vuota.
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
- Tipo:
() => Vitest
Esegue il timer successivo disponibile nella coda. Utile per eseguire asserzioni tra le singole esecuzioni dei timer. Puoi concatenare le chiamate per controllare manualmente l'esecuzione dei timer.
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
- Tipo:
() => Promise<Vitest>
Esegue il timer successivo disponibile nella coda, gestendo anche i timer asincroni. Attende che il timer venga risolto se è stato impostato in modo asincrono. Utile per eseguire asserzioni tra le singole esecuzioni dei 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
- Tipo:
() => number
Restituisce il numero di timer attualmente in attesa di esecuzione.
vi.clearAllTimers
Rimuove tutti i timer programmati, impedendone l'esecuzione futura.
vi.getMockedSystemTime
- Tipo:
() => Date | null
Restituisce la data corrente simulata impostata tramite vi.setSystemTime
. Se la data non è stata simulata, il metodo restituisce null
.
vi.getRealSystemTime
- Tipo:
() => number
Quando si utilizza vi.useFakeTimers
, le chiamate a Date.now
vengono simulate. Se è necessario ottenere il timestamp reale in millisecondi, è possibile chiamare questa funzione.
vi.runAllTicks
- Tipo:
() => Vitest
Esegue tutte le microtask messe in coda da process.nextTick
. Questo eseguirà anche tutte le microtask pianificate da esse.
vi.runAllTimers
- Tipo:
() => Vitest
Esegue tutti i timer impostati fino a quando la coda dei timer non è vuota. Ciò significa che tutti i timer chiamati durante l'esecuzione di vi.runAllTimers
verranno eseguiti. Se è presente un intervallo infinito, verrà generata un'eccezione dopo 10.000 tentativi (configurabile tramite 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
- Tipo:
() => Promise<Vitest>
Esegue in modo asincrono tutti i timer impostati fino a quando la coda dei timer non è vuota. Ciò significa che tutti i timer chiamati durante l'esecuzione di vi.runAllTimersAsync
, inclusi quelli asincroni, verranno eseguiti. Se è presente un intervallo infinito, verrà generata un'eccezione dopo 10.000 tentativi (configurabile tramite fakeTimers.loopLimit
).
import { vi } from 'vitest';
// ---cut---
setTimeout(async () => {
console.log(await Promise.resolve('result'));
}, 100);
await vi.runAllTimersAsync();
// log: result
vi.runOnlyPendingTimers
- Tipo:
() => Vitest
Esegue tutti i timer che sono stati avviati dopo la chiamata a vi.useFakeTimers
. Non eseguirà alcun timer avviato durante la sua esecuzione.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- Tipo:
() => Promise<Vitest>
Esegue in modo asincrono tutti i timer che sono stati avviati dopo la chiamata a vi.useFakeTimers
, inclusi quelli asincroni. Non eseguirà alcun timer avviato durante la sua esecuzione.
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
- Tipo:
(date: string | number | Date) => void
Se i timer fittizi sono abilitati, questo metodo simula la modifica dell'orologio di sistema da parte di un utente (influenzando le API che lavorano con le date come hrtime
, performance.now
o new Date()
); tuttavia, non eseguirà alcun timer. Se i timer fittizi non sono abilitati, questo metodo simulerà solo le chiamate a Date.*
.
Utile per testare codice che dipende dalla data corrente, ad esempio le chiamate a Luxon all'interno del codice.
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
- Tipo:
(config?: FakeTimerInstallOpts) => Vitest
Per abilitare la simulazione dei timer, è necessario chiamare questo metodo. Intercetta tutte le chiamate successive alle funzioni di gestione dei timer (come setTimeout
, setInterval
, clearTimeout
, clearInterval
, setImmediate
, clearImmediate
e Date
) fino a quando non viene chiamato vi.useRealTimers()
.
La simulazione di nextTick
non è supportata quando si esegue Vitest all'interno di node:child_process
utilizzando --pool=forks
. NodeJS utilizza internamente process.nextTick
in node:child_process
e si blocca se viene simulato. La simulazione di nextTick
è supportata quando si esegue Vitest con --pool=threads
.
L'implementazione si basa internamente su @sinonjs/fake-timers
.
TIP
Dalla versione 0.35.0
vi.useFakeTimers()
non simula più automaticamente process.nextTick
. Può comunque essere simulato specificando l'opzione nell'argomento toFake
: vi.useFakeTimers({ toFake: ['nextTick'] })
.
vi.isFakeTimers 0.34.5+
- Tipo:
() => boolean
Restituisce true
se i timer fittizi sono abilitati.
vi.useRealTimers
- Tipo:
() => Vitest
Dopo aver utilizzato i timer simulati, è possibile chiamare questo metodo per ripristinare le implementazioni originali dei timer. Tutti i timer programmati in precedenza verranno scartati.
Varie
Un insieme di funzioni di utilità fornite da Vitest.
vi.waitFor 0.34.5+
- Tipo:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
Attende che la callback venga eseguita correttamente. Se la callback genera un errore o restituisce una promessa rifiutata, continuerà ad attendere finché non avrà successo o fino a quando non scadrà il timeout.
Questo è molto utile quando è necessario attendere il completamento di un'azione asincrona, ad esempio, quando si avvia un server ed è necessario attendere che sia pronto.
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';
test('Server avviato correttamente', async () => {
const server = createServer();
await vi.waitFor(
() => {
if (!server.isReady) throw new Error('Server non avviato');
console.log('Server avviato');
},
{
timeout: 500, // il default è 1000
interval: 20, // il default è 50
}
);
expect(server.isReady).toBe(true);
});
Funziona anche per le callback asincrone
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';
test('Elemento esistente in un DOM', async () => {
// inizia a popolare il DOM
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// prova a ottenere l'elemento fino a quando non viene trovato
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // il default è 1000
interval: 20, // il default è 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
Se viene utilizzato vi.useFakeTimers
, vi.waitFor
chiama automaticamente vi.advanceTimersByTime(interval)
ad ogni esecuzione della callback.
vi.waitUntil 0.34.5+
- Tipo:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
Simile a vi.waitFor
, ma se la callback genera un errore, l'esecuzione viene immediatamente interrotta e si riceverà un errore. Se la callback restituisce un valore falsy, il controllo successivo continuerà fino a quando non viene restituito un valore truthy. Questo è utile quando è necessario attendere che qualcosa esista prima di procedere con il passo successivo.
Guarda l'esempio qui sotto. Possiamo usare vi.waitUntil
per attendere che l'elemento appaia nella pagina, e poi possiamo fare qualcosa con l'elemento.
import { expect, test, vi } from 'vitest';
test('Elemento renderizzato correttamente', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // il default è 1000
interval: 20, // il default è 50
});
// fare qualcosa con l'elemento
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted 0.31.0+
- Tipo:
<T>(factory: () => T) => T
Tutte le istruzioni import
statiche nei moduli ES vengono hoistate all'inizio del file, quindi qualsiasi codice definito prima degli import verrà effettivamente eseguito dopo che gli import sono stati valutati.
Tuttavia, può essere utile invocare alcuni effetti collaterali come la simulazione delle date prima di importare un modulo.
Per ovviare a questa limitazione, puoi riscrivere gli import statici in import dinamici in questo modo:
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
Quando si esegue vitest
, è possibile farlo automaticamente utilizzando il metodo vi.hoisted
.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
Questo metodo restituisce il valore restituito dalla factory. Puoi usare quel valore nelle tue factory vi.mock
se hai bisogno di un facile accesso alle variabili definite localmente:
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);
Nota che questo metodo può anche essere chiamato in modo asincrono anche se il tuo ambiente non supporta l'attesa di livello superiore (top-level await):
const promised = await vi.hoisted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
});
vi.setConfig
- Tipo:
RuntimeConfig
Aggiorna la configurazione del file di test corrente. Questo metodo supporta solo le opzioni di configurazione che hanno effetto sul file di test corrente:
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// supporta l'intero oggetto
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// supporta solo "sequence.hooks"
},
});
vi.resetConfig
- Tipo:
RuntimeConfig
Se vi.setConfig
è stato chiamato in precedenza, questo riporterà la configurazione allo stato originale.