Funzioni Mock
È possibile creare una funzione mock utilizzando il metodo vi.fn
per tracciarne l'esecuzione. Se si desidera monitorare un metodo su un oggetto già esistente, è possibile utilizzare il metodo vi.spyOn
:
import { vi } from 'vitest';
const fn = vi.fn();
fn('hello world');
fn.mock.calls[0] === ['hello world'];
const market = {
getApples: () => 100,
};
const getApplesSpy = vi.spyOn(market, 'getApples');
market.getApples();
getApplesSpy.mock.calls.length === 1;
È consigliabile utilizzare le verifiche mock (ad esempio, toHaveBeenCalled
) con expect
per asserire il risultato del mock. Questo riferimento API descrive le proprietà e i metodi disponibili per manipolare il comportamento del mock.
TIP
L'implementazione della funzione personalizzata nei tipi seguenti è indicata con il tipo generico <T>
.
getMockImplementation
function getMockImplementation(): T | undefined;
Restituisce l'implementazione mock corrente, se presente.
Se il mock è stato creato con vi.fn
, utilizzerà il metodo fornito come implementazione del mock.
Se il mock è stato creato con vi.spyOn
, restituirà undefined
se non viene fornita un'implementazione personalizzata.
getMockName
function getMockName(): string;
Utilizzare questo metodo per restituire il nome assegnato al mock tramite il metodo .mockName(name)
. Per impostazione predefinita, restituirà vi.fn()
.
mockClear
function mockClear(): MockInstance<T>;
Cancella tutte le informazioni relative a ogni chiamata. Dopo averlo chiamato, tutte le proprietà su .mock
torneranno al loro stato iniziale. Questo metodo non ripristina le implementazioni. È utile per ripulire i mock tra diverse asserzioni.
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// azzera la cronologia delle chiamate ma mantiene l'implementazione del mock
spy.mockClear();
expect(spy.mock.calls).toEqual([]);
expect(person.greet('Bob')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Bob']]);
Per chiamare automaticamente questo metodo prima di ogni test, abilitare l'impostazione clearMocks
nella configurazione.
mockName
function mockName(name: string): MockInstance<T>;
Imposta il nome interno del mock. Questo è utile per identificare il mock quando un'asserzione fallisce.
mockImplementation
function mockImplementation(fn: T): MockInstance<T>;
Accetta una funzione da usare come implementazione del mock. TypeScript richiede che gli argomenti e il tipo di ritorno corrispondano a quelli della funzione originale.
const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1);
// o: vi.fn(apples => apples + 1);
const NelliesBucket = mockFn(0);
const BobsBucket = mockFn(1);
NelliesBucket === 1; // true
BobsBucket === 2; // true
mockFn.mock.calls[0][0] === 0; // true
mockFn.mock.calls[1][0] === 1; // true
mockImplementationOnce
function mockImplementationOnce(fn: T): MockInstance<T>;
Accetta una funzione da usare come implementazione del mock. TypeScript richiede che gli argomenti e il tipo di ritorno corrispondano a quelli della funzione originale. Questo metodo può essere concatenato per produrre risultati diversi per chiamate successive della funzione.
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true) // 1a chiamata
.mockImplementationOnce(() => false); // 2a chiamata
myMockFn(); // 1a chiamata: true
myMockFn(); // 2a chiamata: false
Quando la funzione mock non ha più implementazioni specifiche, invocherà l'implementazione predefinita impostata con vi.fn(() => defaultValue)
o .mockImplementation(() => defaultValue)
, se presenti:
const myMockFn = vi
.fn(() => 'default')
.mockImplementationOnce(() => 'first call')
.mockImplementationOnce(() => 'second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
withImplementation
function withImplementation(fn: T, cb: () => void): MockInstance<T>;
function withImplementation(
fn: T,
cb: () => Promise<void>
): Promise<MockInstance<T>>;
Sovrascrive temporaneamente l'implementazione originale del mock per la durata dell'esecuzione della callback.
const myMockFn = vi.fn(() => 'original');
myMockFn.withImplementation(
() => 'temp',
() => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
Può essere usato con una callback asincrona. Il metodo deve essere atteso (awaited) affinché l'implementazione originale venga ripristinata in seguito.
test('async callback', async () => {
const myMockFn = vi.fn(() => 'original');
// Dobbiamo attendere questa chiamata poiché la callback è asincrona
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
});
Si noti che questo metodo ha la precedenza su mockImplementationOnce
.
mockRejectedValue
function mockRejectedValue(value: unknown): MockInstance<T>;
Accetta un errore che causerà il rifiuto della Promise quando viene chiamata la funzione asincrona.
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // genera Error<'Async error'>
mockRejectedValueOnce
function mockRejectedValueOnce(value: unknown): MockInstance<T>;
Accetta un valore che causerà il rifiuto della Promise durante la prossima chiamata di funzione. Se concatenato, ogni chiamata consecutiva causerà il rifiuto del valore specificato.
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // 'first call'
await asyncMock(); // genera Error<'Async error'>
mockReset
function mockReset(): MockInstance<T>;
Esegue le stesse operazioni di mockClear
e ripristina l'implementazione interna alla funzione originale. Questo ripristina anche tutte le implementazioni "once".
Si noti che il ripristino di un mock creato con vi.fn()
imposterà l'implementazione su una funzione vuota che restituisce undefined
. Il ripristino di un mock creato con vi.fn(impl)
ripristinerà l'implementazione a impl
.
Questo è utile quando si desidera riportare un mock al suo stato iniziale.
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// azzera la cronologia delle chiamate e ripristina l'implementazione, ma il metodo è ancora monitorato
spy.mockReset();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([['Bob']]);
Per chiamare automaticamente questo metodo prima di ogni test, abilitare l'impostazione mockReset
nella configurazione.
mockRestore
function mockRestore(): MockInstance<T>;
Esegue le stesse operazioni di mockReset
e ripristina i descrittori originali degli oggetti monitorati.
Si noti che il ripristino di un mock creato con vi.fn()
imposterà l'implementazione su una funzione vuota che restituisce undefined
. Il ripristino di un mock creato con vi.fn(impl)
ripristinerà l'implementazione a impl
.
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// azzera la cronologia delle chiamate e ripristina il metodo dell'oggetto monitorato
spy.mockRestore();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).not.toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([]);
Per chiamare automaticamente questo metodo prima di ogni test, abilitare l'impostazione restoreMocks
nella configurazione.
mockResolvedValue
function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>;
Accetta un valore con cui la Promise verrà risolta quando viene chiamata la funzione asincrona. TypeScript accetterà solo valori che corrispondono al tipo di ritorno della funzione originale.
const asyncMock = vi.fn().mockResolvedValue(42);
await asyncMock(); // 42
mockResolvedValueOnce
function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): MockInstance<T>;
Accetta un valore con cui la Promise verrà risolta durante la prossima chiamata di funzione. TypeScript accetterà solo valori che corrispondono al tipo di ritorno della funzione originale. Se concatenato, ogni chiamata consecutiva risolverà il valore specificato.
const asyncMock = vi
.fn()
.mockResolvedValue('default')
.mockResolvedValueOnce('first call')
.mockResolvedValueOnce('second call');
await asyncMock(); // first call
await asyncMock(); // second call
await asyncMock(); // default
await asyncMock(); // default
mockReturnThis
function mockReturnThis(): MockInstance<T>;
Utilizzare questo metodo se è necessario restituire il contesto this
dal metodo senza invocare l'implementazione effettiva. Questa è una scorciatoia per:
spy.mockImplementation(function () {
return this;
});
mockReturnValue
function mockReturnValue(value: ReturnType<T>): MockInstance<T>;
Accetta un valore che verrà restituito ogni volta che viene chiamata la funzione mock. TypeScript accetterà solo valori che corrispondono al tipo di ritorno della funzione originale.
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
mockReturnValueOnce
function mockReturnValueOnce(value: ReturnType<T>): MockInstance<T>;
Accetta un valore che verrà restituito ogni volta che viene chiamata la funzione mock. TypeScript accetterà solo valori che corrispondono al tipo di ritorno della funzione originale.
Quando la funzione mock esaurisce le implementazioni, invocherà l'implementazione predefinita impostata con vi.fn(() => defaultValue)
o .mockImplementation(() => defaultValue)
se sono state chiamate:
const myMockFn = vi
.fn()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
mock.calls
const calls: Parameters<T>[];
Questo è un array contenente gli argomenti di ogni chiamata. Ogni elemento dell'array rappresenta gli argomenti di una singola chiamata.
const fn = vi.fn();
fn('arg1', 'arg2');
fn('arg3');
fn.mock.calls ===
[
['arg1', 'arg2'], // prima chiamata
['arg3'], // seconda chiamata
];
mock.lastCall
const lastCall: Parameters<T> | undefined;
Questa proprietà contiene gli argomenti dell'ultima chiamata. Se il mock non è stato chiamato, restituirà undefined
.
mock.results
interface MockResultReturn<T> {
type: 'return';
/**
* Il valore restituito dalla funzione.
* Se la funzione ha restituito una Promise, questo sarà il valore con cui la Promise è stata risolta.
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* Un errore che è stato generato durante l'esecuzione della funzione.
*/
value: any;
}
type MockResult<T> =
| MockResultReturn<T>
| MockResultThrow
| MockResultIncomplete;
const results: MockResult<ReturnType<T>>[];
Questo è un array che contiene i valori restituiti
dalla funzione. Ogni elemento dell'array è un oggetto con le proprietà type
e value
. I tipi disponibili sono:
'return'
- la funzione è stata completata senza generare errori.'throw'
- la funzione ha generato un errore.
La proprietà value
contiene il valore restituito o l'errore generato. Se la funzione ha restituito una Promise
, il type
sarà sempre 'return'
anche se la Promise è stata rifiutata.
const fn = vi
.fn()
.mockReturnValueOnce('result')
.mockImplementationOnce(() => {
throw new Error('thrown error');
});
const result = fn(); // ha ritornato 'result'
try {
fn(); // ha generato Error
} catch {}
fn.mock.results ===
[
// primo risultato
{
type: 'return',
value: 'result',
},
// ultimo risultato
{
type: 'throw',
value: Error,
},
];
mock.settledResults
interface MockSettledResultFulfilled<T> {
type: 'fulfilled';
value: T;
}
interface MockSettledResultRejected {
type: 'rejected';
value: any;
}
export type MockSettledResult<T> =
| MockSettledResultFulfilled<T>
| MockSettledResultRejected;
const settledResults: MockSettledResult<Awaited<ReturnType<T>>>[];
Un array che contiene tutti i valori con cui la funzione è stata risolta
o rifiutata
.
Questo array sarà vuoto se la Promise restituita dalla funzione non è mai stata risolta o rifiutata.
const fn = vi.fn().mockResolvedValueOnce('result');
const result = fn();
fn.mock.settledResults === [];
await result;
fn.mock.settledResults ===
[
{
type: 'fulfilled',
value: 'result',
},
];
mock.invocationCallOrder
const invocationCallOrder: number[];
Questa proprietà restituisce l'ordine di esecuzione della funzione mock. È un array di numeri che rappresenta l'ordine di chiamata globale tra tutti i mock definiti.
const fn1 = vi.fn();
const fn2 = vi.fn();
fn1();
fn2();
fn1();
fn1.mock.invocationCallOrder === [1, 3];
fn2.mock.invocationCallOrder === [2];
mock.contexts
const contexts: ThisParameterType<T>[];
Questa proprietà è un array dei valori this
utilizzati in ogni chiamata alla funzione mock.
const fn = vi.fn();
const context = {};
fn.apply(context);
fn.call(context);
fn.mock.contexts[0] === context;
fn.mock.contexts[1] === context;
mock.instances
const instances: ReturnType<T>[];
Questa proprietà è un array contenente tutte le istanze create quando il mock è stato invocato con la parola chiave new
. Si noti che questo rappresenta il contesto (this
) effettivo della funzione, non il valore di ritorno.
WARNING
Se il mock è stato istanziato con new MyClass()
, mock.instances
conterrà un array con un solo valore:
const MyClass = vi.fn();
const a = new MyClass();
MyClass.mock.instances[0] === a;
Se si restituisce un valore dal costruttore, questo non sarà incluso nell'array instances
, ma piuttosto in results
:
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();
Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;