expect
Les types suivants sont utilisés dans les signatures de type suivantes :
type Awaitable<T> = T | PromiseLike<T>;
expect
est utilisé pour créer des assertions. Dans ce contexte, les assertions
sont des fonctions qui peuvent être appelées pour vérifier une condition. Vitest fournit les assertions chai
par défaut ainsi que des assertions compatibles Jest
construites sur chai
.
Par exemple, le code suivant vérifie qu'une valeur input
est égale à 2
. Si ce n'est pas le cas, l'assertion lèvera une erreur et le test échouera.
import { expect } from 'vitest';
const input = Math.sqrt(4);
expect(input).to.equal(2); // API chai
expect(input).toBe(2); // API jest
Techniquement, cet exemple n'utilise pas la fonction test
. Par conséquent, dans la console, vous verrez une erreur Node.js au lieu de la sortie Vitest. Pour en savoir plus sur test
, veuillez consulter la Référence de l'API Test.
De plus, expect
peut être utilisé statiquement pour accéder aux fonctions de correspondance (matchers), décrites plus loin, et à d'autres fonctionnalités.
WARNING
expect
n'a aucun effet sur les types de test, si l'expression ne présente pas d'erreur de type. Si vous voulez utiliser Vitest comme vérificateur de type, utilisez expectTypeOf
ou assertType
.
soft
- Type :
ExpectStatic & (actual: any) => Assertions
expect.soft
fonctionne de manière similaire à expect
, mais au lieu d'interrompre l'exécution du test lorsqu'une assertion échoue, il continue son exécution et considère l'échec comme un échec du test. Toutes les erreurs rencontrées pendant le test seront affichées à la fin de l'exécution.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // Considère le test comme échoué et continue
expect.soft(1 + 2).toBe(4); // Considère le test comme échoué et continue
});
// À la fin du test, les erreurs ci-dessus seront affichées.
Il peut également être utilisé avec expect
. Si une assertion expect
échoue, le test sera interrompu et toutes les erreurs seront affichées.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // Considère le test comme échoué et continue
expect(1 + 2).toBe(3); // Échoue et interrompt le test, toutes les erreurs précédentes seront affichées
expect.soft(1 + 2).toBe(4); // Ne s'exécute pas
});
WARNING
expect.soft
ne peut être utilisé qu'à l'intérieur de la fonction test
.
not
L'utilisation de not
inverse l'assertion. Par exemple, le code suivant vérifie qu'une valeur input
n'est pas égale à 2
. Si elle est égale, l'assertion lèvera une erreur et le test échouera.
import { expect, test } from 'vitest';
const input = Math.sqrt(16);
expect(input).not.to.equal(2); // API chai
expect(input).not.toBe(2); // API jest
toBe
Type :
(value: any) => Awaitable<void>
toBe
peut être utilisé pour vérifier si des primitives sont égales ou si des objets partagent la même référence. Cela équivaut à appelerexpect(Object.is(3, 3)).toBe(true)
. Si les objets ne sont pas les mêmes, mais que vous voulez vérifier si leurs structures sont identiques, vous pouvez utilisertoEqual
.Par exemple, le code ci-dessous vérifie si le commerçant a 13 pommes.
tsimport { expect, test } from 'vitest'; const stock = { type: 'apples', count: 13, }; test('stock has 13 apples', () => { expect(stock.type).toBe('apples'); expect(stock.count).toBe(13); }); test('stocks are the same', () => { const refStock = stock; // même référence expect(stock).toBe(refStock); });
Il est déconseillé d'utiliser
toBe
avec des nombres à virgule flottante. Puisque JavaScript les arrondit,0.1 + 0.2
n'est pas strictement égal à0.3
. Pour vérifier de manière fiable les nombres à virgule flottante, utilisez l'assertiontoBeCloseTo
.
toBeCloseTo
Type :
(value: number, numDigits?: number) => Awaitable<void>
Utilisez
toBeCloseTo
pour comparer les nombres à virgule flottante. L'argument optionnelnumDigits
limite le nombre de chiffres à vérifier après la virgule. Par exemple :tsimport { expect, test } from 'vitest'; test.fails('decimals are not equal in javascript', () => { expect(0.2 + 0.1).toBe(0.3); // 0.2 + 0.1 est 0.30000000000000004 }); test('decimals are rounded to 5 after the point', () => { // Les décimales sont arrondies à 5 chiffres après la virgule // 0.2 + 0.1 est 0.30000 | "000000000004" supprimé expect(0.2 + 0.1).toBeCloseTo(0.3, 5); // Rien de 0.30000000000000004 n'est supprimé expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50); });
toBeDefined
Type :
() => Awaitable<void>
toBeDefined
vérifie que la valeur n'est pas égale àundefined
. Un cas d'utilisation pertinent serait de vérifier si la fonction a retourné quelque chose.tsimport { expect, test } from 'vitest'; function getApples() { return 3; } test('function returned something', () => { expect(getApples()).toBeDefined(); });
toBeUndefined
Type :
() => Awaitable<void>
À l'inverse de
toBeDefined
,toBeUndefined
vérifie que la valeur est égale àundefined
. Un cas d'utilisation pertinent serait de vérifier si la fonction n'a pas retourné quelque chose.tsimport { expect, test } from 'vitest'; function getApplesFromStock(stock) { if (stock === 'Bill') return 13; } test("mary doesn't have a stock", () => { expect(getApplesFromStock('Mary')).toBeUndefined(); });
toBeTruthy
Type :
() => Awaitable<void>
toBeTruthy
vérifie que la valeur est considérée comme vraie lorsqu'elle est convertie en booléen. Utile si la valeur vous importe peu, mais que vous voulez simplement savoir qu'elle peut être convertie entrue
.Par exemple, avec ce code, la valeur de retour de
stocks.getInfo
vous importe peu - il peut s'agir d'un objet complexe, d'une chaîne ou de toute autre chose. Le code fonctionnera toujours.tsimport { Stocks } from './stocks.js'; const stocks = new Stocks(); stocks.sync('Bill'); if (stocks.getInfo('Bill')) stocks.sell('apples', 'Bill');
Donc, si vous voulez tester que
stocks.getInfo
sera truthy, vous pouvez écrire :tsimport { expect, test } from 'vitest'; import { Stocks } from './stocks.js'; const stocks = new Stocks(); test('if we know Bill stock, sell apples to him', () => { stocks.sync('Bill'); expect(stocks.getInfo('Bill')).toBeTruthy(); });
En JavaScript, toutes les valeurs sont considérées comme vraies, sauf
false
,0
,''
,null
,undefined
etNaN
.
toBeFalsy
Type :
() => Awaitable<void>
toBeFalsy
vérifie que la valeur est considérée comme fausse lorsqu'elle est convertie en booléen. Utile si la valeur vous importe peu, mais que vous voulez simplement savoir si elle peut être convertie enfalse
.Par exemple, avec ce code, la valeur de retour de
stocks.stockFailed
vous importe peu - il peut renvoyer n'importe quelle valeur falsy, mais le code fonctionnera toujours.tsimport { Stocks } from './stocks.js'; const stocks = new Stocks(); stocks.sync('Bill'); if (!stocks.stockFailed('Bill')) stocks.sell('apples', 'Bill');
Donc, si vous voulez tester que
stocks.stockFailed
sera falsy, vous pouvez écrire :tsimport { expect, test } from 'vitest'; import { Stocks } from './stocks.js'; const stocks = new Stocks(); test("if Bill stock hasn't failed, sell apples to him", () => { stocks.syncStocks('Bill'); expect(stocks.stockFailed('Bill')).toBeFalsy(); });
En JavaScript, toutes les valeurs sont considérées comme vraies, sauf
false
,0
,''
,null
,undefined
etNaN
.
toBeNull
Type :
() => Awaitable<void>
toBeNull
vérifie simplement si quelque chose estnull
. Alias de.toBe(null)
.tsimport { expect, test } from 'vitest'; function apples() { return null; } test("we don't have apples", () => { expect(apples()).toBeNull(); });
toBeNaN
Type :
() => Awaitable<void>
toBeNaN
vérifie simplement si quelque chose estNaN
. Alias de.toBe(NaN)
.tsimport { expect, test } from 'vitest'; let i = 0; function getApplesCount() { i++; return i > 1 ? Number.NaN : i; } test('getApplesCount has some unusual side effects...', () => { expect(getApplesCount()).not.toBeNaN(); expect(getApplesCount()).toBeNaN(); });
toBeTypeOf
Type :
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
vérifie si une valeur réelle est du type spécifié.tsimport { expect, test } from 'vitest'; const actual = 'stock'; test('stock is type of string', () => { expect(actual).toBeTypeOf('string'); });
toBeInstanceOf
Type :
(c: any) => Awaitable<void>
toBeInstanceOf
vérifie si une valeur réelle est une instance de la classe spécifiée.tsimport { expect, test } from 'vitest'; import { Stocks } from './stocks.js'; const stocks = new Stocks(); test('stocks are instance of Stocks', () => { expect(stocks).toBeInstanceOf(Stocks); });
toBeGreaterThan
Type :
(n: number | bigint) => Awaitable<void>
toBeGreaterThan
vérifie si la valeur réelle est strictement supérieure à la valeur spécifiée. Des valeurs égales entraîneront l'échec du test.tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have more then 10 apples', () => { expect(getApples()).toBeGreaterThan(10); });
toBeGreaterThanOrEqual
Type :
(n: number | bigint) => Awaitable<void>
toBeGreaterThanOrEqual
vérifie si la valeur réelle est supérieure ou égale à la valeur spécifiée.tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have 11 apples or more', () => { expect(getApples()).toBeGreaterThanOrEqual(11); });
toBeLessThan
Type :
(n: number | bigint) => Awaitable<void>
toBeLessThan
vérifie si la valeur réelle est strictement inférieure à la valeur spécifiée. Des valeurs égales entraîneront l'échec du test.tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have less then 20 apples', () => { expect(getApples()).toBeLessThan(20); });
toBeLessThanOrEqual
Type :
(n: number | bigint) => Awaitable<void>
toBeLessThanOrEqual
vérifie si la valeur réelle est inférieure ou égale à la valeur spécifiée.tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have 11 apples or less', () => { expect(getApples()).toBeLessThanOrEqual(11); });
toEqual
Type :
(received: any) => Awaitable<void>
toEqual
vérifie si la valeur réelle est égale à la valeur spécifiée ou a la même structure, s'il s'agit d'un objet (les compare récursivement). Vous pouvez constater la différence entretoEqual
ettoBe
dans l'exemple suivant :tsimport { expect, test } from 'vitest'; const stockBill = { type: 'apples', count: 13, }; const stockMary = { type: 'apples', count: 13, }; test('stocks have the same properties', () => { expect(stockBill).toEqual(stockMary); }); test('stocks are not the same', () => { expect(stockBill).not.toBe(stockMary); });
WARNING
Une égalité profonde ne sera pas effectuée pour les objets
Error
. Pour tester si quelque chose a été lancé, utilisez l'assertiontoThrowError
.
toStrictEqual
Type :
(received: any) => Awaitable<void>
toStrictEqual
vérifie si la valeur réelle est égale à la valeur spécifiée ou a la même structure s'il s'agit d'un objet (les compare récursivement), et du même type.Différences par rapport à
.toEqual
:- Les clés ayant des propriétés
undefined
sont vérifiées. Par exemple,{a: undefined, b: 2}
ne correspond pas à{b: 2}
lors de l'utilisation de.toStrictEqual
. - Les cases vides du tableau sont vérifiées. Par exemple,
[, 1]
ne correspond pas à[undefined, 1]
lors de l'utilisation de.toStrictEqual
. - Les types d'objets sont vérifiés pour être égaux. Par exemple, une instance de classe avec les champs
a
etb
ne sera pas égale à un objet littéral avec les champsa
etb
.
tsimport { expect, test } from 'vitest'; class Stock { constructor(type) { this.type = type; } } test('structurally the same, but semantically different', () => { expect(new Stock('apples')).toEqual({ type: 'apples' }); expect(new Stock('apples')).not.toStrictEqual({ type: 'apples' }); });
- Les clés ayant des propriétés
toContain
Type :
(received: string) => Awaitable<void>
toContain
vérifie si la valeur réelle est présente dans un tableau.toContain
peut également vérifier si une chaîne est une sous-chaîne d'une autre chaîne.tsimport { expect, test } from 'vitest'; import { getAllFruits } from './stocks.js'; test('the fruit list contains orange', () => { expect(getAllFruits()).toContain('orange'); });
toContainEqual
Type :
(received: any) => Awaitable<void>
toContainEqual
vérifie si un élément avec une structure et des valeurs spécifiques est contenu dans un tableau. Son fonctionnement est similaire àtoEqual
appliqué à chaque élément du tableau.tsimport { expect, test } from 'vitest'; import { getFruitStock } from './stocks.js'; test('apple available', () => { expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 }); });
toHaveLength
Type :
(received: number) => Awaitable<void>
toHaveLength
vérifie si un objet a une propriété.length
et qu'elle est définie sur une certaine valeur numérique.tsimport { expect, test } from 'vitest'; test('toHaveLength', () => { expect('abc').toHaveLength(3); expect([1, 2, 3]).toHaveLength(3); expect('').not.toHaveLength(3); // Ne possède pas une propriété .length valant 3 expect({ length: 3 }).toHaveLength(3); });
toHaveProperty
Type:
(key: any, received?: any) => Awaitable<void>
toHaveProperty
vérifie si un objet possède une propriété à la clékey
spécifiée.Vous pouvez également fournir une valeur optionnelle, qui sera comparée à la valeur de la propriété reçue en utilisant une comparaison d'égalité en profondeur (comme
toEqual
).tsimport { expect, test } from 'vitest'; const invoice = { isActive: true, 'P.O': '12345', customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, total_amount: 5000, items: [ { type: 'apples', quantity: 10, }, { type: 'oranges', quantity: 5, }, ], }; test('John Doe Invoice', () => { expect(invoice).toHaveProperty('isActive'); // Vérifie que la clé existe expect(invoice).toHaveProperty('total_amount', 5000); // Vérifie que la clé existe et que la valeur correspond expect(invoice).not.toHaveProperty('account'); // Vérifie que cette clé n'existe pas // Accès profond utilisant la notation pointée expect(invoice).toHaveProperty('customer.first_name'); expect(invoice).toHaveProperty('customer.last_name', 'Doe'); expect(invoice).not.toHaveProperty('customer.location', 'India'); // Accès profond utilisant un tableau contenant la clé expect(invoice).toHaveProperty('items[0].type', 'apples'); expect(invoice).toHaveProperty('items.0.type', 'apples'); // La notation pointée fonctionne également // Accès profond utilisant un tableau contenant le chemin de la clé (keyPath) expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples'); expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // La notation chaîne de caractères fonctionne également // Placez votre clé dans un tableau pour éviter qu'elle ne soit interprétée comme une référence profonde expect(invoice).toHaveProperty(['P.O'], '12345'); });
toMatch
Type:
(received: string | regexp) => Awaitable<void>
toMatch
vérifie si une chaîne de caractères correspond à une expression régulière ou à une autre chaîne de caractères.tsimport { expect, test } from 'vitest'; test('top fruits', () => { expect('top fruits include apple, orange and grape').toMatch(/apple/); expect('applefruits').toMatch('fruit'); // toMatch accepte également une chaîne de caractères });
TIP
Si la valeur dans le message d'erreur est tronquée, vous pouvez augmenter chaiConfig.truncateThreshold dans votre fichier de configuration.
toMatchObject
Type:
(received: object | array) => Awaitable<void>
toMatchObject
vérifie si un objet correspond à un sous-ensemble des propriétés d'un autre objet.Vous pouvez également passer un tableau d'objets. Ceci est utile pour vérifier que deux tableaux ont le même nombre d'éléments et que les éléments correspondent, contrairement à
arrayContaining
, qui autorise des éléments supplémentaires dans le tableau reçu.tsimport { expect, test } from 'vitest'; const johnInvoice = { isActive: true, customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, total_amount: 5000, items: [ { type: 'apples', quantity: 10, }, { type: 'oranges', quantity: 5, }, ], }; const johnDetails = { customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, }; test('invoice has john personal details', () => { expect(johnInvoice).toMatchObject(johnDetails); }); test('the number of elements must match exactly', () => { // Vérifie qu'un tableau d'objets correspond expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([ { foo: 'bar' }, { baz: 1 }, ]); });
toThrowError
Type:
(received: any) => Awaitable<void>
Alias:
toThrow
toThrowError
vérifie si une fonction lève une erreur lorsqu'elle est appelée.Vous pouvez fournir un argument optionnel pour vérifier qu'une erreur spécifique est levée :
- expression régulière : le message d'erreur correspond au modèle
- chaîne de caractères : le message d'erreur inclut la sous-chaîne
TIP
Vous devez envelopper le code dans une fonction, sinon l'erreur ne sera pas capturée et le test échouera.
Par exemple, si nous voulons tester que
getFruitStock('pineapples')
lève une exception, nous pourrions écrire :tsimport { expect, test } from 'vitest'; function getFruitStock(type) { if (type === 'pineapples') throw new DiabetesError( 'Pineapples are not good for people with diabetes' ); // Faire d'autres choses } test('throws on pineapples', () => { // Teste que le message d'erreur contient "diabetes" quelque part : ceux-ci sont équivalents expect(() => getFruitStock('pineapples')).toThrowError(/diabetes/); expect(() => getFruitStock('pineapples')).toThrowError('diabetes'); // Teste le message d'erreur exact expect(() => getFruitStock('pineapples')).toThrowError( /^Pineapples are not good for people with diabetes$/ ); });
TIP
Pour tester les fonctions asynchrones, utilisez cette assertion en combinaison avec rejects.
jsfunction getAsyncFruitStock() { return Promise.reject(new Error('empty')); } test('throws on pineapples', async () => { await expect(() => getAsyncFruitStock()).rejects.toThrowError('empty'); });
toMatchSnapshot
Type:
<T>(shape?: Partial<T> | string, message?: string) => void
Cette assertion garantit qu'une valeur correspond à la capture instantanée (snapshot) la plus récente.
Vous pouvez fournir un argument de chaîne
hint
optionnel qui est ajouté au nom du test. Bien que Vitest ajoute toujours un nombre à la fin du nom d'une capture instantanée, de courts indices descriptifs peuvent être plus utiles que des nombres pour distinguer plusieurs captures instantanées dans un même bloc 'it' ou 'test'. Vitest trie les captures instantanées par nom dans le fichier.snap
correspondant.TIP
Lorsque la capture instantanée ne correspond pas et que le test échoue, si la non-concordance est attendue, vous pouvez appuyer sur la touche
u
pour mettre à jour la capture instantanée une seule fois. Ou vous pouvez passer les options CLI-u
ou--update
pour que Vitest mette toujours à jour les captures instantanées.tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchSnapshot(); });
Vous pouvez également fournir une structure d'objet, si vous ne testez qu'une structure d'objet et que vous n'avez pas besoin d'une correspondance à 100 % :
tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchSnapshot({ foo: expect.any(Set) }); });
toMatchInlineSnapshot
Type:
<T>(shape?: Partial<T> | string, snapshot?: string, message?: string) => void
Cette assertion garantit qu'une valeur correspond à la capture instantanée (snapshot) la plus récente.
Vitest ajoute et met à jour l'argument de chaîne 'inlineSnapshot' du comparateur directement dans le fichier de test (au lieu d'un fichier
.snap
externe).tsimport { expect, test } from 'vitest'; test('matches inline snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; // Vitest mettra à jour le contenu suivant lors de la mise à jour de la capture instantanée expect(data).toMatchInlineSnapshot(` { "foo": Set { "bar", "snapshot", }, } `); });
Vous pouvez également fournir une structure d'objet, si vous ne testez qu'une structure d'objet et que vous n'avez pas besoin d'une correspondance à 100 % :
tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchInlineSnapshot( { foo: expect.any(Set) }, ` { "foo": Any<Set>, } ` ); });
toMatchFileSnapshot
Type:
<T>(filepath: string, message?: string) => Promise<void>
Version: Depuis Vitest 0.30.0
Compare ou met à jour la capture instantanée avec le contenu d'un fichier spécifié explicitement (au lieu du fichier
.snap
).tsimport { expect, it } from 'vitest'; it('render basic', async () => { const result = renderHTML(h('div', { class: 'foo' })); await expect(result).toMatchFileSnapshot('./test/basic.output.html'); });
Notez que, comme l'opération du système de fichiers est asynchrone, vous devez utiliser
await
avectoMatchFileSnapshot()
.
toThrowErrorMatchingSnapshot
Type:
(message?: string) => void
Identique à
toMatchSnapshot
, mais attend la même valeur quetoThrowError
.Si la fonction lève une
Error
, la capture instantanée sera le message d'erreur. Sinon, la capture instantanée sera la valeur levée par la fonction.
toThrowErrorMatchingInlineSnapshot
Type:
(snapshot?: string, message?: string) => void
Identique à
toMatchInlineSnapshot
, mais attend la même valeur quetoThrowError
.Si la fonction lève une
Error
, la capture instantanée sera le message d'erreur. Sinon, la capture instantanée sera la valeur levée par la fonction.
toHaveBeenCalled
Type:
() => Awaitable<void>
Cette assertion est utile pour tester qu'une fonction a été appelée. Elle requiert qu'une fonction espion (spy function) soit passée à
expect
.tsimport { expect, test, vi } from 'vitest'; const market = { buy(subject: string, amount: number) { // ... }, }; test('spy function', () => { const buySpy = vi.spyOn(market, 'buy'); expect(buySpy).not.toHaveBeenCalled(); market.buy('apples', 10); expect(buySpy).toHaveBeenCalled(); });
toHaveBeenCalledTimes
- Type:
(amount: number) => Awaitable<void>
Cette assertion vérifie si une fonction a été appelée un certain nombre de fois. Elle requiert qu'une fonction espion (spy function) soit passée à expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function called two times', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenCalledTimes(2);
});
toHaveBeenCalledWith
- Type:
(...args: any[]) => Awaitable<void>
Cette assertion vérifie si une fonction a été appelée au moins une fois avec certains paramètres. Elle requiert qu'une fonction espion (spy function) soit passée à expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenCalledWith('apples', 10);
expect(buySpy).toHaveBeenCalledWith('apples', 20);
});
toHaveBeenLastCalledWith
- Type:
(...args: any[]) => Awaitable<void>
Cette assertion vérifie si une fonction a été appelée avec certains paramètres lors de sa dernière invocation. Elle requiert qu'une fonction espion (spy function) soit passée à expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).not.toHaveBeenLastCalledWith('apples', 10);
expect(buySpy).toHaveBeenLastCalledWith('apples', 20);
});
toHaveBeenNthCalledWith
- Type:
(time: number, ...args: any[]) => Awaitable<void>
Cette assertion vérifie si une fonction a été appelée avec certains paramètres lors de son n-ième appel. La numérotation commence à 1. Donc, pour vérifier le deuxième appel, vous utiliserez .toHaveBeenNthCalledWith(2, ...)
.
Elle requiert qu'une fonction espion (spy function) soit passée à expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('first call of spy function called with right params', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenNthCalledWith(1, 'apples', 10);
});
toHaveReturned
- Type:
() => Awaitable<void>
Cette assertion vérifie si une fonction a retourné une valeur avec succès au moins une fois (c'est-à-dire, sans lever d'erreur). Elle requiert qu'une fonction espion (spy function) soit passée à expect
.
import { expect, test, vi } from 'vitest';
function getApplesPrice(amount: number) {
const PRICE = 10;
return amount * PRICE;
}
test('spy function returned a value', () => {
const getPriceSpy = vi.fn(getApplesPrice);
const price = getPriceSpy(10);
expect(price).toBe(100);
expect(getPriceSpy).toHaveReturned();
});
toHaveReturnedTimes
- Type:
(amount: number) => Awaitable<void>
Cette assertion vérifie si une fonction a retourné une valeur avec succès un nombre exact de fois (c'est-à-dire, sans lever d'erreur). Elle requiert qu'une fonction espion (spy function) soit passée à expect
.
import { expect, test, vi } from 'vitest';
test('spy function returns a value two times', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveReturnedTimes(2);
});
toHaveReturnedWith
- Type:
(returnValue: any) => Awaitable<void>
Vous pouvez utiliser cette assertion pour vérifier si une fonction espion a retourné une valeur spécifique au moins une fois. Cette assertion nécessite qu'une fonction espion soit passée en argument à expect
.
import { expect, test, vi } from 'vitest';
test('la fonction espion retourne un produit', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
expect(sell).toHaveReturnedWith({ product: 'apples' });
});
toHaveLastReturnedWith
- Type:
(returnValue: any) => Awaitable<void>
Vous pouvez utiliser cette assertion pour vérifier si une fonction espion a retourné une valeur spécifique lors de son dernier appel. Cette assertion nécessite qu'une fonction espion soit passée en argument à expect
.
import { expect, test, vi } from 'vitest';
test('la fonction espion retourne des bananes lors du dernier appel', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveLastReturnedWith({ product: 'bananas' });
});
toHaveNthReturnedWith
- Type:
(time: number, returnValue: any) => Awaitable<void>
Vous pouvez utiliser cette assertion pour vérifier si une fonction espion a retourné une valeur spécifique lors d'un appel spécifique (le n-ième appel). Cette assertion nécessite qu'une fonction espion soit passée en argument à expect
.
import { expect, test, vi } from 'vitest';
test('la fonction espion retourne des bananes lors du deuxième appel', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveNthReturnedWith(2, { product: 'bananas' });
});
toSatisfy
- Type:
(predicate: (value: any) => boolean) => Awaitable<void>
Cette assertion vérifie si une valeur satisfait une condition donnée par un prédicat.
describe('toSatisfy()', () => {
const isOdd = (value: number) => value % 2 !== 0;
it('réussit avec 1', () => {
expect(1).toSatisfy(isOdd);
});
it('échoue avec 2', () => {
expect(2).not.toSatisfy(isOdd);
});
});
resolves
Type:
Promisify<Assertions>
resolves
simplifie l'assertion de code asynchrone. Utilisez-le pour extraire la valeur d'une promesse résolue et vérifier sa valeur avec des assertions classiques. Si la promesse est rejetée, l'assertion échouera.Il renvoie le même objet
Assertions
, mais tous les matchers renvoient maintenant unePromise
, vous devrez donc utiliserawait
. Fonctionne également avec les assertionschai
.Par exemple, si vous avez une fonction qui effectue un appel API et renvoie des données, vous pouvez utiliser ce code pour vérifier sa valeur de retour :
tsimport { expect, test } from 'vitest'; async function buyApples() { return fetch('/buy/apples').then(r => r.json()); } test('buyApples retourne un nouvel identifiant de stock', async () => { // toEqual retourne maintenant une promesse, vous devez donc l'attendre await expect(buyApples()).resolves.toEqual({ id: 1 }); // API jest await expect(buyApples()).resolves.to.equal({ id: 1 }); // API chai });
WARNING
Si l'assertion n'est pas attendue (awaited), vous obtiendrez un test faussement positif qui réussira à chaque fois. Pour vous assurer que les assertions sont réellement appelées, vous pouvez utiliser
expect.assertions(number)
.
rejects
Type:
Promisify<Assertions>
rejects
simplifie l'assertion de code asynchrone. Utilisez-le pour extraire la raison du rejet d'une promesse et vérifier sa valeur avec des assertions classiques. Si la promesse est résolue avec succès, l'assertion échouera.Il renvoie le même objet
Assertions
, mais tous les matchers renvoient maintenant unePromise
, vous devrez donc utiliserawait
. Fonctionne également avec les assertionschai
.Par exemple, si vous avez une fonction qui échoue lorsque vous l'appelez, vous pouvez utiliser ce code pour vérifier la raison :
tsimport { expect, test } from 'vitest'; async function buyApples(id) { if (!id) throw new Error('no id'); } test('buyApples lève une erreur lorsqu'aucun identifiant n'est fourni', async () => { // toThrow retourne maintenant une promesse, vous devez donc l'attendre await expect(buyApples()).rejects.toThrow('no id'); });
WARNING
Si l'assertion n'est pas attendue (awaited), vous obtiendrez un test faussement positif qui réussira à chaque fois. Pour vous assurer que les assertions ont réellement été appelées, vous pouvez utiliser
expect.assertions(number)
.
expect.assertions
Type:
(count: number) => void
Après l'exécution du test, qu'il ait réussi ou échoué, vérifiez qu'un nombre spécifique d'assertions ont été appelées pendant un test. Un cas d'utilisation typique est de vérifier si du code asynchrone a été exécuté.
Par exemple, si nous avons une fonction qui appelle de manière asynchrone deux matchers, nous pouvons vérifier qu'ils ont bien été appelés.
tsimport { expect, test } from 'vitest'; async function doAsync(...cbs) { await Promise.all(cbs.map((cb, index) => cb({ index }))); } test('toutes les assertions sont appelées', async () => { expect.assertions(2); function callback1(data) { expect(data).toBeTruthy(); } function callback2(data) { expect(data).toBeTruthy(); } await doAsync(callback1, callback2); });
WARNING
Lorsque vous utilisez
assertions
avec des tests concurrents asynchrones, leexpect
du Contexte de test local doit être utilisé pour s'assurer que le test approprié est pris en compte.
expect.hasAssertions
Type:
() => void
Après l'exécution du test, qu'il ait réussi ou non, vérifiez qu'au moins une assertion a été appelée pendant un test. Un cas d'utilisation typique est de vérifier si du code asynchrone a été exécuté.
Par exemple, si vous avez un code qui appelle un callback, nous pouvons faire une assertion à l'intérieur d'un callback, mais le test réussira toujours si nous ne vérifions pas si une assertion a été appelée.
tsimport { expect, test } from 'vitest'; import { db } from './db.js'; const cbs = []; function onSelect(cb) { cbs.push(cb); } // after selecting from db, we call all callbacks function select(id) { return db.select({ id }).then(data => { return Promise.all(cbs.map(cb => cb(data))); }); } test('le callback a été appelé', async () => { expect.hasAssertions(); onSelect(data => { // should be called on select expect(data).toBeTruthy(); }); // if not awaited, test will fail // if you don't have expect.hasAssertions(), test will pass await select(3); });
expect.unreachable
Type:
(message?: string) => never
Cette méthode permet de s'assurer qu'une ligne de code ne doit jamais être atteinte.
Par exemple, si nous voulons tester que
build()
lève une exception car les répertoires reçus n'ont pas de dossiersrc
, et également gérer chaque erreur séparément, nous pourrions faire ceci :tsimport { expect, test } from 'vitest'; async function build(dir) { if (dir.includes('no-src')) throw new Error(`${dir}/src does not exist`); } const errorDirs = [ 'no-src-folder', // ... ]; test.each(errorDirs)('build échoue avec "%s"', async dir => { try { await build(dir); expect.unreachable('Ne devrait pas passer la construction'); } catch (err: any) { expect(err).toBeInstanceOf(Error); expect(err.stack).toContain('build'); switch (dir) { case 'no-src-folder': expect(err.message).toBe(`${dir}/src does not exist`); break; default: // to exhaust all error tests expect.unreachable('Tous les tests d'erreur doivent être gérés'); break; } } });
expect.anything
Type:
() => any
Ce matcher asymétrique, utilisé avec une vérification d'égalité, renverra toujours
true
. Utile pour s'assurer de l'existence d'une propriété.tsimport { expect, test } from 'vitest'; test('l'objet a une clé "apples"', () => { expect({ apples: 22 }).toEqual({ apples: expect.anything() }); });
expect.any
Type:
(constructor: unknown) => any
Ce matcher asymétrique, utilisé avec une vérification d'égalité, renverra
true
uniquement si la valeur est une instance d'un constructeur spécifié. Utile lorsqu'une valeur est générée à chaque fois et que l'on souhaite uniquement vérifier son type.tsimport { expect, test } from 'vitest'; import { generateId } from './generators.js'; test('"id" est un nombre', () => { expect({ id: generateId() }).toEqual({ id: expect.any(Number) }); });
expect.arrayContaining
Type:
<T>(expected: T[]) => any
Utilisé avec une vérification d'égalité, ce matcher asymétrique renvoie
true
si la valeur est un tableau contenant les éléments indiqués.tsimport { expect, test } from 'vitest'; test('le panier contient des fuji', () => { const basket = { varieties: ['Empire', 'Fuji', 'Gala'], count: 3, }; expect(basket).toEqual({ count: 3, varieties: expect.arrayContaining(['Fuji']), }); });
TIP
Vous pouvez utiliser
expect.not
avec ce matcher pour nier la valeur attendue.
expect.objectContaining
Type:
(expected: any) => any
Utilisé avec une vérification d'égalité, ce matcher asymétrique renvoie
true
si la valeur présente une structure similaire, c'est-à-dire qu'elle contient au moins les propriétés spécifiées avec les valeurs correspondantes.tsimport { expect, test } from 'vitest'; test('le panier contient des pommes Empire', () => { const basket = { varieties: [ { name: 'Empire', count: 1, }, ], }; expect(basket).toEqual({ varieties: [expect.objectContaining({ name: 'Empire' })], }); });
TIP
Vous pouvez utiliser
expect.not
avec ce matcher pour nier la valeur attendue.
expect.stringContaining
Type:
(expected: any) => any
Utilisé avec une vérification d'égalité, ce matcher asymétrique renvoie
true
si la valeur est une chaîne contenant une sous-chaîne spécifiée.tsimport { expect, test } from 'vitest'; test('la variété a "Emp" dans son nom', () => { const variety = { name: 'Empire', count: 1, }; expect(variety).toEqual({ name: expect.stringContaining('Emp'), count: 1, }); });
TIP
Vous pouvez utiliser
expect.not
avec ce matcher pour nier la valeur attendue.
expect.stringMatching
Type:
(expected: any) => any
Utilisé avec une vérification d'égalité, ce matcher asymétrique renvoie
true
si la valeur est une chaîne contenant une sous-chaîne spécifiée ou correspondant à une expression régulière.tsimport { expect, test } from 'vitest'; test('la variété se termine par "re"', () => { const variety = { name: 'Empire', count: 1, }; expect(variety).toEqual({ name: expect.stringMatching(/re$/), count: 1, }); });
TIP
Vous pouvez utiliser
expect.not
avec ce matcher pour nier la valeur attendue.
expect.addSnapshotSerializer
Type:
(plugin: PrettyFormatPlugin) => void
Cette méthode ajoute des sérialiseurs personnalisés qui sont appelés lors de la création d'un snapshot. C'est une fonctionnalité avancée - si vous voulez en savoir plus, veuillez lire un guide sur les sérialiseurs personnalisés.
Si vous ajoutez des sérialiseurs personnalisés, vous devez appeler cette méthode dans le fichier
setupFiles
. Cela affectera chaque snapshot.TIP
Si vous avez déjà utilisé Vue CLI avec Jest, vous pouvez installer jest-serializer-vue. Sinon, vos snapshots seront encapsulés dans une chaîne de caractères, ce qui entraînera l'échappement des guillemets (
"
).
expect.extend
Type:
(matchers: MatchersObject) => void
Vous pouvez étendre les matchers par défaut en ajoutant les vôtres. Cette fonction est utilisée pour étendre l'objet
matchers
avec des matchers personnalisés.Définir des matchers de cette manière permet également de créer des matchers asymétriques utilisables comme
expect.stringContaining
.tsimport { expect, test } from 'vitest'; test('matchers personnalisés', () => { expect.extend({ toBeFoo: (received, expected) => { if (received !== 'foo') { return { message: () => `expected ${received} to be foo`, pass: false, }; } }, }); expect('foo').toBeFoo(); expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() }); });
TIP
Pour que vos matchers soient disponibles dans chaque test, vous devez appeler cette méthode dans le fichier
setupFiles
.Cette fonction étant compatible avec
expect.extend
de Jest, toute bibliothèque l'utilisant pour créer des matchers personnalisés fonctionnera avec Vitest.Si vous utilisez TypeScript (depuis Vitest 0.31.0), vous pouvez étendre l'interface
Assertion
par défaut dans un fichier de déclaration ambiante (par exemple :vitest.d.ts
) en utilisant le code suivant :tsinterface CustomMatchers<R = unknown> { toBeFoo(): R; } declare module 'vitest' { interface Assertion<T = any> extends CustomMatchers<T> {} interface AsymmetricMatchersContaining extends CustomMatchers {} }
WARNING
N'oubliez pas d'inclure le fichier de déclaration ambiante dans votre
tsconfig.json
.TIP
Si vous voulez en savoir plus, consultez le guide sur l'extension des matchers.