Fonctions Mocks
Vous pouvez créer une fonction mock pour suivre son exécution avec la méthode vi.fn
. Si vous souhaitez suivre une méthode sur un objet déjà créé, vous pouvez utiliser la méthode 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;
Utilisez les assertions de simulation (par exemple, toHaveBeenCalled
) avec expect
pour valider le comportement de la simulation. Cette référence API décrit les propriétés et méthodes disponibles pour contrôler le comportement d'une simulation.
TIP
L'implémentation de fonction personnalisée dans les types ci-dessous est marquée avec un générique <T>
.
getMockImplementation
function getMockImplementation(): T | undefined;
Retourne l'implémentation actuelle de la simulation, si elle existe.
Si la simulation a été créée avec vi.fn
, elle utilisera la fonction fournie comme implémentation de la simulation.
Si la simulation a été créée avec vi.spyOn
, elle retournera undefined
à moins qu'une implémentation personnalisée n'ait été fournie.
getMockName
function getMockName(): string;
Permet de retourner le nom assigné à la simulation avec la méthode .mockName(name)
. Par défaut, elle retournera vi.fn()
.
mockClear
function mockClear(): MockInstance<T>;
Efface toutes les informations sur chaque appel. Après son appel, toutes les propriétés de l'objet .mock
reviendront à leur état initial. Cette méthode ne réinitialise pas les implémentations. Elle est utile pour nettoyer les simulations entre les différentes assertions.
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']]);
// Effacer l'historique des appels mais conserver l'implémentation mock.
spy.mockClear();
expect(spy.mock.calls).toEqual([]);
expect(person.greet('Bob')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Bob']]);
Pour appeler automatiquement cette méthode avant chaque test, activez le paramètre clearMocks
dans la configuration.
mockName
function mockName(name: string): MockInstance<T>;
Définit le nom interne de la simulation. C'est utile pour identifier la simulation lorsqu'une assertion échoue.
mockImplementation
function mockImplementation(fn: T): MockInstance<T>;
Accepte une fonction à utiliser comme implémentation de la simulation. TypeScript s'attend à ce que les arguments et le type de retour correspondent à ceux de la fonction originale.
const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1);
// ou : 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>;
Accepte une fonction à utiliser comme implémentation de la simulation. TypeScript s'attend à ce que les arguments et le type de retour correspondent à ceux de la fonction originale. Cette méthode peut être enchaînée pour produire des résultats différents pour plusieurs appels de fonction.
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true) // 1er appel
.mockImplementationOnce(() => false); // 2ème appel
myMockFn(); // 1er appel : true
myMockFn(); // 2ème appel : false
Lorsque la fonction simulée n'a plus d'implémentations spécifiques, elle invoquera l'implémentation par défaut définie avec vi.fn(() => defaultValue)
ou .mockImplementation(() => defaultValue)
si celles-ci ont été configurées :
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>>;
Remplace temporairement l'implémentation originale de la simulation pendant l'exécution du callback.
const myMockFn = vi.fn(() => 'original');
myMockFn.withImplementation(
() => 'temp',
() => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
Peut être utilisé avec un callback asynchrone. La méthode doit être await
ée pour que l'implémentation originale soit restaurée par la suite.
test('async callback', async () => {
const myMockFn = vi.fn(() => 'original');
// Nous attendons cet appel puisque le callback est asynchrone
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
});
Notez que cette méthode prend le pas sur mockImplementationOnce
.
mockRejectedValue
function mockRejectedValue(value: unknown): MockInstance<T>;
Accepte une erreur qui sera rejetée lorsque la fonction asynchrone est appelée.
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // lève Error<'Async error'>
mockRejectedValueOnce
function mockRejectedValueOnce(value: unknown): MockInstance<T>;
Accepte une valeur qui sera rejetée lors du prochain appel de fonction. Si enchaînée, chaque appel consécutif rejettera la valeur spécifiée.
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // 'first call'
await asyncMock(); // lève Error<'Async error'>
mockReset
function mockReset(): MockInstance<T>;
Effectue les mêmes actions que mockClear
et réinitialise l'implémentation interne à la fonction originale. Cela réinitialise également toutes les implémentations "once".
Notez que la réinitialisation d'une simulation créée avec vi.fn()
définira l'implémentation à une fonction vide qui retourne undefined
. La réinitialisation d'une simulation créée avec vi.fn(impl)
restaurera l'implémentation à impl
.
Ceci est utile lorsque vous souhaitez réinitialiser une simulation à son état initial.
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']]);
// Effacer l'historique des appels et réinitialiser l'implémentation, mais la méthode est toujours espionnée.
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']]);
Pour appeler automatiquement cette méthode avant chaque test, activez le paramètre mockReset
dans la configuration.
mockRestore
function mockRestore(): MockInstance<T>;
Effectue les mêmes actions que mockReset
et restaure les descripteurs originaux des objets espionnés.
Notez que la restauration d'une simulation créée avec vi.fn()
définira l'implémentation à une fonction vide qui retourne undefined
. La restauration d'une simulation créée avec vi.fn(impl)
restaurera l'implémentation à 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']]);
// Effacer l'historique des appels et restaurer la méthode de l'objet espionné.
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([]);
Pour appeler automatiquement cette méthode avant chaque test, activez le paramètre restoreMocks
dans la configuration.
mockResolvedValue
function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>;
Accepte une valeur qui sera résolue lorsque la fonction asynchrone est appelée. TypeScript n'acceptera que les valeurs qui correspondent au type de retour de la fonction originale.
const asyncMock = vi.fn().mockResolvedValue(42);
await asyncMock(); // 42
mockResolvedValueOnce
function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): MockInstance<T>;
Accepte une valeur qui sera résolue lors du prochain appel de la fonction. TypeScript n'acceptera que les valeurs qui correspondent au type de retour de la fonction originale. Si enchaînée, chaque appel consécutif résoudra la valeur spécifiée.
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>;
Utilisez cette méthode pour retourner le contexte this
de la méthode sans invoquer l'implémentation réelle. C'est un raccourci pour :
spy.mockImplementation(function () {
return this;
});
mockReturnValue
function mockReturnValue(value: ReturnType<T>): MockInstance<T>;
Accepte une valeur qui sera retournée chaque fois que la fonction simulée est appelée. TypeScript n'acceptera que les valeurs qui correspondent au type de retour de la fonction originale.
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
mockReturnValueOnce
function mockReturnValueOnce(value: ReturnType<T>): MockInstance<T>;
Accepte une valeur qui sera retournée lors du prochain appel de la fonction simulée. TypeScript n'acceptera que les valeurs qui correspondent au type de retour de la fonction originale.
Lorsque la fonction simulée n'a plus d'implémentations spécifiques, elle invoquera l'implémentation par défaut définie avec vi.fn(() => defaultValue)
ou .mockImplementation(() => defaultValue)
si elles ont été appelées :
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>[];
Ce tableau contient tous les arguments de chaque appel. Chaque élément du tableau représente les arguments d'un appel.
const fn = vi.fn();
fn('arg1', 'arg2');
fn('arg3');
fn.mock.calls ===
[
['arg1', 'arg2'], // premier appel
['arg3'], // deuxième appel
];
mock.lastCall
const lastCall: Parameters<T> | undefined;
Ceci contient les arguments du dernier appel. Si la simulation n'a pas été appelée, elle retournera undefined
.
mock.results
interface MockResultReturn<T> {
type: 'return';
/**
* The value that was returned from the function.
* If function returned a Promise, then this will be a resolved value.
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* An error that was thrown during function execution.
*/
value: any;
}
type MockResult<T> =
| MockResultReturn<T>
| MockResultThrow
| MockResultIncomplete;
const results: MockResult<ReturnType<T>>[];
Ce tableau contient toutes les valeurs qui ont été retournées
par la fonction. Chaque élément du tableau est un objet avec les propriétés type
et value
. Les types disponibles sont :
'return'
- la fonction s'est exécutée sans lever d'exception.'throw'
- la fonction a levé une erreur.
La propriété value
contient la valeur retournée ou l'erreur levée. Si la fonction a retourné une Promise
, alors le type de résultat sera toujours 'return'
même si la promesse a été rejetée.
const fn = vi
.fn()
.mockReturnValueOnce('result')
.mockImplementationOnce(() => {
throw new Error('thrown error');
});
const result = fn(); // a retourné 'result'
try {
fn(); // a levé une erreur
} catch {}
fn.mock.results ===
[
// first result
{
type: 'return',
value: 'result',
},
// last result
{
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 tableau contenant toutes les valeurs qui ont été résolues
ou rejetées
par la fonction.
Ce tableau sera vide si la fonction n'a pas encore été résolue ou rejetée.
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[];
Cette propriété indique l'ordre d'exécution de la fonction simulée. C'est un tableau de nombres partagés par toutes les simulations définies.
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>[];
Cette propriété est un tableau des contextes this
utilisés lors de chaque appel à la fonction simulée.
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>[];
Cette propriété est un tableau contenant toutes les instances créées lorsque la simulation a été appelée avec le mot-clé new
. Notez qu'il s'agit du contexte réel (this
) de la fonction, et non de sa valeur de retour.
WARNING
Si la simulation a été instanciée avec new MyClass()
, alors mock.instances
sera un tableau contenant une seule valeur :
const MyClass = vi.fn();
const a = new MyClass();
MyClass.mock.instances[0] === a;
Si vous retournez une valeur depuis le constructeur, elle ne sera pas dans le tableau instances
, mais plutôt dans results
:
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();
Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;