Aller au contenu principal
Version : 28.x

Fonctions simulées

Les fonctions simulées sont également connues sous le nom d'« espions », car elles vous permettent d'espionner le comportement d'une fonction qui est appelée indirectement par un autre code, plutôt que de tester uniquement la sortie. Vous pouvez créer une fonction simulée avec jest.fn(). Si aucune implémentation n’est donnée, la fonction simulée retournera undefined lorsqu’elle est appelée.

info

Les exemples TypeScript de cette page ne fonctionneront comme documenté que si vous importez explicitement les API Jest :

import {expect, jest, test} from '@jest/globals';

Méthodes


Référence

mockFn.getMockName()

Returns the mock name string set by calling .mockName().

mockFn.mock.calls

Un tableau contenant les arguments d'appel de tous les appels qui ont été faits à cette fonction simulée. Chaque élément du tableau est un tableau d'arguments qui ont été passés pendant l'appel.

Par exemple : Une fonction simulée f qui a été appelée deux fois, avec les arguments f('arg1', 'arg2'), puis avec les arguments f('arg3', 'arg4'), aurait un tableau mock.calls qui ressemble à ceci :

[
['arg1', 'arg2'],
['arg3', 'arg4'],
];

mockFn.mock.results

Un tableau contenant les résultats de tous les appels qui ont été faits à cette fonction simulée. Chaque entrée de ce tableau est un objet contenant une propriété type, et une propriété value. type sera l'un des suivants :

  • 'return' - Indique que l'appel s'est terminé en retournant normalement.
  • 'throw' - Indique que l'appel s'est terminé en levant une valeur.
  • 'incomplete' - Indique que l'appel n'est pas encore terminé. Cela se produit si vous testez le résultat à partir de la fonction simulée elle-même, ou à partir d'une fonction qui a été appelée par la fonction simulée.

La propriété value contient la valeur qui a été levée ou retournée. value est indéfinie lorsque type === 'incomplete'.

Par exemple : Une fonction simulée f qui a été appelée trois fois, renvoyant 'result1', lançant une erreur, puis renvoyant 'result2', aurait un tableau mock.results qui ressemble à ceci :

[
{
type: 'return',
value: 'result1',
},
{
type: 'throw',
value: {
/* Error instance */
},
},
{
type: 'return',
value: 'result2',
},
];

mockFn.mock.instances

Un tableau qui contient toutes les instances d'objet qui ont été instanciées à partir de cette fonction simulée en utilisant new.

Par exemple : Une fonction simulée qui a été instanciée deux fois aurait le tableau mock.instances suivant :

const mockFn = jest.fn();

const a = new mockFn();
const b = new mockFn();

mockFn.mock.instances[0] === a; // true
mockFn.mock.instances[1] === b; // true

mockFn.mock.contexts

Un tableau qui contient les contextes pour tous les appels de la fonction simulée.

Un contexte est la valeur this qu'une fonction reçoit lorsqu'elle est appelée. Le contexte peut être défini en utilisant Function.prototype.bind, Function.prototype.call ou Function.prototype.apply.

Par exemple :

const mockFn = jest.fn();

const boundMockFn = mockFn.bind(thisContext0);
boundMockFn('a', 'b');
mockFn.call(thisContext1, 'a', 'b');
mockFn.apply(thisContext2, ['a', 'b']);

mockFn.mock.contexts[0] === thisContext0; // true
mockFn.mock.contexts[1] === thisContext1; // true
mockFn.mock.contexts[2] === thisContext2; // true

mockFn.mock.lastCall

Un tableau contenant les arguments d'appel du dernier appel qui a été fait à cette fonction simulée. Si la fonction n'a pas été appelée, elle retournera undefined.

Par exemple : Une fonction simulée f qui a été appelée deux fois, avec les arguments f('arg1', 'arg2'), puis avec les arguments f('arg3', 'arg4'), aurait un tableau mock.lastCall qui ressemble à ceci :

['arg3', 'arg4'];

mockFn.mockClear()

Efface toutes les informations stockées dans les tableaux mockFn.mock.calls, mockFn.mock.instances, mockFn.mock.contexts et mockFn.mock.results. Souvent, cela est utile lorsque vous voulez nettoyer les données d'utilisation d'une simulation entre deux assertions.

Attention, mockFn.mockClear() remplacera mockFn.mock, et ne se contentera pas de réinitialiser les valeurs de ses propriétés ! Vous devriez donc éviter d'assigner mockFn.mock à d'autres variables, temporaires ou non, pour être sûr de ne pas accéder à des données périmées.

L'option de configuration clearMocks est disponible pour effacer les simulations automatiquement avant chaque test.

mockFn.mockReset()

Fait tout ce que mockFn.mockClear() fait, et supprime également toute valeur de retour ou d'implémentation simulées.

Ceci est utile lorsque vous voulez réinitialiser complètement une simulation à son état initial. (Notez que la réinitialisation d'un espion se traduira par une fonction sans valeur de retour).

The resetMocks configuration option is available to reset mocks automatically before each test.

mockFn.mockRestore()

Fait tout ce que mockFn.mockReset() fait, et restaure également l'implémentation originale (non simulée).

Ceci est utile lorsque vous voulez simuler des fonctions dans certains cas de test et restaurer l'implémentation originale dans d'autres.

Attention, mockFn.mockRestore() ne fonctionne que lorsque la simulation a été créée avec jest.spyOn(). Vous devez donc vous occuper vous-même de la restauration lorsque vous assignez manuellement jest.fn().

L'option de configuration restoreMocks est disponible pour restaurer les simulations automatiquement avant chaque test.

mockFn.mockImplementation(fn)

Accepte une fonction qui doit être utilisée comme l'implémentation de simulation. La simulation elle-même enregistrera toujours tous les appels qui entrent et les instances qui proviennent d'elle - la seule différence est que l'implémentation sera également exécutée lorsque la simulation est appelée.

astuce

jest.fn(implémentation) est un raccourci pour jest.fn().mockImplementation(implémentation).

const mockFn = jest.fn(scalar => 42 + scalar);

mockFn(0); // 42
mockFn(1); // 43

mockFn.mockImplementation(scalar => 36 + scalar);

mockFn(2); // 38
mockFn(3); // 39

.mockImplementation() peut également être utilisé pour simuler les constructeurs de classes :

SomeClass.js
module.exports = class SomeClass {
method(a, b) {}
};
SomeClass.test.js
const SomeClass = require('./SomeClass');

jest.mock('./SomeClass'); // cela se produit automatiquement avec l'auto-simulation

const mockMethod = jest.fn();
SomeClass.mockImplementation(() => {
return {
method: mockMethod,
};
});

const some = new SomeClass();
some.method('a', 'b');

console.log('Calls to method: ', mockMethod.mock.calls);

mockFn.mockImplementationOnce(fn)

Accepte une fonction qui sera utilisée comme une implémentation de simulation pour un appel à la fonction simulée. Peut être enchaîné de sorte que plusieurs appels de fonction produisent des résultats différents.

const mockFn = jest
.fn()
.mockImplementationOnce(cb => cb(null, true))
.mockImplementationOnce(cb => cb(null, false));

mockFn((err, val) => console.log(val)); // true
mockFn((err, val) => console.log(val)); // false

Lorsque la fonction simulée manque d'implémentations définies avec .mockImplementationOnce(), elle exécutera l'implémentation par défaut définie avec jest.fn(() => defaultValue) ou .mockImplementation(() => defaultValue) s'ils ont été appelés :

const mockFn = jest
.fn(() => 'par défaut')
.mockImplementationOnce(() => 'premier appel')
.mockImplementationOnce(() => 'second appel');

mockFn(); // 'premier appel'
mockFn(); // 'second appel'
mockFn(); // 'par défaut'
mockFn(); // 'par défaut'

mockFn.mockName(name)

Accepte une chaîne à utiliser dans le résultat du test à la place de 'jest.fn()' pour indiquer quelle fonction simulée est référencée.

Par exemple :

const mockFn = jest.fn().mockName('mockedFunction');

// mockFn();
expect(mockFn).toHaveBeenCalled();

Le résultat est cette erreur :

expect(mockedFunction).toHaveBeenCalled()

Expected number of calls: >= 1
Received number of calls: 0

mockFn.mockReturnThis()

Shorthand for:

jest.fn(function () {
return this;
});

mockFn.mockReturnValue(value)

Accepte une valeur qui sera retournée chaque fois que la fonction simulée est appelée.

const mock = jest.fn();

mock.mockReturnValue(42);
mock(); // 42

mock.mockReturnValue(43);
mock(); // 43

mockFn.mockReturnValueOnce(value)

Accepte une valeur qui sera retournée pour un appel à la fonction simulée. Peut être enchaîné de sorte que les appels successifs à la fonction simulée retournent des valeurs différentes. Quand il n'y a plus de valeurs mockReturnValueOnce à utiliser, les appels retourneront une valeur spécifiée par mockReturnValue.

const mockFn = jest
.fn()
.mockReturnValue('par défaut')
.mockReturnValueOnce('premier appel')
.mockReturnValueOnce('deuxième appel');

mockFn(); // 'premier appel'
mockFn(); // 'deuxième appel'
mockFn(); // 'par défaut'
mockFn(); // 'par défaut'

mockFn.mockResolvedValue(value)

Shorthand for:

jest.fn().mockImplementation(() => Promise.resolve(value));

Utile pour simuler les fonctions asynchrones dans les tests asynchrones :

test('async test', async () => {
const asyncMock = jest.fn().mockResolvedValue(43);

await asyncMock(); // 43
});

mockFn.mockResolvedValueOnce(value)

Shorthand for:

jest.fn().mockImplementationOnce(() => Promise.resolve(value));

Utile pour résoudre des valeurs différentes sur plusieurs appels asynchrones :

test('async test', async () => {
const asyncMock = jest
.fn()
.mockResolvedValue('par défaut')
.mockResolvedValueOnce('premier appel')
.mockResolvedValueOnce('deuxième appel');

await asyncMock(); // 'premier appel'
await asyncMock(); // 'deuxième appel'
await asyncMock(); // 'par défaut'
await asyncMock(); // 'par défaut'
});

mockFn.mockRejectedValue(value)

Shorthand for:

jest.fn().mockImplementation(() => Promise.reject(value));

Utile pour créer des fonctions simulées asynchrones qui seront toujours rejetées :

test('async test', async () => {
const asyncMock = jest
.fn()
.mockRejectedValue(new Error('Async error message'));

await asyncMock(); // lève 'Async error message'
});

mockFn.mockRejectedValueOnce(value)

Shorthand for:

jest.fn().mockImplementationOnce(() => Promise.reject(value));

Utile avec .mockResolvedValueOnce() ou pour rejeter avec des exceptions différentes sur plusieurs appels asynchrones :

test('async test', async () => {
const asyncMock = jest
.fn()
.mockResolvedValueOnce('premier appel')
.mockRejectedValueOnce(new Error('Async error message'));

await asyncMock(); // 'premier appel'
await asyncMock(); // lève 'Async error message'
});

Utilisation de TypeScript

astuce

Veuillez consulter le guide Premiers pas pour plus de détails sur la façon de configurer Jest avec TypeScript.

jest.fn(implementation?)

Les typages simulés corrects seront déduits, si l'implémentation est passée à la fonction jest.fn(). Il existe de nombreux cas d'utilisation où l'implémentation est omise. Pour assurer la sécurité des types, vous pouvez passer un argument de type générique (voir aussi les exemples ci-dessus pour plus de référence) :

import {expect, jest, test} from '@jest/globals';
import type add from './add';
import calculate from './calc';

test('calculate appelle add', () => {
// Crée une nouvelle simulation qui peut être utilisé à la place de `add`.
const mockAdd = jest.fn<typeof add>();

// `.mockImplementation()` peut maintenant déduire que `a` et `b` sont des `number`
// et que la valeur renvoyée est un `number`.
mockAdd.mockImplementation((a, b) => {
// Oui, cette fonction simulée ajoute toujours deux nombres mais imaginez que
// c'est une fonction complexe que nous simulons.
return a + b
});

// `mockAdd` est correctement typé et donc accepté par tout
// ce que requiert `add`.
calculate(mockAdd, 1, 2);

expect(mockAdd).toHaveBeenCalledTimes(1);
expect(mockAdd).toHaveBeenCalledWith(1, 2);
});