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
});
// reporter signalera les deux erreurs à la fin de l'exécution
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(4); // Échoue et interrompt le test, toutes les erreurs précédentes seront affichées
expect.soft(1 + 3).toBe(5); // Ne s'exécute pas
});
WARNING
expect.soft
ne peut être utilisé qu'à l'intérieur de la fonction test
.
poll
interface ExpectPoll extends ExpectStatic {
(actual: () => T, options: { interval; timeout; message }): Promise<
Assertions<T>
>;
}
expect.poll
réexécute l'assertion jusqu'à ce qu'elle réussisse. Vous pouvez configurer le nombre de fois que Vitest doit réexécuter la fonction de rappel expect.poll
en définissant les options interval
et timeout
.
Si une erreur est levée à l'intérieur de la fonction de rappel expect.poll
, Vitest réessayera jusqu'à ce que le délai d'attente expire.
import { expect, test } from 'vitest';
test('element exists', async () => {
asyncInjectElement();
await expect.poll(() => document.querySelector('.element')).toBeTruthy();
});
WARNING
expect.poll
rend chaque assertion asynchrone, vous devez donc l'attendre. Depuis Vitest 2.2, si vous oubliez de l'attendre, le test échouera avec un avertissement vous invitant à le faire.
expect.poll
ne fonctionne pas avec plusieurs correspondances :
- Les correspondances d'instantanés ne sont pas prises en charge car elles réussiront toujours. Si votre condition est instable, envisagez d'utiliser
vi.waitFor
à la place pour la résoudre d'abord :
import { expect, vi } from 'vitest';
const flakyValue = await vi.waitFor(() => getFlakyValue());
expect(flakyValue).toMatchSnapshot();
.resolves
et.rejects
ne sont pas pris en charge.expect.poll
attend déjà la condition si elle est asynchrone.toThrow
et ses alias ne sont pas pris en charge car la conditionexpect.poll
est toujours résolue avant que la correspondance n'obtienne la valeur.
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 à appeler expect(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 utiliser toEqual
.
Par exemple, le code ci-dessous vérifie si le commerçant a 13 pommes.
import { 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'assertion toBeCloseTo
.
toBeCloseTo
- Type :
(value: number, numDigits?: number) => Awaitable<void>
Utilisez toBeCloseTo
pour comparer les nombres à virgule flottante. L'argument optionnel numDigits
limite le nombre de chiffres à vérifier après la virgule. Par exemple :
import { 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.
import { 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.
import { expect, test } from 'vitest';
function getApplesFromStock(stock: string) {
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 en true
.
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.
import { 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 :
import { 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
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
et document.all
.
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 en false
.
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.
import { 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 :
import { 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
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
et document.all
.
toBeNull
- Type :
() => Awaitable<void>
toBeNull
vérifie simplement si quelque chose est null
. Alias de .toBe(null)
.
import { 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 est NaN
. Alias de .toBe(NaN)
.
import { 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é.
import { 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.
import { 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.
import { 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.
import { 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.
import { 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.
import { 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 entre toEqual
et toBe
dans l'exemple suivant :
import { 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
. Seule la propriété message
d'une erreur est prise en compte pour l'égalité. Pour personnaliser l'égalité afin de vérifier des propriétés autres que message
, utilisez expect.addEqualityTesters
. Pour tester si quelque chose a été lancé, utilisez l'assertion toThrowError
.
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
.
import { 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' });
});
toContain
- Type:
(received: string) => Awaitable<void>
toContain
affirme si la valeur réelle est dans un tableau. toContain
peut également vérifier si une chaîne est une sous-chaîne d'une autre chaîne. Depuis Vitest 1.0, si vous exécutez des tests dans un environnement de type navigateur, cette assertion peut également vérifier si une classe est contenue dans une classList
, ou si un élément est à l'intérieur d'un autre.
import { expect, test } from 'vitest';
import { getAllFruits } from './stocks.js';
test('la liste de fruits contient orange', () => {
expect(getAllFruits()).toContain('orange');
const element = document.querySelector('#el');
// element a une classe
expect(element.classList).toContain('flex');
// element est à l'intérieur d'un autre
expect(document.querySelector('#wrapper')).toContain(element);
});
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.
import { 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.
import { 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
).
import { 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.
import { 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
});
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.
import { 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 :
import { expect, test } from 'vitest';
function getFruitStock(type: string) {
if (type === 'pineapples') throw new Error('Pineapples are not in stock');
// Faire d'autres choses
}
test('throws on pineapples', () => {
// Teste que le message d'erreur contient "stock" quelque part : ceux-ci sont équivalents
expect(() => getFruitStock('pineapples')).toThrowError(/stock/);
expect(() => getFruitStock('pineapples')).toThrowError('stock');
// Teste le message d'erreur exact
expect(() => getFruitStock('pineapples')).toThrowError(
/^Pineapples are not in stock$/
);
});
TIP
Pour tester les fonctions asynchrones, utilisez cette assertion en combinaison avec rejects.
function 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.
import { 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 % :
import { 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).
import { 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 % :
import { 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>
Compare ou met à jour la capture instantanée avec le contenu d'un fichier spécifié explicitement (au lieu du fichier .snap
).
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Note that since file system operation is async, you need to use await
with toMatchFileSnapshot()
. If await
is not used, Vitest treats it like expect.soft
, meaning the code after the statement will continue to run even if the snapshot mismatches. After the test finishes, Vitest will check the snapshot and fail if there is a mismatch.
toThrowErrorMatchingSnapshot
- Type:
(message?: string) => void
Identique à toMatchSnapshot
, mais attend la même valeur que toThrowError
.
toThrowErrorMatchingInlineSnapshot
- Type:
(snapshot?: string, message?: string) => void
Identique à toMatchInlineSnapshot
, mais attend la même valeur que toThrowError
.
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
.
import { 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 appeler cette assertion pour vérifier si une fonction a renvoyé avec succès une certaine valeur lors de sa dernière invocation. Requiert qu'une fonction espionne soit passée à 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' });
});
toHaveResolved
- Type:
() => Awaitable<void>
Cette assertion vérifie si une fonction a résolu une valeur avec succès au moins une fois (c'est-à-dire n'a pas rejeté). Nécessite qu'une fonction espionne soit passée à expect
.
Si la fonction a renvoyé une promesse, mais qu'elle n'est pas encore résolue, cela échouera.
import { expect, test, vi } from 'vitest';
import db from './db/apples.js';
async function getApplesPrice(amount: number) {
return amount * (await db.get('price'));
}
test('la fonction espionne a résolu une valeur', async () => {
const getPriceSpy = vi.fn(getApplesPrice);
const price = await getPriceSpy(10);
expect(price).toBe(100);
expect(getPriceSpy).toHaveResolved();
});
toHaveResolvedTimes
- Type:
(amount: number) => Awaitable<void>
Cette assertion vérifie si une fonction a résolu une valeur avec succès un nombre exact de fois (c'est-à-dire n'a pas rejeté). Nécessite qu'une fonction espionne soit passée à expect
.
Cela ne compte que les promesses résolues. Si la fonction a renvoyé une promesse, mais qu'elle n'est pas encore résolue, elle ne sera pas comptée.
import { expect, test, vi } from 'vitest';
test('la fonction espionne a résolu une valeur deux fois', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }));
await sell('apples');
await sell('bananas');
expect(sell).toHaveResolvedTimes(2);
});
toHaveResolvedWith
- Type:
(returnValue: any) => Awaitable<void>
Vous pouvez appeler cette assertion pour vérifier si une fonction a résolu une certaine valeur avec succès au moins une fois (c'est-à-dire n'a pas rejeté). Nécessite qu'une fonction espionne soit passée à expect
.
Si la fonction a renvoyé une promesse, mais qu'elle n'est pas encore résolue, cela échouera.
import { expect, test, vi } from 'vitest';
test('la fonction espionne a résolu un produit', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }));
await sell('apples');
expect(sell).toHaveResolvedWith({ product: 'apples' });
});
toHaveLastResolvedWith
- Type:
(returnValue: any) => Awaitable<void>
Vous pouvez appeler cette assertion pour vérifier si une fonction a résolu une certaine valeur avec succès lors de sa dernière invocation. Nécessite qu'une fonction espionne soit passée à expect
.
Si la fonction a renvoyé une promesse, mais qu'elle n'est pas encore résolue, cela échouera.
import { expect, test, vi } from 'vitest';
test('la fonction espionne résout les bananes lors du dernier appel', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }));
await sell('apples');
await sell('bananas');
expect(sell).toHaveLastResolvedWith({ product: 'bananas' });
});
toHaveNthResolvedWith
- Type:
(time: number, returnValue: any) => Awaitable<void>
Vous pouvez appeler cette assertion pour vérifier si une fonction a résolu une certaine valeur avec succès lors d'une invocation spécifique. Nécessite qu'une fonction espionne soit passée à expect
.
Si la fonction a renvoyé une promesse, mais qu'elle n'est pas encore résolue, cela échouera.
import { expect, test, vi } from 'vitest';
test('la fonction espionne renvoie des bananes lors du deuxième appel', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }));
await sell('apples');
await sell('bananas');
expect(sell).toHaveNthResolvedWith(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.
import { describe, expect, it } from 'vitest';
const isOdd = (value: number) => value % 2 !== 0;
describe('toSatisfy()', () => {
it('pass with 0', () => {
expect(1).toSatisfy(isOdd);
});
it('pass with negation', () => {
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 une Promise
, vous devrez donc utiliser await
. Fonctionne également avec les assertions chai
.
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 :
import { 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)
.
Depuis Vitest 2.2, si une méthode n'est pas attendue (awaited), Vitest affichera un avertissement à la fin du test. Dans Vitest 3, le test sera marqué comme "échoué" si l'assertion n'est pas attendue.
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 une Promise
, vous devrez donc utiliser await
. Fonctionne également avec les assertions chai
.
Par exemple, si vous avez une fonction qui échoue lorsque vous l'appelez, vous pouvez utiliser ce code pour vérifier la raison :
import { 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)
.
Depuis Vitest 2.2, si une méthode n'est pas attendue (awaited), Vitest affichera un avertissement à la fin du test. Dans Vitest 3, le test sera marqué comme "échoué" si l'assertion n'est pas attendue.
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.
import { 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, le expect
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.
import { 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 dossier src
, et également gérer chaque erreur séparément, nous pourrions faire ceci :
import { 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é.
import { 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.
import { expect, test } from 'vitest';
import { generateId } from './generators.js';
test('"id" est un nombre', () => {
expect({ id: generateId() }).toEqual({ id: expect.any(Number) });
});
expect.closeTo
- Type:
(expected: any, precision?: number) => any
expect.closeTo
est utile pour comparer des nombres à virgule flottante dans les propriétés d'objet ou les éléments de tableau. Si vous avez besoin de comparer un nombre, veuillez utiliser .toBeCloseTo
à la place.
L'argument optionnel precision
limite le nombre de chiffres à vérifier après la virgule. Pour la valeur par défaut 2
, le critère de test est Math.abs(expected - received) < 0.005 (soit, 10 ** -2 / 2)
.
Par exemple, ce test réussit avec une précision de 5 chiffres :
test('comparer un flottant dans les propriétés d'un 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.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.
import { 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.
import { 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.
import { 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.
import { 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
.
import { 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 :
interface 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.
expect.addEqualityTesters
- Type :
(tester : Array<Tester>) => void
Vous pouvez utiliser cette méthode pour définir des testeurs personnalisés, qui sont des méthodes utilisées par les correspondances, pour tester si deux objets sont égaux. Il est compatible avec expect.addEqualityTesters
de Jest.
import { expect, test } from 'vitest';
class AnagramComparator {
public word: string;
constructor(word: string) {
this.word = word;
}
equals(other: AnagramComparator): boolean {
const cleanStr1 = this.word.replace(/ /g, '').toLowerCase();
const cleanStr2 = other.word.replace(/ /g, '').toLowerCase();
const sortedStr1 = cleanStr1.split('').sort().join('');
const sortedStr2 = cleanStr2.split('').sort().join('');
return sortedStr1 === sortedStr2;
}
}
function isAnagramComparator(a: unknown): a is AnagramComparator {
return a instanceof AnagramComparator;
}
function areAnagramsEqual(a: unknown, b: unknown): boolean | undefined {
const isAAnagramComparator = isAnagramComparator(a);
const isBAnagramComparator = isAnagramComparator(b);
if (isAAnagramComparator && isBAnagramComparator) return a.equals(b);
else if (isAAnagramComparator === isBAnagramComparator) return undefined;
else return false;
}
expect.addEqualityTesters([areAnagramsEqual]);
test('testeur d'égalité personnalisé', () => {
expect(new AnagramComparator('listen')).toEqual(
new AnagramComparator('silent')
);
});