Aller au contenu principal
Version : 29.4

Expect

Lorsque vous écrivez des tests, vous devez souvent vérifier que les valeurs remplissent certaines conditions. expect vous donne accès à un certain nombre de « comparateurs » qui vous permettent de valider différentes choses.

astuce

For additional Jest matchers maintained by the Jest Community check out jest-extended.

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';

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

Référence


Expect

expect(valeur)

La fonction expect est utilisée à chaque fois que vous souhaitez tester une valeur. Vous appellerez rarement expect par lui-même. Au lieu de cela, vous utiliserez expect avec une fonction « comparateur » pour vérifier quelque chose sur une valeur.

Il est plus facile de comprendre cela avec un exemple. Supposons que vous ayez une méthode bestLaCroixFlavor() qui est censée renvoyer la chaîne 'grapefruit'. Voici comment vous pourriez tester cela :

test('la meilleure saveur est le pamplemousse', () => {
expect(bestLaCroixFlavor()).toBe('grapefruit');
});

Dans ce cas, toBe est la fonction comparateur. Il existe un grand nombre de fonctions comparateur différentes, documentées ci-dessous, pour vous aider à tester différentes choses.

L'argument de expect doit être la valeur que votre code produit, et le paramètre du comparateur doit être la valeur correcte. Si vous les confondez, vos tests fonctionneront toujours, mais les messages d'erreur des tests qui échouent seront étranges.

Modifiers

.not

Si vous savez comment tester quelque chose, .not vous permet de tester son opposé. Par exemple, ce code teste que le meilleur goût de La Croix n'est pas coconut :

test('la meilleure saveur n\'est pas coconut', () => {
expect(bestLaCroixFlavor()).not.toBe('coconut');
});

.resolves

Utilisez resolves pour déballer la valeur d'une promesse remplie afin que tout autre comparateur puisse être enchaîné. Si la promesse est rejetée, l'assertion échoue.

Par exemple, ce code teste que la promesse se résout et que la valeur résultante est 'lemon' :

test('resolves to lemon', () => {
// assurez-vous d'ajouter une instruction return
return expect(Promise.resolve('lemon')).resolves.toBe('lemon');
});
remarque

Since you are still testing promises, the test is still asynchronous. Par conséquent, vous devrez dire à Jest d'attendre en retournant l'assertion non enveloppée.

Alternativement, vous pouvez utiliser async/wait en combinaison avec .resolves :

test('resolves to lemon', async () => {
await expect(Promise.resolve('lemon')).resolves.toBe('lemon');
await expect(Promise.resolve('lemon')).resolves.not.toBe('octopus');
});

.rejects

Utilisez .rejects pour déballer la raison d'une promesse rejetée afin que tout autre comparateur puisse être enchaîné. Si la promesse est remplie, l'assertion échoue.

Par exemple, ce code teste que la promesse rejette avec la raison 'octopus' :

test('rejects to octopus', () => {
// assurez-vous d'ajouter une instruction return
return expect(Promise.reject(new Error('octopus'))).rejects.toThrow(
'octopus',
);
});
remarque

Since you are still testing promises, the test is still asynchronous. Par conséquent, vous devrez dire à Jest d'attendre en retournant l'assertion non enveloppée.

Alternativement, vous pouvez utiliser async/wait en combinaison avec .rejects .

test('rejects to octopus', async () => {
await expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus');
});

Matchers

.toBe(value)

Utilisez .toBe pour comparer des valeurs primitives ou pour vérifier l'identité référentielle d'instances d'objets. Il appelle Object.is pour comparer les valeurs, ce qui est encore mieux pour les tests que l'opérateur d'égalité stricte ===.

Par exemple, ce code validera certaines propriétés de l'objet can :

const can = {
name: 'pamplemousse',
ounces: 12,
};

describe('le can', () => {
test('a 12 ounces', () => {
expect(can.ounces).toBe(12);
});

test('a un nom sophistiqué', () => {
expect(can.name).toBe('pamplemousse');
});
});

N'utilisez pas .toBe avec des nombres à virgule flottante. Par exemple, en raison de l'arrondi, en JavaScript 0.2 + 0.1 n'est pas strictement égal à 0.3. Si vous avez des nombres à virgule flottante, essayez à la place .toBeCloseTo.

Bien que le comparateur .toBe vérifie l'identité référentielle, il reporte une comparaison profonde des valeurs si l'assertion échoue. Si les différences entre les propriétés ne vous aident pas à comprendre pourquoi un test échoue, surtout si le rapport est volumineux, vous pouvez déplacer la comparaison dans la fonction expect. Par exemple, pour vérifier si des éléments ont ou non la même instance :

  • rewrite expect(received).toBe(expected) as expect(Object.is(received, expected)).toBe(true)
  • rewrite expect(received).not.toBe(expected) as expect(Object.is(received, expected)).toBe(false)

.toHaveBeenCalled()

Aussi sous l'alias : .toBeCalled()

Use .toHaveBeenCalled to ensure that a mock function was called.

Par exemple, supposons que vous avez une fonction drinkAll(boisson, flavour) qui prend une fonction drink et l'applique à toutes les boissons disponibles. Vous pourriez vérifier que drink est appelée pour 'lemon', mais pas pour 'octopus', parce que la saveur 'octopus' est vraiment bizarre et pourquoi quelque chose serait-il aromatisé à l'octopus ? Vous pouvez le faire avec cette suite de tests :

function drinkAll(callback, flavour) {
if (flavour !== 'octopus') {
callback(flavour);
}
}

describe('drinkAll', () => {
test('boit quelque chose à la saveur lemon', () => {
const drink = jest.fn();
drinkAll(drink, 'lemon');
expect(drink).toHaveBeenCalled();
});

test('ne boit pas quelque chose à la saveur octopus', () => {
const drink = jest.fn();
drinkAll(drink, 'octopus');
expect(drink).not.toHaveBeenCalled();
});
});

.toHaveBeenCalledTimes(number)

Aussi sous l'alias : .toBeCalledTimes(number)

Utilisez .toHaveBeenCalledTimes pour vous assurer qu'une fonction simulée a été appelée le nombre exact de fois.

Par exemple, supposons que vous ayez une fonction drinkEach(drink, Array<flavor>) qui prend une fonction drink et l'applique à un tableau de boissons passées. Vous pouvez vérifier que la fonction drink a été appelée le nombre exact de fois. Vous pouvez le faire avec cette suite de tests :

test('drinkEach boit chaque drink', () => {
const drink = jest.fn();
drinkEach(drink, ['lemon', 'octopus']);
expect(drink).toHaveBeenCalledTimes(2);
});

.toHaveBeenCalledWith(arg1, arg2, ...)

Aussi sous l'alias : .toBeCalledWith()

Utilisez .toHaveBeenCalledWith pour vous assurer qu'une fonction simulée a été appelée avec des arguments spécifiques. Les arguments sont vérifiés avec le même algorithme que celui de .toEqual.

Par exemple, supposons que vous pouvez enregistrer une boisson avec une fonction register, et que applyToAll(f) devrait appliquer la fonction f à toutes les boissons enregistrées. Pour vous assurer que cela fonctionne, vous pouvez écrire :

test('l\'enregistrement s\'applique correctement à orange La Croix', () => {
const beverage = new LaCroix('orange');
register(beverage);
const f = jest.fn();
applyToAll(f);
expect(f).toHaveBeenCalledWith(beverage);
});

.toHaveBeenLastCalledWith(arg1, arg2, ...)

Aussi sous l'alias : .lastCalledWith(arg1, arg2, ...)

Si vous avez une fonction simulée, vous pouvez utiliser .toHaveBeenLastCalledWith pour tester avec quels arguments il a été appelé en dernier. Par exemple, supposons que vous avez une fonction applyToAllFlavors(f) qui applique f à un tas de saveurs, et que vous voulez vous assurer que lorsque vous l'appelez, la dernière saveur sur laquelle elle opère est 'mango'. Vous pouvez écrire :

test('appliquation à tous les parfums, mango est le dernier', () => {
const drink = jest.fn();
applyToAllFlavors(drink);
expect(drink).toHaveBeenLastCalledWith('mango');
});

.toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)

Aussi sous l'alias : .nthCalledWith(nthCall, arg1, arg2, ...)

Si vous avez une fonction simulée, vous pouvez utiliser .toHaveBeenNthCalledWith pour tester avec quels arguments elle a été énièmement appelée. Par exemple, supposons que vous ayez une fonction drinkEach(drink, Array<flavor>) qui applique f à un tas de saveurs, et vous voulez vous assurer que lorsque vous l'appelez, la première saveur sur laquelle elle opère est 'lemon' et la seconde 'octopus'. Vous pouvez écrire :

test('drinkEach boit chaque drink', () => {
const drink = jest.fn();
drinkEach(drink, ['lemon', 'octopus']);
expect(drink).toHaveBeenNthCalledWith(1, 'lemon');
expect(drink).toHaveBeenNthCalledWith(2, 'octopus');
});
remarque

L'argument nth doit être un entier positif à partir de 1.

.toHaveReturned()

Aussi sous l'alias : .toReturn()

Si vous avez une fonction simulée, vous pouvez utiliser .toHaveReturned pour tester que la fonction simulée a retourné avec succès (c'est-à-dire qu'elle n'a pas lancé d'erreur) au moins une fois. Par exemple, supposons que vous avez un drink simulé qui renvoie true. Vous pouvez écrire :

test('drinks retourne', () => {
const drink = jest.fn(() => true);

drink();

expect(drink).toHaveReturned();
});

.toHaveReturnedTimes(number)

Aussi sous l'alias : .toReturnTimes(nombre)

Utilisez .toHaveReturnedTimes pour vous assurer qu'une fonction simulée est retournée avec succès (c'est-à-dire qu'elle n'a pas lancé d'erreur) un nombre exact de fois. Les appels à la fonction simulée qui provoquent une erreur ne sont pas comptabilisés dans le nombre de retours de la fonction.

Par exemple, supposons que vous avez un drink simulé qui renvoie true. Vous pouvez écrire :

test('drink retourne 2 fois', () => {
const drink = jest.fn(() => true);

drink();
drink();

expect(drink).toHaveReturnedTimes(2);
});

.toHaveReturnedWith(value)

Aussi sous l'alias : .toReturnWith(value)

Utilisez .toHaveReturnedWith pour vous assurer qu'une fonction simulée a retourné une valeur spécifique.

Par exemple, supposons que vous ayez un drink simulé qui renvoie le nom de la boisson qui a été consommée. Vous pouvez écrire :

test('drink retourne La Croix', () => {
const beverage = {name: 'La Croix'};
const drink = jest.fn(beverage => beverage.name);

drink(beverage);

expect(drink).toHaveReturnedWith('La Croix');
});

.toHaveLastReturnedWith(value)

Aussi sous l'alias : .lastReturnedWith(value)

Utilisez .toHaveLastReturnedWith pour tester la valeur spécifique que la dernière fonction simulée a retournée. Si le dernier appel à la fonction simulée a généré une erreur, alors ce comparateur échouera, quelle que soit la valeur que vous avez fournie comme valeur de retour attendue.

Par exemple, supposons que vous ayez un drink simulé qui renvoie le nom de la boisson qui a été consommée. Vous pouvez écrire :

test('drink retourne La Croix (Orange) en dernier', () => {
const beverage1 = {name: 'La Croix (Lemon)'};
const beverage2 = {name: 'La Croix (Orange)'};
const drink = jest.fn(beverage => beverage.name);

drink(beverage1);
drink(beverage2);

expect(drink).toHaveLastReturnedWith('La Croix (Orange)');
});

.toHaveNthReturnedWith(nthCall, value)

Aussi sous l'alias : .nthReturnedWith(nthCall, valeur)

Utilisez .toHaveNthReturnedWith pour tester la valeur spécifique retournée par une fonction simulée pour le nième appel. Si le nième appel à la fonction simulée a lancé une erreur, alors ce résultat échouera quelle que soit la valeur que vous avez fournie comme valeur de retour attendue.

Par exemple, supposons que vous ayez un drink simulé qui renvoie le nom de la boisson qui a été consommée. Vous pouvez écrire :

test('drink retourne les nièmes appels attendus', () => {
const beverage1 = {name: 'La Croix (Lemon)'};
const beverage2 = {name: 'La Croix (Orange)'};
const drink = jest.fn(beverage => beverage.name);

drink(beverage1);
drink(beverage2);

expect(drink).toHaveNthReturnedWith(1, 'La Croix (Lemon)');
expect(drink).toHaveNthReturnedWith(2, 'La Croix (Orange)');
});
remarque

L'argument nth doit être un entier positif à partir de 1.

.toHaveLength(number)

Utilisez .toHaveLength pour vérifier qu'un objet a une propriété .length et il est défini à une certaine valeur numérique.

Ceci est particulièrement utile pour vérifier la taille des tableaux ou des chaînes.

expect([1, 2, 3]).toHaveLength(3);
expect('abc').toHaveLength(3);
expect('').not.toHaveLength(5);

.toHaveProperty(keyPath, value?)

Utilisez .toHaveProperty pour vérifier si la propriété pour la référence fournie keyPath existe pour un objet. Pour vérifier les propriétés profondément imbriquées dans un objet, vous pouvez utiliser la notation du point ou un tableau contenant le keyPath pour les références profondes.

Vous pouvez fournir un argument facultatif value pour comparer la valeur de la propriété reçue (de manière récursive pour toutes les propriétés des instances d'objets, également appelée égalité profonde, comme le comparateur toEqual).

L'exemple suivant contient un objet houseForSale avec des propriétés imbriquées. Nous utilisons toHaveProperty pour vérifier l'existence et les valeurs de diverses propriétés dans l'objet.

// Objet contenant les fonctionnalités de la maison à tester
const houseForSale = {
bath: true,
bedrooms: 4,
kitchen: {
amenities: ['oven', 'stove', 'washer'],
area: 20,
wallColor: 'white',
'nice.oven': true,
},
livingroom: {
amenities: [
{
couch: [
['large', {dimensions: [20, 20]}],
['small', {dimensions: [10, 10]}],
],
},
],
},
'ceiling.height': 2,
};

test('cette maison a mes fonctionnalités désirées', () => {
// Exemple de référencement
expect(houseForSale).toHaveProperty('bath');
expect(houseForSale).toHaveProperty('bedrooms', 4);

expect(houseForSale).not.toHaveProperty('pool');

// Référencement profond à l'aide de la notation par points
expect(houseForSale).toHaveProperty('kitchen.area', 20);
expect(houseForSale).toHaveProperty('kitchen.amenities', [
'oven',
'stove',
'washer',
]);

expect(houseForSale).not.toHaveProperty('kitchen.open');

// Référencement profond en utilisant un tableau contenant le keyPath
expect(houseForSale).toHaveProperty(['kitchen', 'area'], 20);
expect(houseForSale).toHaveProperty(
['kitchen', 'amenities'],
['oven', 'stove', 'washer'],
);
expect(houseForSale).toHaveProperty(['kitchen', 'amenities', 0], 'oven');
expect(houseForSale).toHaveProperty(
'livingroom.amenities[0].couch[0][1].dimensions[0]',
20,
);
expect(houseForSale).toHaveProperty(['kitchen', 'nice.oven']);
expect(houseForSale).not.toHaveProperty(['kitchen', 'open']);

// Referencing keys with dot in the key itself
expect(houseForSale).toHaveProperty(['ceiling.height'], 'tall');
});

.toBeCloseTo(number, numDigits?)

Utilisez toBeCloseTo pour comparer les nombres à virgule flottante pour une égalité approximative.

L'argument optionnel numDigits limite le nombre de chiffres à vérifier après le point décimal. Pour la valeur par défaut 2, le critère de test est Math.abs(expected - received) < 0.005 (c'est-à-dire 10 ** -2 / 2).

Les comparaisons intuitives d'égalité échouent souvent, car l'arithmétique sur les valeurs décimales (base 10) comporte souvent des erreurs d'arrondi dans la représentation binaire avec une précision limitée (base 2). Par exemple, ce test échoue :

test('l\'addition fonctionne sainement avec les décimales', () => {
expect(0.2 + 0.1).toBe(0.3); // échoue !
});

Il échoue car en JavaScript, 0.2 + 0.1 est en fait 0.3000000000004.

Par exemple, ce test passe avec une précision de 5 chiffres :

test('l\'addition fonctionne sainement avec les décimales', () => {
expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
});

Comme les erreurs en virgule flottante sont le problème que toBeCloseTo résout, il ne supporte pas les grandes valeurs entières.

.toBeDefined()

Utilisez .toBeDefined pour vérifier qu'une variable n'est pas undefined. Par exemple, si vous voulez vérifier qu'une fonction fetchNewFlavorIdea() retourne quelque chose, vous pouvez écrire :

test('il y a une nouvelle idée de saveur', () => {
expect(fetchNewFlavorIdea()).toBeDefined();
});

Vous pourriez écrire expect(fetchNewFlavorIdea()).not.toBe(undefined), mais il est préférable d'éviter de faire référence à undefined directement dans votre code.

.toBeFalsy()

Utilisez .toBeFalsy lorsque vous ne vous souciez pas de ce qu'est une valeur et que vous voulez vous assurer qu'une valeur est fausse dans un contexte booléen. Par exemple, disons que vous avez un code d'application qui ressemble à ceci :

drinkSomeLaCroix();
if (!getErrors()) {
drinkMoreLaCroix();
}

Vous pouvez ne pas vous soucier de ce que getErrors renvoie, spécifiquement - il pourrait retourner false, null, ou 0, et votre code fonctionnerait toujours. Donc, si vous voulez tester qu'il n'y a pas d'erreurs après avoir consommé La Croix, vous pouvez écrire :

test('drinking La Croix ne conduit pas à des erreurs', () => {
drinkSomeLaCroix();
expect(getErrors()).toBeFalsy();
});

En JavaScript, il y a six valeurs fausses : false, 0, '', null, undefined et NaN. Tout le reste est vrai.

.toBeGreaterThan(number | bigint)

Utilisez toBeGreaterThan pour comparer reçu > attendu pour des valeurs numériques ou de grands entiers. Par exemple, tester que ouncesPerCan() retourne une valeur de plus de 10 onces :

test('ounces per can est plus grand que 10', () => {
expect(ouncesPerCan()).toBeGreaterThan(10);
});

.toBeGreaterThanOrEqual(number | bigint)

Utilisez toBeGreaterThanOrEqual pour comparer reçu >= attendu pour des valeurs numériques ou de grands entiers. Par exemple, tester que ouncesPerCan() retourne une valeur d'au moins 12 onces :

test('ounces per can est au moins plus grand que 12', () => {
expect(ouncesPerCan()).toBeGreaterThanOrEqual(12);
});

.toBeLessThan(number | bigint)

Utilisez toBeLessThan pour comparer reçu < attendu pour des valeurs numériques ou de grands entiers. Par exemple, tester que ouncesPerCan() retourne une valeur de moins de 20 onces :

test('ounces per can est inférieur à 20', () => {
expect(ouncesPerCan()).toBeLessThan(20);
});

.toBeLessThanOrEqual(number | bigint)

Utilisez toBeLessThanOrEqual pour comparer reçu <= attendu pour des valeurs numériques ou de grands entiers. Par exemple, tester que ouncesPerCan() retourne une valeur d'au plus 12 onces :

test('ounces per can est au plus de 12', () => {
expect(ouncesPerCan()).toBeLessThanOrEqual(12);
});

.toBeInstanceOf(Class)

Utilisez .toBeInstanceOf(Class) pour vérifier qu'un objet est une instance d'une classe. Ce comparateur utilise instanceof en dessous.

class A {}

expect(new A()).toBeInstanceOf(A);
expect(() => {}).toBeInstanceOf(Function);
expect(new A()).toBeInstanceOf(Function); // throws

.toBeNull()

.toBeNull() est identique à .toBe(null) mais les messages d'erreur sont un peu plus jolis. Utilisez donc .toBeNull() lorsque vous voulez vérifier que quelque chose est null.

function bloop() {
return null;
}

test('bloop retourne null', () => {
expect(bloop()).toBeNull();
});

.toBeTruthy()

Utilisez .toBeTruthy lorsque vous ne vous souciez pas de ce qu'est une valeur et que vous voulez vous assurer qu'une valeur est vraie dans un contexte booléen. Par exemple, disons que vous avez un code d'application qui ressemble à ceci :

drinkSomeLaCroix();
if (thirstInfo()) {
drinkMoreLaCroix();
}

Vous pouvez ne pas vous soucier de ce que thirstInfo renvoie, spécifiquement - il pourrait retourner true ou un objet complexe, et votre code fonctionnerait toujours. Ainsi, si vous voulez tester que thirstInfo sera vrai après avoir bu du La Croix, vous pouvez écrire :

test('boire du La Croix conduit à avoir des infos sur la soif', () => {
drinkSomeLaCroix();
expect(thirstInfo()).toBeTruthy();
});

En JavaScript, il y a six valeurs fausses : false, 0, '', null, undefined et NaN. Tout le reste est vrai.

.toBeUndefined()

Utilisez .toBeUndefined pour vérifier qu'une variable est undefined. Par exemple, si vous voulez vérifier qu'une fonction bestDrinkForFlavor(flavor) renvoie undefined pour la saveur 'octopus', car il n'existe pas de bonne boisson aromatisée à l'octopus :

test('la meilleure boisson pour la saveur octopus est undefined', () => {
expect(bestDrinkForFlavor('octopus')).toBeUndefined();
});

Vous pourriez écrire expect(bestDrinkForFlavor('octopus')).toBe(undefined), mais il est préférable d'éviter de faire référence à undefined directement dans votre code.

.toBeNaN()

Utilisez .toBeNaN lorsque vous vérifiez qu'une valeur est NaN.

test('passe lorsque la valeur est NaN', () => {
expect(NaN).toBeNaN();
expect(1).not.toBeNaN();
});

.toContain(item)

Utilisez .toContain lorsque vous voulez vérifier qu'un élément est dans un tableau. Pour tester les éléments du tableau, on utilise ===, un contrôle d'égalité strict. .toContain peut également vérifier si une chaîne de caractères est une sous-chaîne d'une autre chaîne.

Par exemple, si getAllFlavors() retourne un tableau de saveurs et vous voulez être sûr que lime est là, vous pouvez écrire :

test('la liste de saveurs contient lime', () => {
expect(getAllFlavors()).toContain('lime');
});

Ce comparateur accepte également d'autres itérables tels que les chaînes, les sets, les listes de noeuds et les collections HTML.

.toContainEqual(item)

Utilisez .toContainEqual lorsque vous voulez vérifier qu'un élément ayant une structure et des valeurs spécifiques est contenu dans un tableau. Pour tester les éléments du tableau, ce comparateur vérifie récursivement l'égalité de tous les champs, plutôt que de vérifier l'identité des objets.

describe('ma boisson', () => {
test('est délicieuse et non acide', () => {
const myBeverage = {delicious: true, sour: false};
expect(myBeverages()).toContainEqual(myBeverage);
});
});

.toEqual(value)

Utilisez .toEqual pour comparer récursivement toutes les propriétés des instances d'objets (également connu sous le nom d'égalité « profonde »). Il appelle Object.is pour comparer des valeurs primitives, ce qui est encore mieux pour les tests que l'opérateur d'égalité stricte ===.

Par exemple, .toEqual et .toBe se comportent différemment dans cette suite de tests, de sorte que tous les tests passent :

const can1 = {
flavor: 'grapefruit',
ounces: 12,
};
const can2 = {
flavor: 'grapefruit',
ounces: 12,
};

describe('les canettes de La Croix sur mon bureau', () => {
test('ont toutes les mêmes propriétés', () => {
expect(can1).toEqual(can2);
});
test('ne sont pas exactement les mêmes canettes', () => {
expect(can1).not.toBe(can2);
});
});
astuce

toEqual ignore les clés d'objets avec des propriétés undefined, les éléments undefined dans les tableaux, les trous dans les tableaux, ou les incompatibilités de types d'objets. To take these into account use .toStrictEqual instead.

info

.toEqual n'effectuera pas de vérification d'égalité profonde pour deux erreurs. Seule la propriété message d'une erreur est prise en compte pour l'égalité. Il est recommandé d'utiliser le comparateur .toThrow pour les tests d'erreurs.

Si les différences entre les propriétés ne vous aident pas à comprendre pourquoi un test échoue, surtout si le rapport est volumineux, vous pouvez déplacer la comparaison dans la fonction expect. Par exemple, utilisez la méthode equals de la classe Buffer pour vérifier si les buffers contiennent ou non le même contenu :

  • rewrite expect(received).toEqual(expected) as expect(received.equals(expected)).toBe(true)
  • rewrite expect(received).not.toEqual(expected) as expect(received.equals(expected)).toBe(false)

.toMatch(regexp | string)

Utilisez .toMatch pour vérifier qu'une chaîne correspond à une expression régulière.

Par exemple, vous ne savez peut-être pas ce que essayOnTheBestFlavor() renvoie exactement, mais vous savez qu'il s'agit d'une très longue chaîne de caractères et que la sous-chaîne grapefruit devrait s'y trouver quelque part. Vous pouvez tester ceci avec :

describe('un essai sur la meilleure saveur', () => {
test('mentionne grapefruit', () => {
expect(essayOnTheBestFlavor()).toMatch(/grapefruit/);
expect(essayOnTheBestFlavor()).toMatch(new RegExp('grapefruit'));
});
});

Ce comparateur accepte également une chaîne de caractères, qu'il essaiera de faire correspondre :

describe('grapefruits sont sains', () => {
test('grapefruits sont des fruits', () => {
expect('grapefruits').toMatch('fruit');
});
});

.toMatchObject(object)

Utilisez .toMatchObject pour vérifier qu'un objet JavaScript correspond à un sous-ensemble des propriétés d'un objet. Il correspondra aux objets reçus dont les propriétés ne sont pas dans l'objet attendu.

Vous pouvez également passer un tableau d'objets, auquel cas la méthode retournera true uniquement si chaque objet du tableau reçu correspond (au sens toMatchObject décrit ci-dessus) à l'objet correspondant dans le tableau attendu. Ceci est utile si vous voulez vérifier que deux tableaux correspondent dans leur nombre d'éléments, par opposition à arrayContaining, qui autorise des éléments supplémentaires dans le tableau reçu.

Vous pouvez faire correspondre des propriétés à des valeurs ou à des comparateurs.

const houseForSale = {
bath: true,
bedrooms: 4,
kitchen: {
amenities: ['oven', 'stove', 'washer'],
area: 20,
wallColor: 'white',
},
};
const desiredHouse = {
bath: true,
kitchen: {
amenities: ['oven', 'stove', 'washer'],
wallColor: expect.stringMatching(/white|yellow/),
},
};

test('la maison a mes caractéristiques souhaitées', () => {
expect(houseForSale).toMatchObject(desiredHouse);
});
describe('toMatchObject appliqué aux tableaux', () => {
test('le nombre d\'éléments doit correspondre exactement', () => {
expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}, {baz: 1}]);
});

test('.toMatchObject est appelé pour chaque élément, donc les propriétés supplémentaires de l\'objet sont correctes', () => {
expect([{foo: 'bar'}, {baz: 1, extra: 'quux'}]).toMatchObject([
{foo: 'bar'},
{baz: 1},
]);
});
});

.toMatchSnapshot(propertyMatchers?, hint?)

Cela garantit qu'une valeur correspond au snapshot le plus récent. Consultez le guide de test des snapshots pour plus d'informations.

Vous pouvez fournir un argument objet optionnel propertyMatchers, qui a des comparateurs asymétriques comme valeurs d'un sous-ensemble de propriétés attendues, si la valeur reçue est une instance d'objet. C'est comme toMatchObject avec des critères flexibles pour un sous-ensemble de propriétés, suivis d'un test de snapshot comme critère exact pour le reste des propriétés.

Vous pouvez fournir un argument hint facultatif de type string qui sera ajouté au nom du test. Bien que Jest ajoute toujours un numéro à la fin du nom d'un snapshot, de courtes indications descriptives pourraient être plus utiles que des numéros pour différencier plusieurs snapshots dans un seul bloc it ou test. Jest trie les snapshots par nom dans le fichier .snap correspondant.

.toMatchInlineSnapshot(propertyMatchers?, inlineSnapshot)

Assure qu'une valeur correspond au snapshot le plus récent.

Vous pouvez fournir un argument objet optionnel propertyMatchers, qui a des comparateurs asymétriques comme valeurs d'un sous-ensemble de propriétés attendues, si la valeur reçue est une instance d'objet. C'est comme toMatchObject avec des critères flexibles pour un sous-ensemble de propriétés, suivis d'un test de snapshot comme critère exact pour le reste des propriétés.

Jest ajoute l'argument inlineSnapshot au comparateur dans le fichier de test (au lieu d'un fichier .snap externe) lors de la première exécution du test.

Consultez la section sur les snapshots en ligne pour plus d'informations.

.toStrictEqual(value)

Use .toStrictEqual to test that objects have the same structure and type.

Différences avec .toEqual :

  • keys with undefined properties are checked, e.g. {a: undefined, b: 2} will not equal {b: 2};
  • undefined items are taken into account, e.g. [2] will not equal [2, undefined];
  • array sparseness is checked, e.g. [, 1] will not equal [undefined, 1];
  • object types are checked, e.g. a class instance with fields a and b will not equal a literal object with fields a and b.
class LaCroix {
constructor(flavor) {
this.flavor = flavor;
}
}

describe('les canettes La Croix sur mon bureau', () => {
test('ne sont pas sémantiquement les mêmes', () => {
expect(new LaCroix('lemon')).toEqual({flavor: 'lemon'});
expect(new LaCroix('lemon')).not.toStrictEqual({flavor: 'lemon'});
});
});

.toThrow(error?)

Aussi sous l'alias : .toThrowError(error?)

Utilisez .toThrow pour tester qu'une fonction lève une exception lorsqu'elle est appelée. Par exemple, si nous voulons tester que drinkFlavor('octopus') lève une exception, parce que la saveur de octopus est trop dégoûtante à boire, nous pourrions écrire :

test('throws sur octopus', () => {
expect(() => {
drinkFlavor('octopus');
}).toThrow();
});
astuce

Vous devez envelopper le code dans une fonction, sinon l'erreur ne sera pas détectée et l'assertion échouera.

Vous pouvez fournir un argument facultatif pour vérifier qu'une erreur spécifique est déclenchée :

  • regular expression: error message matches the pattern
  • string: error message includes the substring
  • error object: error message is equal to the message property of the object
  • error class: error object is instance of class

Par exemple, supposons que le drinkFlavor est codé comme suit :

function drinkFlavor(flavor) {
if (flavor == 'octopus') {
throw new DisgustingFlavorError('beurk, goût octopus');
}
// Faire d'autres choses
}

Nous pourrions tester cette erreur de plusieurs façons :

test('throws on octopus', () => {
function drinkOctopus() {
drinkFlavor('octopus');
}

// Test that the error message says "yuck" somewhere: these are equivalent
expect(drinkOctopus).toThrow(/yuck/);
expect(drinkOctopus).toThrow('yuck');

// Test the exact error message
expect(drinkOctopus).toThrow(/^yuck, octopus flavor$/);
expect(drinkOctopus).toThrow(new Error('yuck, octopus flavor'));

// Test that we get a DisgustingFlavorError
expect(drinkOctopus).toThrow(DisgustingFlavorError);
});

.toThrowErrorMatchingSnapshot(hint?)

Utilisez .toThrowErrorMatchingSnapshot pour tester qu'une fonction lance une erreur correspondant au snapshot le plus récent lorsqu'il est appelé.

Vous pouvez fournir un argument hint facultatif de type string qui sera ajouté au nom du test. Bien que Jest ajoute toujours un numéro à la fin du nom d'un snapshot, de courtes indications descriptives pourraient être plus utiles que des numéros pour différencier plusieurs snapshots dans un seul bloc it ou test. Jest trie les snapshots par nom dans le fichier .snap correspondant.

Par exemple, supposons que vous avez une fonction drinkFlavor qui lève une exception chaque fois que la saveur est 'octopus', et qui est codée comme ceci :

function drinkFlavor(flavor) {
if (flavor == 'octopus') {
throw new DisgustingFlavorError('beurk, goût octopus');
}
// Faire d'autres choses
}

Le test pour cette fonction se présentera de la manière suivante :

test('throws on octopus', () => {
function drinkOctopus() {
drinkFlavor('octopus');
}

expect(drinkOctopus).toThrowErrorMatchingSnapshot();
});

Et cela va générer le snapshot suivant :

exports[`drinking flavors throws on octopus 1`] = `"beurk, goût octopus"`;

Consultez Test de snapshot de l'arborescence React pour plus d'informations sur les tests de snapshots.

.toThrowErrorMatchingInlineSnapshot(inlineSnapshot)

Utilisez .toThrowErrorMatchingInlineSnapshot pour tester qu'une fonction lève une erreur correspondant au snapshot le plus récent lorsqu'elle est appelée.

Jest ajoute l'argument inlineSnapshot au comparateur dans le fichier de test (au lieu d'un fichier .snap externe) lors de la première exécution du test.

Consultez la section sur les snapshots en ligne pour plus d'informations.

Asymmetric Matchers

expect.anything()

expect.anything() correspond à tout sauf à null ou undefined. You can use it inside toEqual or toHaveBeenCalledWith instead of a literal value. Par exemple, si vous voulez vérifier qu'une fonction simulée est appelée avec un argument non null :

test('map calls its argument with a non-null argument', () => {
const mock = jest.fn();
[1].map(x => mock(x));
expect(mock).toHaveBeenCalledWith(expect.anything());
});

expect.any(constructor)

expect.any(constructor) correspond à tout ce qui a été créé avec le constructeur donné ou si c'est une primitive qui est du type transmis. You can use it inside toEqual or toHaveBeenCalledWith instead of a literal value. Par exemple, si vous voulez vérifier qu'une fonction simulée est appelée avec un nombre :

class Cat {}
function getCat(fn) {
return fn(new Cat());
}

test('randocall calls its callback with a class instance', () => {
const mock = jest.fn();
getCat(mock);
expect(mock).toHaveBeenCalledWith(expect.any(Cat));
});

function randocall(fn) {
return fn(Math.floor(Math.random() * 6 + 1));
}

test('randocall calls its callback with a number', () => {
const mock = jest.fn();
randocall(mock);
expect(mock).toHaveBeenCalledWith(expect.any(Number));
});

expect.arrayContaining(array)

expect.arrayContaining(array) correspond à un tableau reçu qui contient tous les éléments du tableau attendu. C'est-à-dire que le tableau attendu est un sous-ensemble du tableau reçu. Par conséquent, il correspond à un tableau reçu qui contient des éléments qui ne sont pas dans le tableau attendu.

Vous pouvez l'utiliser à la place d'une valeur littérale :

  • in toEqual or toHaveBeenCalledWith
  • to match a property in objectContaining or toMatchObject
describe('arrayContaining', () => {
const expected = ['Alice', 'Bob'];
it('correspond même si celui reçu contient des éléments supplémentaires', () => {
expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
});
it('ne correspond pas si celui reçu ne contient pas les éléments attendus', () => {
expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(expected));
});
});
describe('Méfiez-vous d\'un malentendu ! Une séquence de lancers de dés', () => {
const expected = [1, 2, 3, 4, 5, 6];
it('correspond même avec un nombre inattendu, le 7', () => {
expect([4, 1, 6, 7, 3, 5, 2, 5, 4, 6]).toEqual(
expect.arrayContaining(expected),
);
});
it('ne correspond pas sans un nombre attendu, le 2', () => {
expect([4, 1, 6, 7, 3, 5, 7, 5, 4, 6]).not.toEqual(
expect.arrayContaining(expected),
);
});
});

expect.not.arrayContaining(array)

expect.not.arrayContaining(array) correspond à un tableau reçu qui ne contient pas tous les éléments du tableau attendu. C'est-à-dire que le tableau attendu n'est pas un sous-ensemble du tableau reçu.

C'est l'inverse de expect.arrayContaining.

describe('not.arrayContaining', () => {
const expected = ['Samantha'];

it('correspond si le tableau actuel ne contient pas les éléments attendus', () => {
expect(['Alice', 'Bob', 'Eve']).toEqual(
expect.not.arrayContaining(expected),
);
});
});

expect.closeTo(number, numDigits?)

expect.closeTo(number, numDigits?) est utile lors de la comparaison de nombres à virgule flottante dans les propriétés de l'objet ou d'élément de tableau. Si vous avez besoin de comparer un nombre, veuillez utiliser .toBeCloseTo à la place.

L'argument optionnel numDigits limite le nombre de chiffres à vérifier après le point décimal. Pour la valeur par défaut 2, le critère de test est Math.abs(expected - received) < 0.005 (that is, 10 ** -2 / 2).

Par exemple, ce test passe avec une précision de 5 chiffres :

test('compare un nombre décimal dans les propriétés de l\'objet', () => {
expect({
title: '0.1 + 0.2',
sum: 0.1 + 0.2,
}).toEqual({
title: '0.1 + 0.2',
sum: expect.closeTo(0.3, 5),
});
});

expect.objectContaining(object)

expect.objectContaining(object) correspond à tout objet reçu qui correspond récursivement aux propriétés attendues. C'est-à-dire que l'objet attendu est un sous-ensemble de l'objet reçu. Par conséquent, il correspond à un objet reçu qui contient des propriétés qui sont présentes dans l'objet attendu.

Au lieu de valeurs de propriétés littérales dans l'objet attendu, vous pouvez utiliser des comparateurs, expect.anything(), et ainsi de suite.

Par exemple, disons que nous nous attendons à ce qu'une fonction onPress soit appelée avec un objet Event, et tout ce que nous devons vérifier est que l'événement a les propriétés event.x et event.y. Nous pouvons le tester ainsi :

test('onPress gets called with the right thing', () => {
const onPress = jest.fn();
simulatePresses(onPress);
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({
x: expect.any(Number),
y: expect.any(Number),
}),
);
});

expect.not.objectContaining(object)

expect.not.objectContaining(object) correspond à tout objet reçu qui ne correspond pas récursivement aux propriétés attendues. C'est-à-dire que l'objet attendu n'est pas un sous-ensemble de l'objet reçu. Par conséquent, il correspond à un objet reçu qui contient des propriétés qui ne sont pas dans l'objet attendu.

C'est l'inverse de expect.objectContaining.

describe('not.objectContaining', () => {
const expected = {foo: 'bar'};

it('correspond si l\'objet réel ne contient pas les paires clé-valeur attendues', () => {
expect({bar: 'baz'}).toEqual(expect.not.objectContaining(expected));
});
});

expect.stringContaining(string)

expect.stringContaining(string) correspond à la valeur reçue si c'est une chaîne qui contient exactement la chaîne attendue.

expect.not.stringContaining(string)

expect.not.stringContaining(string) correspond à la valeur reçue si ce n'est pas une chaîne ou si c'est une chaîne qui ne contient pas la chaîne exacte attendue.

C'est l'inverse de expect.stringContaining.

describe('not.stringContaining', () => {
const expected = 'Hello world!';

it('correspond si la valeur reçue ne contient pas la sous-chaîne attendue', () => {
expect('How are you?').toEqual(expect.not.stringContaining(expected));
});
});

expect.stringMatching(string | regexp)

expect.stringMatching(string | regexp) correspond à la valeur reçue si c'est une chaîne qui correspond à la chaîne attendue ou à l'expression régulière.

Vous pouvez l'utiliser à la place d'une valeur littérale :

  • in toEqual or toHaveBeenCalledWith
  • to match an element in arrayContaining
  • to match a property in objectContaining or toMatchObject

Cet exemple montre également comment vous pouvez imbriquer plusieurs comparateurs asymétriques, avec expect.stringMatching à l'intérieur du expect.arrayContaining.

describe('stringMatching in arrayContaining', () => {
const expected = [
expect.stringMatching(/^Alic/),
expect.stringMatching(/^[BR]ob/),
];
it('correspond même si celle reçue contient des éléments supplémentaires', () => {
expect(['Alicia', 'Roberto', 'Evelina']).toEqual(
expect.arrayContaining(expected),
);
});
it('ne correspond pas si celle reçue ne contient pas les éléments attendus', () => {
expect(['Roberto', 'Evelina']).not.toEqual(
expect.arrayContaining(expected),
);
});
});

expect.not.stringMatching(string | regexp)

expect.not.stringMatching(string | regexp) correspond à la valeur reçue si ce n'est pas une chaîne ou si c'est une chaîne qui ne correspond pas à la chaîne ou à l'expression régulière attendue.

C'est l'inverse de expect.stringMatching.

describe('not.stringMatching', () => {
const expected = /Hello world!/;

it('correspond si la valeur reçue ne correspond pas à la regex attendue', () => {
expect('How are you?').toEqual(expect.not.stringMatching(expected));
});
});

Assertion Count

expect.assertions(number)

expect.assertions(number) vérifie qu'un certain nombre d'assertions sont appelées lors d'un test. Ceci est souvent utile lors des tests de code asynchrone, afin de s'assurer que les assertions dans un callback ont été effectivement appelées.

Par exemple, supposons que nous ayons une fonction doAsync qui reçoit deux callbacks callback1 et callback2, elle va les appeler de manière asynchrone dans un ordre inconnu. Nous pouvons le tester ainsi :

test('doAsync appelle les deux callbacks', () => {
expect.assertions(2);
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}

doAsync(callback1, callback2);
});

L'appel expect.assertions(2) garantit que les deux callbacks sont effectivement appelés.

expect.hasAssertions()

expect.hasAssertions() vérifie qu'au moins une assertion est appelée lors d'un test. Ceci est souvent utile lors des tests de code asynchrone, afin de s'assurer que les assertions dans un callback ont été effectivement appelées.

Par exemple, disons que nous avons quelques fonctions qui traitent toutes de l'état. prepareState appelle une callback avec un objet d'état, validateState s'exécute sur cet objet d'état, et waitOnState renvoie une promesse qui attend que toutes les callbacks de prepareState se terminent. Nous pouvons le tester ainsi :

test('prepareState prépare un état valide', () => {
expect.hasAssertions();
prepareState(state => {
expect(validateState(state)).toBeTruthy();
});
return waitOnState();
});

L'appel expect.hasAssertions() garantit que la callback prepareState est effectivement appelée.

Extend Utilities

expect.addEqualityTesters(testers)

You can use expect.addEqualityTesters to add your own methods to test if two objects are equal. For example, let's say you have a class in your code that represents volume and can determine if two volumes using different units are equal. You may want toEqual (and other equality matchers) to use this custom equality method when comparing to Volume classes. You can add a custom equality tester to have toEqual detect and apply custom logic when comparing Volume classes:

Volume.js
// For simplicity in this example, we'll just support the units 'L' and 'mL'
export class Volume {
constructor(amount, unit) {
this.amount = amount;
this.unit = unit;
}

toString() {
return `[Volume ${this.amount}${this.unit}]`;
}

equals(other) {
if (this.unit === other.unit) {
return this.amount === other.amount;
} else if (this.unit === 'L' && other.unit === 'mL') {
return this.amount * 1000 === other.unit;
} else {
return this.amount === other.unit * 1000;
}
}
}
areVolumesEqual.js
import {expect} from '@jest/globals';
import {Volume} from './Volume.js';

function areVolumesEqual(a, b) {
const isAVolume = a instanceof Volume;
const isBVolume = b instanceof Volume;

if (isAVolume && isBVolume) {
return a.equals(b);
} else if (isAVolume === isBVolume) {
return undefined;
} else {
return false;
}
}

expect.addEqualityTesters([areVolumesEqual]);
__tests__/Volume.test.js
import {expect, test} from '@jest/globals';
import {Volume} from '../Volume.js';
import '../areVolumesEqual.js';

test('are equal with different units', () => {
expect(new Volume(1, 'L')).toEqual(new Volume(1000, 'mL'));
});

Custom equality testers API

Custom testers are functions that return either the result (true or false) of comparing the equality of the two given arguments or undefined if the tester does not handle the given objects and wants to delegate equality to other testers (for example, the builtin equality testers).

Custom testers are called with 3 arguments: the two objects to compare and the array of custom testers (used for recursive testers, see the section below).

These helper functions and properties can be found on this inside a custom tester:

this.equals(a, b, customTesters?)

Il s'agit d'une fonction d'égalité profonde qui retournera true si deux objets ont les mêmes valeurs (de manière récursive). It optionally takes a list of custom equality testers to apply to the deep equality checks. If you use this function, pass through the custom testers your tester is given so further equality checks equals applies can also use custom testers the test author may have configured. See the example in the Recursive custom equality testers section for more details.

Matchers vs Testers

Matchers are methods available on expect, for example expect().toEqual(). toEqual is a matcher. A tester is a method used by matchers that do equality checks to determine if objects are the same.

Custom matchers are good to use when you want to provide a custom assertion that test authors can use in their tests. For example, the toBeWithinRange example in the expect.extend section is a good example of a custom matcher. Sometimes a test author may want to assert two numbers are exactly equal and should use toBe. Other times, however, a test author may want to allow for some flexibility in their test, and toBeWithinRange may be a more appropriate assertion.

Custom equality testers are good for globally extending Jest matchers to apply custom equality logic for all equality comparisons. Test authors can't turn on custom testers for certain assertions and turn them off for others (a custom matcher should be used instead if that behavior is desired). For example, defining how to check if two Volume objects are equal for all matchers would be a good custom equality tester.

Recursive custom equality testers

If your custom equality testers are testing objects with properties you'd like to do deep equality with, you should use the this.equals helper available to equality testers. This equals method is the same deep equals method Jest uses internally for all of its deep equality comparisons. It's the method that invokes your custom equality tester. It accepts an array of custom equality testers as a third argument. Custom equality testers are also given an array of custom testers as their third argument. Pass this argument into the third argument of equals so that any further equality checks deeper into your object can also take advantage of custom equality testers.

For example, let's say you have a Book class that contains an array of Author classes and both of these classes have custom testers. The Book custom tester would want to do a deep equality check on the array of Authors and pass in the custom testers given to it, so the Authors custom equality tester is applied:

customEqualityTesters.js
function areAuthorEqual(a, b) {
const isAAuthor = a instanceof Author;
const isBAuthor = b instanceof Author;

if (isAAuthor && isBAuthor) {
// Authors are equal if they have the same name
return a.name === b.name;
} else if (isAAuthor === isBAuthor) {
return undefined;
} else {
return false;
}
}

function areBooksEqual(a, b, customTesters) {
const isABook = a instanceof Book;
const isBBook = b instanceof Book;

if (isABook && isBBook) {
// Books are the same if they have the same name and author array. We need
// to pass customTesters to equals here so the Author custom tester will be
// used when comparing Authors
return (
a.name === b.name && this.equals(a.authors, b.authors, customTesters)
);
} else if (isABook === isBBook) {
return undefined;
} else {
return false;
}
}

expect.addEqualityTesters([areAuthorsEqual, areBooksEqual]);
remarque

Remember to define your equality testers as regular functions and not arrow functions in order to access the tester context helpers (e.g. this.equals).

expect.addSnapshotSerializer(serializer)

Vous pouvez appeler expect.addSnapshotSerializer pour ajouter un module qui formate les structures de données spécifiques à l'application.

Pour un fichier de test individuel, un module ajouté précède tous les modules de la configuration snapshotSerializers, qui précèdent les sérialiseurs snapshot par défaut pour les types JavaScript intégrés et pour les éléments React. Le dernier module ajouté est le premier module testé.

import serializer from 'my-serializer-module';
expect.addSnapshotSerializer(serializer);

// affecte les assertions expect(value).toMatchSnapshot() dans le fichier de test

Si vous ajoutez un sérialiseur de snapshot dans des fichiers de test individuels au lieu de l'ajouter à la configuration snapshotSerializers :

  • You make the dependency explicit instead of implicit.
  • You avoid limits to configuration that might cause you to eject from create-react-app.

Consultez la configuration de Jest pour plus d'informations.

expect.extend(matchers)

Vous pouvez utiliser expect.extend pour ajouter vos propres comparateurs à Jest. Par exemple, supposons que vous testiez une bibliothèque d'utilitaires de nombres et que vous vérifiiez fréquemment que les nombres apparaissent dans des plages particulières de nombres. Vous pourriez résumer cela en un comparateur toBeWithinRange :

toBeWithinRange.js
import {expect} from '@jest/globals';

function toBeWithinRange(actual, floor, ceiling) {
if (
typeof actual !== 'number' ||
typeof floor !== 'number' ||
typeof ceiling !== 'number'
) {
throw new TypeError('These must be of type number!');
}

const pass = actual >= floor && actual <= ceiling;
if (pass) {
return {
message: () =>
`expected ${this.utils.printReceived(
actual,
)} not to be within range ${this.utils.printExpected(
`${floor} - ${ceiling}`,
)}`,
pass: true,
};
} else {
return {
message: () =>
`expected ${this.utils.printReceived(
actual,
)} to be within range ${this.utils.printExpected(
`${floor} - ${ceiling}`,
)}`,
pass: false,
};
}
}

expect.extend({
toBeWithinRange,
});
__tests__/ranges.test.js
import {expect, test} from '@jest/globals';
import '../toBeWithinRange';

test('is within range', () => expect(100).toBeWithinRange(90, 110));

test('is NOT within range', () => expect(101).not.toBeWithinRange(0, 100));

test('asymmetric ranges', () => {
expect({apples: 6, bananas: 3}).toEqual({
apples: expect.toBeWithinRange(1, 10),
bananas: expect.not.toBeWithinRange(11, 20),
});
});
toBeWithinRange.d.ts
// optionally add a type declaration, e.g. it enables autocompletion in IDEs
declare module 'expect' {
interface AsymmetricMatchers {
toBeWithinRange(floor: number, ceiling: number): void;
}
interface Matchers<R> {
toBeWithinRange(floor: number, ceiling: number): R;
}
}

export {};
astuce

The type declaration of the matcher can live in a .d.ts file or in an imported .ts module (see JS and TS examples above respectively). If you keep the declaration in a .d.ts file, make sure that it is included in the program and that it is a valid module, i.e. it has at least an empty export {}.

astuce

Instead of importing toBeWithinRange module to the test file, you can enable the matcher for all tests by moving the expect.extend call to a setupFilesAfterEnv script:

import {expect} from '@jest/globals';
// remember to export `toBeWithinRange` as well
import {toBeWithinRange} from './toBeWithinRange';

expect.extend({
toBeWithinRange,
});

Async Matchers

expect.extend prend également en charge lescomparateurs asynchrones. Les comparateurs asynchrones renvoient une promesse. Vous devrez donc attendre la valeur renvoyée. Utilisons un exemple de comparateur pour illustrer leur utilisation. Nous allons implémenter un comparateur appelé toBeDivisibleByExternalValue, où le nombre divisible va être obtenu à partir d'une source externe.

expect.extend({
async toBeDivisibleByExternalValue(received) {
const externalValue = await getExternalValueFromRemoteSource();
const pass = received % externalValue == 0;
if (pass) {
return {
message: () =>
`s'attend à ce que ${received} ne soit pas divisible par ${externalValue}`,
pass: true,
};
} else {
return {
message: () =>
`s'attend à ce que ${received} soit divisible par ${externalValue}`,
pass: false,
};
}
},
});

test('est divisible par une valeur externe', async () => {
await expect(100).toBeDivisibleByExternalValue();
await expect(101).not.toBeDivisibleByExternalValue();
});

Custom Matchers API

Les comparateurs doivent retourner un objet (ou une promesse d'un objet) avec deux clés. pass indique s'il y a eu ou non une correspondance, et message fournit une fonction sans arguments qui retourne un message d'erreur en cas d'échec. Ainsi, lorsque pass est faux, message devrait retourner le message d'erreur lorsque expect(x).yourMatcher() échoue. Et lorsque pass est vrai, message devrait retourner le message d'erreur lorsque expect(x).not.yourMatcher() échoue.

Les comparateurs sont appelés avec l'argument passé à expect(x) suivi des arguments passés à .yourMatcher(y, z) :

expect.extend({
yourMatcher(x, y, z) {
return {
pass: true,
message: () => '',
};
},
});

Ces fonctions d'aide et propriétés peuvent être trouvées sur this à l'intérieur d'un comparateur personnalisé :

this.isNot

Un booléen pour vous indiquer que ce comparateur a été appelé avec le modificateur de négation .not, ce qui vous permet d'afficher une indication claire et correcte du comparateur (voir l'exemple de code).

this.promise

Une chaîne permettant d'afficher un indice de concordance clair et correct :

  • 'rejects' if matcher was called with the promise .rejects modifier
  • 'resolves' if matcher was called with the promise .resolves modifier
  • '' if matcher was not called with a promise modifier

this.equals(a, b, customTesters?)

Il s'agit d'une fonction d'égalité profonde qui retournera true si deux objets ont les mêmes valeurs (de manière récursive). It optionally takes a list of custom equality testers to apply to the deep equality checks (see this.customTesters below).

this.expand

Un booléen pour vous indiquer que ce comparateur a été appelé avec une option expand. Quand Jest est appelé avec le flag --expand , this.expand peut être utilisé pour déterminer si Jest est censé afficher des différences et des erreurs complètes.

this.utils

There are a number of helpful tools exposed on this.utils primarily consisting of the exports from jest-matcher-utils.

Les plus utiles sont matcherHint, printExpected et printReceived pour formater joliment les messages d'erreur. Par exemple, jetez un œil à l'implémentation pour le comparateur toBe :

const {diff} = require('jest-diff');
expect.extend({
toBe(received, expected) {
const options = {
comment: 'Object.is equality',
isNot: this.isNot,
promise: this.promise,
};

const pass = Object.is(received, expected);

const message = pass
? () =>
// eslint-disable-next-line prefer-template
this.utils.matcherHint('toBe', undefined, undefined, options) +
'\n\n' +
`Expected: not ${this.utils.printExpected(expected)}\n` +
`Received: ${this.utils.printReceived(received)}`
: () => {
const diffString = diff(expected, received, {
expand: this.expand,
});
return (
// eslint-disable-next-line prefer-template
this.utils.matcherHint('toBe', undefined, undefined, options) +
'\n\n' +
(diffString && diffString.includes('- Expect')
? `Difference:\n\n${diffString}`
: `Expected: ${this.utils.printExpected(expected)}\n` +
`Received: ${this.utils.printReceived(received)}`)
);
};

return {actual: received, message, pass};
},
});

Cela affichera quelque chose comme ceci :

  expect(received).toBe(expected)

Expected value to be (using Object.is):
"banana"
Received:
"apple"

Lorsqu'une assertion échoue, le message d'erreur doit donner autant de détails que nécessaire à l'utilisateur pour qu'il puisse résoudre son problème rapidement. Vous devez élaborer un message d'échec précis pour vous assurer que les utilisateurs de vos assertions personnalisées ont une bonne expérience de développeur.

this.customTesters

If your matcher does a deep equality check using this.equals, you may want to pass user-provided custom testers to this.equals. The custom equality testers the user has provided using the addEqualityTesters API are available on this property. The built-in Jest matchers pass this.customTesters (along with other built-in testers) to this.equals to do deep equality, and your custom matchers may want to do the same.

Custom snapshot matchers

Pour utiliser les tests de snapshot à l'intérieur de votre comparateur personnalisé, vous pouvez importer jest-snapshot et l'utiliser depuis votre comparateur.

Voici un comparateur de snapshot qui découpe une chaîne de caractères à stocker pour une longueur donnée, .toMatchTrimmedSnapshot(length) :

const {toMatchSnapshot} = require('jest-snapshot');

expect.extend({
toMatchTrimmedSnapshot(received, length) {
return toMatchSnapshot.call(
this,
received.slice(0, length),
'toMatchTrimmedSnapshot',
);
},
});

it('stores only 10 characters', () => {
expect('extra long string oh my gerd').toMatchTrimmedSnapshot(10);
});

/*
Stored snapshot will look like:

exports[`stores only 10 characters: toMatchTrimmedSnapshot 1`] = `"extra long"`;
*/

Il est également possible de créer des comparateurs personnalisés pour les snapshots en ligne, les snapshots seront correctement ajoutés aux comparateurs personnalisés. Cependant, le snapshot en ligne essaiera toujours d'ajouter au premier argument ou au second lorsque le premier argument est le comparateur de propriétés, il n'est donc pas possible d'accepter des arguments personnalisés dans les comparateurs personnalisés.

const {toMatchInlineSnapshot} = require('jest-snapshot');

expect.extend({
toMatchTrimmedInlineSnapshot(received, ...rest) {
return toMatchInlineSnapshot.call(this, received.slice(0, 10), ...rest);
},
});

it('stores only 10 characters', () => {
expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot();
/*
The snapshot will be added inline like
expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot(
`"extra long"`
);
*/
});

async

Si votre comparateur de snapshots en ligne personnalisé est asynchrone, c'est-à-dire qu'il utilise async-await, vous pouvez rencontrer une erreur du type "Multiple inline snapshots for the same call are not supported". Jest a besoin d'informations contextuelles supplémentaires pour trouver où le comparateur de snapshot en ligne personnalisé a été utilisé pour mettre à jour les snapshots correctement.

const {toMatchInlineSnapshot} = require('jest-snapshot');

expect.extend({
async toMatchObservationInlineSnapshot(fn, ...rest) {
// L'erreur (et sa stacktrace) doit être créée avant tout `await`.
this.error = new Error();

// L'implémentation de `observe` n'a pas d'importance.
// Il importe seulement que le comparateur de snapshots personnalisé soit asynchrone.
const observation = await observe(async () => {
await fn();
});

return toMatchInlineSnapshot.call(this, recording, ...rest);
},
});

it('observe quelque chose', async () => {
await expect(async () => {
return 'async action';
}).toMatchTrimmedInlineSnapshot();
/*
Le snapshot sera ajouté en ligne comme suit
await expect(async () => {
return 'async action';
}).toMatchTrimmedInlineSnapshot(`"async action"`);
*/
});

Bail out

Habituellement, jest essaie de faire correspondre chaque snapshot qui est attendu dans un test.

Parfois, il peut être inutile de poursuivre le test si un snapshot précédent a échoué. Par exemple, lorsque vous faites des snapshots d'un état-machine après diverses transitions, vous pouvez interrompre le test dès qu'une transition produit un état erroné.

Dans ce cas, vous pouvez mettre en place un comparateur de snapshots personnalisé qui se déclenche à la première incohérence au lieu de collecter toutes les incohérences.

const {toMatchInlineSnapshot} = require('jest-snapshot');

expect.extend({
toMatchStateInlineSnapshot(...args) {
this.dontThrow = () => {};

return toMatchInlineSnapshot.call(this, ...args);
},
});

let state = 'initial';

function transition() {
// Une erreur dans l'implémentation devrait faire échouer le test.
if (state === 'INITIAL') {
state = 'pending';
} else if (state === 'pending') {
state = 'done';
}
}

it('transitions comme prévu', () => {
expect(state).toMatchStateInlineSnapshot(`"initial"`);

transition();
// Cela produit déjà un dysfonctionnement. Il est inutile de poursuivre le test.
expect(state).toMatchStateInlineSnapshot(`"loading"`);

transition();
expect(state).toMatchStateInlineSnapshot(`"done"`);
});