Mocking
Quando si scrivono test, è inevitabile dover creare una versione "falsa" di un servizio, sia esso interno o esterno. Questa pratica è comunemente nota come mocking. Vitest offre funzioni di utilità per facilitare questo processo tramite il suo helper vi
. È possibile importarlo da vitest
o accedervi globalmente se la configurazione global
è abilitata.
WARNING
Ricorda sempre di cancellare o ripristinare i mock prima o dopo ogni esecuzione del test per assicurare che le modifiche allo stato del mock non influenzino i test successivi! Per maggiori dettagli, consulta la documentazione di mockReset
.
Se non hai familiarità con i metodi vi.fn
, vi.mock
o vi.spyOn
, ti consigliamo di consultare prima la sezione API.
Date
A volte è necessario controllare la data per garantire la coerenza durante i test. Vitest utilizza il pacchetto @sinonjs/fake-timers
per manipolare i timer e la data di sistema. Puoi trovare maggiori dettagli sull'API specifica qui.
Esempio
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const businessHours = [9, 17];
function purchase() {
const currentHour = new Date().getHours();
const [open, close] = businessHours;
if (currentHour > open && currentHour < close) {
return { message: 'Success' };
}
return { message: 'Error' };
}
describe('purchasing flow', () => {
beforeEach(() => {
// indica a Vitest di usare i timer fittizi
vi.useFakeTimers();
});
afterEach(() => {
// ripristina i timer reali dopo ogni esecuzione del test
vi.useRealTimers();
});
it('consente gli acquisti durante l\'orario lavorativo', () => {
// imposta l'ora all'interno dell'orario di lavoro
const date = new Date(2000, 1, 1, 13);
vi.setSystemTime(date);
// l'accesso a Date.now() risulterà nella data impostata sopra
expect(purchase()).toEqual({ message: 'Success' });
});
it('non permette acquisti fuori dall\'orario lavorativo', () => {
// imposta l'ora al di fuori dell'orario di lavoro
const date = new Date(2000, 1, 1, 19);
vi.setSystemTime(date);
// l'accesso a Date.now() risulterà nella data impostata sopra
expect(purchase()).toEqual({ message: 'Error' });
});
});
Funzioni
Il mocking delle funzioni può essere suddiviso in due categorie principali: spying e mocking.
A volte è sufficiente convalidare se una funzione specifica è stata chiamata (e quali argomenti sono stati passati). In questi casi, una "spy" è sufficiente e può essere utilizzata direttamente con vi.spyOn()
(leggi di più qui).
Tuttavia, le "spy" possono solo spiare le funzioni; non sono in grado di modificarne l'implementazione. Nel caso in cui sia necessario creare una versione fittizia (o mockata) di una funzione, possiamo usare vi.fn()
(leggi di più qui).
Utilizziamo Tinyspy come base per il mocking delle funzioni, ma abbiamo un nostro wrapper per renderlo compatibile con jest
. Sia vi.fn()
che vi.spyOn()
condividono gli stessi metodi, tuttavia solo il risultato di vi.fn()
è eseguibile.
Esempio
import { afterEach, describe, expect, it, vi } from 'vitest';
const messages = {
items: [
{ message: 'Simple test message', from: 'Testman' },
// ...
],
getLatest, // può anche essere un "getter" o un "setter", se supportati
};
function getLatest(index = messages.items.length - 1) {
return messages.items[index];
}
describe('reading messages', () => {
afterEach(() => {
vi.restoreAllMocks();
});
it('dovrebbe recuperare l\'ultimo messaggio utilizzando uno spy', () => {
const spy = vi.spyOn(messages, 'getLatest');
expect(spy.getMockName()).toEqual('getLatest');
expect(messages.getLatest()).toEqual(
messages.items[messages.items.length - 1]
);
expect(spy).toHaveBeenCalledTimes(1);
spy.mockImplementationOnce(() => 'access-restricted');
expect(messages.getLatest()).toEqual('access-restricted');
expect(spy).toHaveBeenCalledTimes(2);
});
it('dovrebbe ottenere con un mock', () => {
const mock = vi.fn().mockImplementation(getLatest);
expect(mock()).toEqual(messages.items[messages.items.length - 1]);
expect(mock).toHaveBeenCalledTimes(1);
mock.mockImplementationOnce(() => 'access-restricted');
expect(mock()).toEqual('access-restricted');
expect(mock).toHaveBeenCalledTimes(2);
expect(mock()).toEqual(messages.items[messages.items.length - 1]);
expect(mock).toHaveBeenCalledTimes(3);
});
});
Altro
Variabili globali
Puoi mockare le variabili globali non presenti con jsdom
o node
usando l'utilità vi.stubGlobal
. Questo inserirà il valore della variabile globale in un oggetto globalThis
.
import { vi } from 'vitest';
const IntersectionObserverMock = vi.fn(() => ({
disconnect: vi.fn(),
observe: vi.fn(),
takeRecords: vi.fn(),
unobserve: vi.fn(),
}));
vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);
// ora puoi accedervi come `IntersectionObserver` o `window.IntersectionObserver`
Moduli
I moduli mock interagiscono con le librerie di terze parti invocate in altro codice, permettendoti di testare argomenti, output o persino di ridefinirne l'implementazione.
Consulta la sezione API di vi.mock()
per una descrizione API più dettagliata e approfondita.
Algoritmo di Automocking
Se il tuo codice importa un modulo mockato, senza alcun file __mocks__
associato o una factory
per tale modulo, Vitest mockerà il modulo stesso invocandolo e mockando ogni export.
Si applicano i seguenti principi:
- Tutti gli array saranno svuotati
- Tutti i tipi primitivi e le collezioni rimarranno invariati
- Tutti gli oggetti saranno clonati profondamente
- Tutte le istanze di classi e i loro prototipi saranno clonati profondamente
Moduli Virtuali
Vitest supporta il mocking dei moduli virtuali di Vite. Funziona in modo diverso da come i moduli virtuali sono trattati in Jest. Invece di passare l'opzione virtual: true
a una funzione vi.mock
, devi indicare a Vite che il modulo esiste, altrimenti si verificherà un errore durante il parsing. Puoi farlo in diversi modi:
- Fornire un alias
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
test: {
alias: {
'$app/forms': resolve('./mocks/forms.js'),
},
},
});
- Fornire un plugin che risolve un modulo virtuale
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [
{
name: 'virtual-modules',
resolveId(id) {
if (id === '$app/forms') {
return 'virtual:$app/forms';
}
},
},
],
});
Il vantaggio del secondo approccio è che puoi creare dinamicamente diversi "entrypoint" virtuali. Se reindirizzi diversi moduli virtuali in un singolo file, allora ne saranno tutti influenzati da vi.mock
, quindi assicurati di usare identificatori unici.
Insidie del Mocking
Si noti che non è possibile mockare le chiamate a metodi che vengono invocati all'interno di altri metodi dello stesso file. Ad esempio, in questo codice:
export function foo() {
return 'foo';
}
export function foobar() {
return `${foo()}bar`;
}
Non è possibile mockare il metodo foo
dall'esterno perché è referenziato direttamente. Di conseguenza, questo codice non avrà alcun effetto sulla chiamata a foo
all'interno di foobar
(ma avrà effetto sulla chiamata a foo
in altri moduli):
import { vi } from 'vitest';
import * as mod from './foobar.js';
// questo avrà effetto soltanto su "foo" al di fuori del modulo originale
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
return {
...(await importOriginal<typeof import('./foobar.js')>()),
// questo avrà effetto soltanto su "foo" al di fuori del modulo originale
foo: () => 'mocked',
};
});
Puoi confermare questo comportamento fornendo l'implementazione al metodo foobar
direttamente:
import * as mod from './foobar.js';
vi.spyOn(mod, 'foo');
// foo esportato fa riferimento al metodo mockato
mod.foobar(mod.foo);
export function foo() {
return 'foo';
}
export function foobar(injectedFoo) {
return injectedFoo === foo; // false
}
Questo è il comportamento previsto. Di solito è un segno di codice di scarsa qualità quando il mocking è coinvolto in questo modo. Si consiglia di rifattorizzare il codice in più file o di migliorare l'architettura dell'applicazione utilizzando tecniche come l'iniezione di dipendenza.
Esempio
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';
// ottieni i todo
export async function getTodos(event, context) {
const client = new Client({
// ...opzioni del client
});
await client.connect();
try {
const result = await client.query('SELECT * FROM todos;');
client.end();
return success({
message: `${result.rowCount} elementi restituiti`,
data: result.rows,
status: true,
});
} catch (e) {
console.error(e.stack);
client.end();
return failure({ message: e, status: false });
}
}
vi.mock('pg', () => {
const Client = vi.fn();
Client.prototype.connect = vi.fn();
Client.prototype.query = vi.fn();
Client.prototype.end = vi.fn();
return { Client };
});
vi.mock('./handlers.js', () => {
return {
success: vi.fn(),
failure: vi.fn(),
};
});
describe('ottieni una lista di elementi todo', () => {
let client;
beforeEach(() => {
client = new Client();
});
afterEach(() => {
vi.clearAllMocks();
});
it('dovrebbe restituire gli elementi con successo', async () => {
client.query.mockResolvedValueOnce({ rows: [], rowCount: 0 });
await getTodos();
expect(client.connect).toBeCalledTimes(1);
expect(client.query).toBeCalledWith('SELECT * FROM todos;');
expect(client.end).toBeCalledTimes(1);
expect(success).toBeCalledWith({
message: '0 elementi restituiti',
data: [],
status: true,
});
});
it('dovrebbe lanciare un errore', async () => {
const mError = new Error('Impossibile recuperare le righe');
client.query.mockRejectedValueOnce(mError);
await getTodos();
expect(client.connect).toBeCalledTimes(1);
expect(client.query).toBeCalledWith('SELECT * FROM todos;');
expect(client.end).toBeCalledTimes(1);
expect(failure).toBeCalledWith({ message: mError, status: false });
});
});
File System
Il mocking del file system assicura che i test non dipendano dal file system reale, rendendo i test più affidabili e prevedibili. Questo isolamento aiuta a evitare effetti collaterali da test precedenti. Permette di testare condizioni di errore e casi limite che potrebbero essere difficili o impossibili da replicare con un file system reale, come problemi di permessi, scenari di disco pieno o errori di lettura/scrittura.
Vitest non fornisce alcuna API di mocking del file system pronta all'uso. Puoi usare vi.mock
per mockare il modulo fs
manualmente, ma è di difficile manutenzione. Invece, ti consigliamo di usare memfs
per farlo. memfs
crea un file system in memoria, che simula le operazioni del file system senza toccare il disco reale. Questo approccio è veloce e sicuro, evitando potenziali effetti collaterali sul file system reale.
Esempio
Per reindirizzare automaticamente ogni chiamata fs
a memfs
, puoi creare i file __mocks__/fs.cjs
e __mocks__/fs/promises.cjs
nella root del tuo progetto:
// possiamo anche usare `import`, ma poi
// ogni esportazione dovrebbe essere esplicitamente definita
const { fs } = require('memfs');
module.exports = fs;
// possiamo anche usare `import`, ma poi
// ogni esportazione dovrebbe essere esplicitamente definita
const { fs } = require('memfs');
module.exports = fs.promises;
import { readFileSync } from 'node:fs';
export function readHelloWorld(path) {
return readFileSync(path, 'utf-8');
}
import { beforeEach, expect, it, vi } from 'vitest';
import { fs, vol } from 'memfs';
import { readHelloWorld } from './read-hello-world.js';
// indica a Vitest di usare il mock fs dalla cartella __mocks__
// questo può essere fatto in un file di setup se fs deve essere sempre mockato
vi.mock('node:fs');
vi.mock('node:fs/promises');
beforeEach(() => {
// resetta lo stato del fs in memoria
vol.reset();
});
it('dovrebbe restituire il testo corretto', () => {
const path = '/hello-world.txt';
fs.writeFileSync(path, 'hello world');
const text = readHelloWorld(path);
expect(text).toBe('hello world');
});
it('può restituire un valore più volte', () => {
// puoi usare vol.fromJSON per definire diversi file
vol.fromJSON(
{
'./dir1/hw.txt': 'hello dir1',
'./dir2/hw.txt': 'hello dir2',
},
// cwd predefinito
'/tmp'
);
expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1');
expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2');
});
Richieste
Poiché Vitest viene eseguito in Node, il mocking delle richieste di rete è complesso. Le API web non sono disponibili, quindi abbiamo bisogno di qualcosa che simuli il comportamento di rete per noi. Raccomandiamo Mock Service Worker per raggiungere questo obiettivo. Ti consente di mockare richieste di rete http
, WebSocket
e GraphQL
, ed è indipendente dal framework.
Mock Service Worker (MSW) funziona intercettando le richieste che i tuoi test effettuano, permettendoti di usarlo senza modificare il codice della tua applicazione. Nel browser, viene utilizzata l'API Service Worker. In Node.js, e per Vitest, si avvale della libreria @mswjs/interceptors
. Per saperne di più su MSW, leggi la loro introduzione
Configurazione
Puoi usarlo come segue nel tuo file di setup
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';
const posts = [
{
userId: 1,
id: 1,
title: 'first post title',
body: 'first post body',
},
// ...
];
export const restHandlers = [
http.get('https://rest-endpoint.example/path/to/posts', () => {
return HttpResponse.json(posts);
}),
];
const server = setupServer(...restHandlers);
// Avvia il server prima di tutti i test
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Chiudi il server dopo tutti i test
afterAll(() => server.close());
// Resetta i gestori dopo ogni test per garantire l'isolamento dei test
afterEach(() => server.resetHandlers());
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { graphql, HttpResponse } from 'msw';
const posts = [
{
userId: 1,
id: 1,
title: 'first post title',
body: 'first post body',
},
// ...
];
const graphqlHandlers = [
graphql.query('ListPosts', () => {
return HttpResponse.json({
data: { posts },
});
}),
];
const server = setupServer(...graphqlHandlers);
// Avvia il server prima di tutti i test
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Chiudi il server dopo tutti i test
afterAll(() => server.close());
// Resetta i gestori dopo ogni test per garantire l'isolamento dei test
afterEach(() => server.resetHandlers());
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { ws } from 'msw';
const chat = ws.link('wss://chat.example.com');
const wsHandlers = [
chat.addEventListener('connection', ({ client }) => {
client.addEventListener('message', event => {
console.log('Messaggio ricevuto dal client:', event.data);
// Ripeti il messaggio ricevuto al client
client.send(`Server ricevuto: ${event.data}`);
});
}),
];
const server = setupServer(...wsHandlers);
// Avvia il server prima di tutti i test
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Chiudi il server dopo tutti i test
afterAll(() => server.close());
// Resetta i gestori dopo ogni test per garantire l'isolamento dei test
afterEach(() => server.resetHandlers());
La configurazione del server con
onUnhandledRequest: 'error'
garantisce che venga generato un errore ogni volta che una richiesta non ha un gestore corrispondente.
Altro
MSW offre molte altre funzionalità. Puoi accedere ai cookie e ai parametri di query, definire risposte di errore mockate e molto altro! Per vedere tutto ciò che puoi fare con MSW, leggi la loro documentazione.
Timer
Quando testiamo codice che coinvolge timeout o intervalli, invece di far attendere o scadere i nostri test, possiamo accelerare i nostri test usando timer "falsi" che mockano le chiamate a setTimeout
e setInterval
.
Consulta la sezione API di vi.useFakeTimers
per una descrizione API più dettagliata e approfondita.
Esempio
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
function executeAfterTwoHours(func) {
setTimeout(func, 1000 * 60 * 60 * 2); // 2 ore
}
function executeEveryMinute(func) {
setInterval(func, 1000 * 60); // 1 minuto
}
const mock = vi.fn(() => console.log('eseguito'));
describe('esecuzione ritardata', () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.restoreAllMocks();
});
it('dovrebbe eseguire la funzione', () => {
executeAfterTwoHours(mock);
vi.runAllTimers();
expect(mock).toHaveBeenCalledTimes(1);
});
it('non dovrebbe eseguire la funzione', () => {
executeAfterTwoHours(mock);
// avanzare di 2ms non attiverà la funzione
vi.advanceTimersByTime(2);
expect(mock).not.toHaveBeenCalled();
});
it('dovrebbe eseguire ogni minuto', () => {
executeEveryMinute(mock);
vi.advanceTimersToNextTimer();
expect(mock).toHaveBeenCalledTimes(1);
vi.advanceTimersToNextTimer();
expect(mock).toHaveBeenCalledTimes(2);
});
});
Classi
Puoi mockare un'intera classe con una singola chiamata vi.fn
- poiché tutte le classi sono anche funzioni, questo funziona out of the box. Si noti che attualmente Vitest non rispetta la parola chiave new
, quindi new.target
è sempre undefined
nel corpo di una funzione.
class Dog {
name: string;
constructor(name: string) {
this.name = name;
}
static getType(): string {
return 'animal';
}
greet = (): string => {
return `Ciao! Il mio nome è ${this.name}!`;
};
speak(): string {
return 'bau!';
}
isHungry() {}
feed() {}
}
Possiamo ricreare questa classe con funzioni ES5:
const Dog = vi.fn(function (name) {
this.name = name;
// mocka i metodi dell'istanza nel costruttore, ogni istanza avrà una propria spy
this.greet = vi.fn(() => `Ciao! Il mio nome è ${this.name}!`);
});
// si noti che i metodi statici sono mockati direttamente sulla funzione,
// non sull'istanza della classe
Dog.getType = vi.fn(() => 'animale simulato');
// mocka i metodi "speak" e "feed" su ogni istanza di una classe
// tutte le istanze `new Dog()` erediteranno e condivideranno queste funzioni spy
Dog.prototype.speak = vi.fn(() => 'bau forte!');
Dog.prototype.feed = vi.fn();
WARNING
Se un valore non primitivo viene restituito dalla funzione costruttore, quel valore diventerà il risultato dell'espressione new
. In questo caso il [[Prototype]]
potrebbe non essere correttamente associato:
const CorrectDogClass = vi.fn(function (name) {
this.name = name;
});
const IncorrectDogClass = vi.fn(name => ({
name,
}));
const Marti = new CorrectDogClass('Marti');
const Newt = new IncorrectDogClass('Newt');
Marti instanceof CorrectDogClass; // ✅ true
Newt instanceof IncorrectDogClass; // ❌ false!
QUANDO USARLO?
Generalmente, si ricreerebbe una classe in questo modo all'interno della factory del modulo se la classe viene riesportata da un altro modulo:
import { Dog } from './dog.js';
vi.mock(import('./dog.js'), () => {
const Dog = vi.fn();
Dog.prototype.feed = vi.fn();
// ... altri mock
return { Dog };
});
Questo metodo può anche essere usato per passare un'istanza di una classe a una funzione che implementa la stessa interfaccia:
function feed(dog: Dog) {
// ...
}
import { expect, test, vi } from 'vitest';
import { feed } from '../src/feed.js';
const Dog = vi.fn();
Dog.prototype.feed = vi.fn();
test('è possibile nutrire i cani', () => {
const dogMax = new Dog('Max');
feed(dogMax);
expect(dogMax.feed).toHaveBeenCalled();
expect(dogMax.isHungry()).toBe(false);
});
Ora, quando creiamo una nuova istanza della classe Dog
, il suo metodo speak
(insieme a feed
e greet
) è già mockato:
const Cooper = new Dog('Cooper');
Cooper.speak(); // bau forte!
Cooper.greet(); // Ciao! Il mio nome è Cooper!
// è possibile usare le asserzioni integrate per controllare la validità della chiamata
expect(Cooper.speak).toHaveBeenCalled();
expect(Cooper.greet).toHaveBeenCalled();
const Max = new Dog('Max');
// i metodi definiti sul prototipo sono condivisi tra le istanze
expect(Max.speak).toHaveBeenCalled();
expect(Max.greet).not.toHaveBeenCalled();
Possiamo riassegnare il valore di ritorno per un'istanza specifica:
const dog = new Dog('Cooper');
// "vi.mocked" è un'utilità di tipo, poiché
// TypeScript non sa che Dog è una classe mockata,
// incapsula qualsiasi funzione in un tipo MockInstance<T>
// senza convalidare se la funzione è un mock
vi.mocked(dog.speak).mockReturnValue('bau bau');
dog.speak(); // bau bau
Per mockare la proprietà, è possibile usare il metodo vi.spyOn(dog, 'name', 'get')
. In questo modo è possibile usare le asserzioni spy sulla proprietà mockata:
const dog = new Dog('Cooper');
const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max');
expect(dog.name).toBe('Max');
expect(nameSpy).toHaveBeenCalledTimes(1);
TIP
Puoi anche spiare getter e setter usando lo stesso metodo.
Foglio riassuntivo
INFO
vi
negli esempi seguenti è importato direttamente da vitest
. È anche possibile usarlo globalmente, se imposti globals
a true
nella tua configurazione.
Voglio…
Mockare variabili esportate
export const getter = 'variable';
import * as exports from './example.js';
vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');
Mockare una funzione esportata
- Esempio con
vi.mock
:
WARNING
Si tenga presente che una chiamata vi.mock
viene elevata all'inizio del file. Verrà sempre eseguita prima di tutte le importazioni.
export function method() {}
import { method } from './example.js';
vi.mock('./example.js', () => ({
method: vi.fn(),
}));
- Esempio con
vi.spyOn
:
import * as exports from './example.js';
vi.spyOn(exports, 'method').mockImplementation(() => {});
Mockare l'implementazione di una classe esportata
- Esempio con
vi.mock
e.prototype
:
export class SomeClass {}
import { SomeClass } from './example.js';
vi.mock(import('./example.js'), () => {
const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();
return { SomeClass };
});
// SomeClass.mock.instances conterrà l'istanza di SomeClass
- Esempio con
vi.spyOn
:
import * as mod from './example.js';
const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();
vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);
Spiare un oggetto restituito da una funzione
- Esempio usando la cache:
export function useObject() {
return { method: () => true };
}
import { useObject } from './example.js';
const obj = useObject();
obj.method();
import { useObject } from './example.js';
vi.mock(import('./example.js'), () => {
let _cache;
const useObject = () => {
if (!_cache) {
_cache = {
method: vi.fn(),
};
}
// ora ogni volta che useObject() viene chiamato,
// restituirà lo stesso riferimento all'oggetto
return _cache;
};
return { useObject };
});
const obj = useObject();
// obj.method è stato chiamato all'interno di "some-path"
expect(obj.method).toHaveBeenCalled();
Mockare parte di un modulo
import { mocked, original } from './some-path.js';
vi.mock(import('./some-path.js'), async importOriginal => {
const mod = await importOriginal();
return {
...mod,
mocked: vi.fn(),
};
});
original(); // ha il comportamento originale
mocked(); // è una funzione spy
WARNING
Si tenga presente che questo mocka solo l'accesso esterno. In questo esempio, se original
chiama mocked
internamente, chiamerà sempre la funzione definita nel modulo, non nella factory del mock.
Mockare la data corrente
Per mockare l'ora di Date
, puoi usare la funzione helper vi.setSystemTime
. Questo valore non verrà automaticamente ripristinato tra i diversi test.
Si noti che l'uso di vi.useFakeTimers
cambia anche l'ora di Date
.
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// resetta il tempo mockato
vi.useRealTimers();
Mockare una variabile globale
È possibile impostare una variabile globale assegnando un valore a globalThis
o usando l'helper vi.stubGlobal
. Quando si usa vi.stubGlobal
, non verrà automaticamente ripristinato tra i diversi test, a meno che non si abiliti l'opzione di configurazione unstubGlobals
o si chiami vi.unstubAllGlobals
.
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');
Mockare import.meta.env
- Per cambiare una variabile d'ambiente, è sufficiente assegnarle un nuovo valore.
WARNING
Il valore della variabile d'ambiente non verrà automaticamente ripristinato tra i diversi test.
import { beforeEach, expect, it } from 'vitest';
// prima di eseguire i test "VITE_ENV" è "test"
const originalViteEnv = import.meta.env.VITE_ENV;
beforeEach(() => {
import.meta.env.VITE_ENV = originalViteEnv;
});
it('cambia valore', () => {
import.meta.env.VITE_ENV = 'staging';
expect(import.meta.env.VITE_ENV).toBe('staging');
});
- Se si desidera resettare automaticamente i valori, è possibile usare l'helper
vi.stubEnv
con l'opzione di configurazioneunstubEnvs
abilitata (o chiamarevi.unstubAllEnvs
manualmente in una funzione di hookbeforeEach
):
import { expect, it, vi } from 'vitest';
// prima di eseguire i test "VITE_ENV" è "test"
import.meta.env.VITE_ENV === 'test';
it('cambia valore', () => {
vi.stubEnv('VITE_ENV', 'staging');
expect(import.meta.env.VITE_ENV).toBe('staging');
});
it('il valore viene ripristinato prima di eseguire un altro test', () => {
expect(import.meta.env.VITE_ENV).toBe('test');
});
export default defineConfig({
test: {
unstubEnvs: true,
},
});