expect
Voici la version optimisée de votre documentation technique en français :
type Awaitable<T> = T | PromiseLike<T>;
expect
est utilisé pour créer des assertions. Dans ce contexte, les assertions
sont des fonctions qui vérifient une condition donnée. Vitest fournit par défaut les assertions chai
, ainsi que des assertions compatibles Jest
basées sur chai
. Contrairement à Jest
, Vitest accepte un message comme deuxième argument : si l'assertion échoue, ce message sera affiché.
export interface ExpectStatic
extends Chai.ExpectStatic,
AsymmetricMatchersContaining {
<T>(actual: T, message?: string): Assertion<T>;
extend: (expects: MatchersObject) => void;
anything: () => any;
any: (constructor: unknown) => any;
getState: () => MatcherState;
setState: (state: Partial<MatcherState>) => void;
not: AsymmetricMatchersContaining;
}
Par exemple, ce code affirme 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, vous verrez une erreur Node.js dans la console au lieu de la sortie de Vitest. Pour en savoir plus sur test
, veuillez consulter la Référence de l'API de test.
De plus, expect
peut être utilisé statiquement pour accéder aux fonctions de comparateur (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 souhaitez 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 de terminer l'exécution du test lorsqu'une assertion échoue, il continue l'exécution et marque le test comme échoué. Toutes les erreurs rencontrées pendant le test seront affichées une fois le test terminé.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // marque le test comme échoué et continue
expect.soft(1 + 2).toBe(4); // marque le test comme échoué et continue
});
// Le rapporteur 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 terminé et toutes les erreurs précédentes seront affichées.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // marque le test comme échoué et continue
expect(1 + 2).toBe(4); // échoue et termine 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 la fréquence de réexécution du rappel expect.poll
en définissant les options interval
et timeout
.
Si une erreur est levée à l'intérieur du 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 (await
). Depuis Vitest 3, si vous oubliez de l'attendre, le test échouera avec un avertissement.
expect.poll
ne fonctionne pas avec plusieurs comparateurs :
- Les comparateurs de snapshot ne sont pas pris en charge car ils réussiront toujours. Si votre condition est instable, envisagez d'utiliser
vi.waitFor
pour la stabiliser en premier :
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 le comparateur ne reçoive la valeur.
not
L'utilisation de not
inverse l'assertion. Par exemple, ce code affirme 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 affirmer l'égalité de types primitifs ou la référence identique d'objets. C'est l'équivalent d'appeler expect(Object.is(3, 3)).toBe(true)
. Si les objets ne sont pas les mêmes mais que vous souhaitez vérifier si leurs structures sont identiques, utilisez 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);
});
Évitez d'utiliser toBe
avec des nombres à virgule flottante. Puisque JavaScript les arrondit, 0.1 + 0.2
n'est pas strictement 0.3
. Pour affirmer 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', () => {
// 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
affirme que la valeur n'est pas undefined
. Il est utile, par exemple, pour vérifier si une 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>
Contrairement à toBeDefined
, toBeUndefined
affirme que la valeur est undefined
. Il est utile, par exemple, pour vérifier si une fonction n'a rien retourné.
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
affirme que la valeur est vraie lorsqu'elle est convertie en booléen. Utile si la valeur elle-même n'est pas importante, mais que vous souhaitez simplement savoir si elle peut être convertie en true
.
Par exemple, avec ce code, la valeur de retour de stocks.getInfo
n'est pas pertinente pour vous - il peut s'agir d'un objet complexe, d'une chaîne de caractères 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 vrai, vous pourriez é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();
});
Toute valeur en JavaScript est vraie, sauf false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
et document.all
.
toBeFalsy
- Type :
() => Awaitable<void>
toBeFalsy
affirme que la valeur est fausse lorsqu'elle est convertie en booléen. Utile si la valeur elle-même n'est pas importante, mais que vous souhaitez simplement savoir si elle peut être convertie en false
.
Par exemple, avec ce code, la valeur de retour de stocks.stockFailed
n'est pas pertinente pour vous - elle peut retourner n'importe quelle valeur fausse, 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 faux, vous pourriez é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();
});
Toute valeur en JavaScript est vraie, sauf false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
et document.all
.
toBeNull
- Type :
() => Awaitable<void>
toBeNull
vérifie simplement si une valeur est null
. C'est un alias pour .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 une valeur est NaN
. C'est un alias pour .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();
});
toBeOneOf
- Type :
(sample: Array<any>) => any
toBeOneOf
affirme si une valeur correspond à l'une des valeurs du tableau fourni.
import { expect, test } from 'vitest';
test('fruit is one of the allowed values', () => {
expect(fruit).toBeOneOf(['apple', 'banana', 'orange']);
});
Le comparateur asymétrique est particulièrement utile lorsque l'on teste des propriétés optionnelles qui pourraient être null
ou undefined
:
test('optional properties can be null or undefined', () => {
const user = {
firstName: 'John',
middleName: undefined,
lastName: 'Doe',
};
expect(user).toEqual({
firstName: expect.any(String),
middleName: expect.toBeOneOf([expect.any(String), undefined]),
lastName: expect.any(String),
});
});
TIP
Vous pouvez utiliser expect.not
avec ce comparateur pour vous assurer qu'une valeur ne correspond PAS à l'une des options fournies.
toBeTypeOf
- Type :
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
affirme si une valeur réelle est du même type que le type attendu.
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
affirme si une valeur réelle est une instance de la classe reçue.
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
affirme si la valeur réelle est strictement supérieure à celle reçue. Les 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
affirme si la valeur réelle est supérieure ou égale à celle reçue.
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
affirme si la valeur réelle est strictement inférieure à celle reçue. Les 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
affirme si la valeur réelle est inférieure ou égale à celle reçue.
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
affirme si la valeur réelle est égale à la valeur reçue ou, s'il s'agit d'un objet, a la même structure (les compare récursivement). Vous pouvez voir la différence entre toEqual
et toBe
dans cet exemple :
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
Pour les objets Error
, les propriétés non énumérables telles que name
, message
, cause
et AggregateError.errors
sont également comparées. Pour Error.cause
, la comparaison est asymétrique :
// succès
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi'));
// échec
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' }));
Pour tester si quelque chose a été levé, utilisez l'assertion toThrowError
.
toStrictEqual
- Type :
(received: any) => Awaitable<void>
toStrictEqual
affirme si la valeur réelle est égale à la valeur reçue ou, s'il s'agit d'un objet, a la même structure (les compare récursivement), et est du même type.
Différences par rapport à .toEqual
:
- Les clés avec 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
. - La nature 'sparse' (creuse) des tableaux est vérifiée. 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 présente dans un tableau. toContain
peut également vérifier si une chaîne est une sous-chaîne d'une autre chaîne. 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('the fruit list contains orange', () => {
expect(getAllFruits()).toContain('orange');
const element = document.querySelector('#el');
// l'élément a une classe
expect(element.classList).toContain('flex');
// l'élément est à l'intérieur d'un autre
expect(document.querySelector('#wrapper')).toContain(element);
});
toContainEqual
- Type :
(received: any) => Awaitable<void>
toContainEqual
affirme si un élément avec une structure et des valeurs spécifiques est contenu dans un tableau. Il fonctionne comme toEqual
en interne pour chaque élément.
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
affirme si un objet a une propriété .length
et que sa valeur est un nombre spécifique.
import { expect, test } from 'vitest';
test('toHaveLength', () => {
expect('abc').toHaveLength(3);
expect([1, 2, 3]).toHaveLength(3);
expect('').not.toHaveLength(3); // n'a pas une longueur de 3
expect({ length: 3 }).toHaveLength(3);
});
toHaveProperty
- Type :
(key: any, received?: any) => Awaitable<void>
toHaveProperty
affirme si une propriété à la key
fournie existe pour un objet.
Vous pouvez également fournir un argument de valeur optionnel (connu sous le nom d'égalité profonde), similaire au comparateur toEqual
, pour comparer la valeur de la propriété reçue.
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'); // affirme que la clé existe
expect(invoice).toHaveProperty('total_amount', 5000); // affirme que la clé existe et que la valeur est égale
expect(invoice).not.toHaveProperty('account'); // affirme que cette clé n'existe pas
// Référencement profond utilisant la notation par points
expect(invoice).toHaveProperty('customer.first_name');
expect(invoice).toHaveProperty('customer.last_name', 'Doe');
expect(invoice).not.toHaveProperty('customer.location', 'India');
// Référencement profond utilisant un tableau contenant la clé
expect(invoice).toHaveProperty('items[0].type', 'apples');
expect(invoice).toHaveProperty('items.0.type', 'apples'); // la notation par points fonctionne aussi
// Référencement profond utilisant un tableau contenant le chemin de la clé
expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples');
expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // la notation de chaîne fonctionne aussi
// Enveloppez votre clé dans un tableau pour éviter que la clé ne soit analysée comme une référence profonde
expect(invoice).toHaveProperty(['P.O'], '12345');
});
toMatch
- Type :
(received: string | regexp) => Awaitable<void>
toMatch
affirme si une chaîne correspond à une expression régulière ou à une chaîne.
import { expect, test } from 'vitest';
test('top fruits', () => {
expect('top fruits include apple, orange and grape').toMatch(/apple/);
expect('applefruits').toMatch('fruit'); // toMatch accepte aussi une chaîne
});
toMatchObject
- Type :
(received: object | array) => Awaitable<void>
toMatchObject
affirme si un objet correspond à un sous-ensemble des propriétés de l'objet attendu.
Vous pouvez également passer un tableau d'objets. C'est utile si vous voulez vérifier que deux tableaux ont le même nombre d'éléments, par opposition à 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', () => {
// Affirme 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 tester qu'une erreur spécifique est levée :
RegExp
: le message d'erreur correspond au motifstring
: le message d'erreur inclut la sous-chaîneError
,AsymmetricMatcher
: compare avec un objet reçu similaire àtoEqual(received)
TIP
Vous devez envelopper le code dans une fonction, sinon l'erreur ne sera pas interceptée et le test échouera.
Cela ne s'applique pas aux appels asynchrones car rejects gère correctement la promesse :
test('expect rejects toThrow', async ({ expect }) => {
const promise = Promise.reject(new Error('Test'));
await expect(promise).rejects.toThrowError();
});
Par exemple, si nous voulons tester que getFruitStock('pineapples')
lève une erreur, nous pourrions écrire :
import { expect, test } from 'vitest';
function getFruitStock(type: string) {
if (type === 'pineapples') {
throw new Error('Pineapples are not in stock');
}
// Fait d'autres choses
}
test('throws on pineapples', () => {
// Teste que le message d'erreur contient "stock" quelque part : ces deux expressions sont équivalentes
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$/
);
expect(() => getFruitStock('pineapples')).toThrowError(
new Error('Pineapples are not in stock')
);
expect(() => getFruitStock('pineapples')).toThrowError(
expect.objectContaining({
message: 'Pineapples are not in stock',
})
);
});
TIP
Pour tester des fonctions asynchrones, utilisez 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, hint?: string) => void
Ceci garantit qu'une valeur correspond à l'instantané le plus récent.
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 d'un nom d'instantané, de courts indices descriptifs peuvent être plus utiles que des nombres pour différencier plusieurs instantanés dans un seul bloc it
ou test
. Vitest trie les instantanés par nom dans le fichier .snap
correspondant.
TIP
Lorsqu'un instantané ne correspond pas et fait échouer le test, si cette non-correspondance est attendue, vous pouvez appuyer sur la touche u
pour mettre à jour l'instantané une fois. Ou vous pouvez passer les options CLI -u
ou --update
pour que Vitest mette toujours à jour les tests.
import { expect, test } from 'vitest';
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
expect(data).toMatchSnapshot();
});
Vous pouvez également fournir une forme d'objet, si vous testez uniquement la structure d'un objet, et n'avez pas besoin qu'elle soit 100% compatible :
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, hint?: string) => void
Ceci garantit qu'une valeur correspond au dernier instantané.
Vitest ajoute et met à jour l'argument de chaîne inlineSnapshot
au 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 l'instantané
expect(data).toMatchInlineSnapshot(`
{
"foo": Set {
"bar",
"snapshot",
},
}
`);
});
Vous pouvez également fournir une forme d'objet, si vous testez juste une forme d'objet, et n'avez pas besoin qu'elle soit 100% compatible :
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, hint?: string) => Promise<void>
Compare ou met à jour l'instantané avec le contenu d'un fichier explicitement spécifié (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');
});
Notez que puisque les opérations sur le système de fichiers sont asynchrones, vous devez utiliser await
avec toMatchFileSnapshot()
. Si await
n'est pas utilisé, Vitest le traite comme expect.soft
, ce qui signifie que le code après l'instruction continuera à s'exécuter même si l'instantané ne correspond pas. Une fois le test terminé, Vitest vérifiera l'instantané et échouera s'il y a une non-correspondance.
toThrowErrorMatchingSnapshot
- Type :
(hint?: string) => void
Identique à toMatchSnapshot
, mais attend la même valeur que toThrowError
.
toThrowErrorMatchingInlineSnapshot
- Type :
(snapshot?: string, hint?: 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 une fonction espion (mock) comme paramètre de 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 nombre précis de fois. Elle requiert une fonction espion (mock) comme paramètre de 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 une fonction espion (mock) comme paramètre de 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);
});
toHaveBeenCalledBefore 3.0.0+
- Type :
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable<void>
Cette assertion vérifie si un Mock
a été appelé avant un autre Mock
.
test('calls mock1 before mock2', () => {
const mock1 = vi.fn();
const mock2 = vi.fn();
mock1();
mock2();
mock1();
expect(mock1).toHaveBeenCalledBefore(mock2);
});
toHaveBeenCalledAfter 3.0.0+
- Type :
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable<void>
Cette assertion vérifie si un Mock
a été appelé après un autre Mock
.
test('calls mock1 after mock2', () => {
const mock1 = vi.fn();
const mock2 = vi.fn();
mock2();
mock1();
mock2();
expect(mock1).toHaveBeenCalledAfter(mock2);
});
toHaveBeenCalledExactlyOnceWith 3.0.0+
- Type :
(...args: any[]) => Awaitable<void>
Cette assertion vérifie si une fonction a été appelée exactement une fois et avec certains paramètres. Elle requiert une fonction espion (mock) comme paramètre de 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);
expect(buySpy).toHaveBeenCalledExactlyOnceWith('apples', 10);
});
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 une fonction espion (mock) comme paramètre de 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 d'un appel spécifique (N-ième appel). Le compte commence à 1. Ainsi, pour vérifier la deuxième entrée, vous écririez .toHaveBeenNthCalledWith(2, ...)
.
Elle requiert une fonction espion (mock) comme paramètre de 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 correctement renvoyé une valeur au moins une fois (c'est-à-dire qu'elle n'a pas généré d'erreur). Elle requiert une fonction espion (mock) comme paramètre de 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 correctement renvoyé une valeur un nombre exact de fois (c'est-à-dire qu'elle n'a pas généré d'erreur). Elle requiert une fonction espion (mock) comme paramètre de 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>
Cette assertion permet de vérifier si une fonction a correctement renvoyé une valeur avec certains paramètres au moins une fois. Elle requiert une fonction espion (mock) comme paramètre de expect
.
import { expect, test, vi } from 'vitest';
test('spy function returns a product', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
expect(sell).toHaveReturnedWith({ product: 'apples' });
});
toHaveLastReturnedWith
- Type :
(returnValue: any) => Awaitable<void>
Cette assertion permet de vérifier si une fonction a correctement renvoyé une certaine valeur lors de sa dernière invocation. Elle requiert une fonction espion (mock) comme paramètre de expect
.
import { expect, test, vi } from 'vitest';
test('spy function returns bananas on a last call', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveLastReturnedWith({ product: 'bananas' });
});
toHaveNthReturnedWith
- Type :
(time: number, returnValue: any) => Awaitable<void>
Cette assertion permet de vérifier si une fonction a correctement renvoyé une valeur avec certains paramètres lors d'un certain appel. Elle requiert une fonction espion (mock) comme paramètre de expect
.
import { expect, test, vi } from 'vitest';
test('spy function returns bananas on second call', () => {
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 correctement résolu une valeur au moins une fois (c'est-à-dire qu'elle n'a pas échoué). Elle requiert une fonction espion (mock) comme paramètre de expect
.
Si la fonction a renvoyé une promesse, mais qu'elle n'a pas encore été 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('spy function resolved a value', 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 correctement résolu une valeur un nombre exact de fois (c'est-à-dire qu'elle n'a pas échoué). Elle requiert une fonction espion (mock) comme paramètre de expect
.
Cela ne comptera que les promesses résolues. Si la fonction a renvoyé une promesse, mais qu'elle n'a pas encore été résolue, elle ne sera pas comptée.
import { expect, test, vi } from 'vitest';
test('spy function resolved a value two times', 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>
Cette assertion permet de vérifier si une fonction a correctement résolu une certaine valeur au moins une fois. Elle requiert une fonction espion (mock) comme paramètre de expect
.
Si la fonction a renvoyé une promesse, mais qu'elle n'a pas encore été résolue, cela échouera.
import { expect, test, vi } from 'vitest';
test('spy function resolved a product', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }));
await sell('apples');
expect(sell).toHaveResolvedWith({ product: 'apples' });
});
toHaveLastResolvedWith
- Type :
(returnValue: any) => Awaitable<void>
Cette assertion permet de vérifier si une fonction a correctement résolu une certaine valeur lors de sa dernière invocation. Elle requiert une fonction espion (mock) comme paramètre de expect
.
Si la fonction a renvoyé une promesse, mais qu'elle n'a pas encore été résolue, cela échouera.
import { expect, test, vi } from 'vitest';
test('spy function resolves bananas on a last call', 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>
Cette assertion permet de vérifier si une fonction a correctement résolu une certaine valeur lors d'une invocation spécifique. Elle requiert une fonction espion (mock) comme paramètre de expect
.
Si la fonction a renvoyé une promesse, mais qu'elle n'a pas encore été résolue, cela échouera.
import { expect, test, vi } from 'vitest';
test('spy function returns bananas on second call', 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 un certain 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
est destiné à simplifier l'assertion de code asynchrone. Utilisez-le pour extraire la valeur de la promesse en attente et affirmer sa valeur avec les assertions habituelles. Si la promesse est rejetée, l'assertion échouera.
Il renvoie le même objet Assertions
, mais tous les comparateurs renvoient maintenant une Promise
, vous devrez donc l'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 affirmer sa valeur de retour :
import { expect, test } from 'vitest';
async function buyApples() {
return fetch('/buy/apples').then(r => r.json());
}
test('buyApples returns new stock id', async () => {
// toEqual renvoie 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, vous aurez un test faussement positif qui passera à chaque fois. Pour vous assurer que les assertions sont réellement appelées, vous pouvez utiliser expect.assertions(number)
.
Depuis Vitest 3, si une méthode n'est pas attendue, Vitest affichera un avertissement à la fin du test. Dans Vitest 4, le test sera marqué comme "échoué" si l'assertion n'est pas attendue.
rejects
- Type :
Promisify<Assertions>
rejects
est destiné à simplifier l'assertion de code asynchrone. Utilisez-le pour extraire la raison du rejet de la promesse, et affirmer sa valeur avec les assertions habituelles. Si la promesse est résolue avec succès, l'assertion échouera.
Il renvoie le même objet Assertions
, mais tous les comparateurs renvoient maintenant une Promise
, vous devrez donc l'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 affirmer la raison :
import { expect, test } from 'vitest';
async function buyApples(id) {
if (!id) {
throw new Error('no id');
}
}
test('buyApples throws an error when no id provided', async () => {
// toThrow renvoie maintenant une promesse, vous DEVEZ donc l'attendre
await expect(buyApples()).rejects.toThrow('no id');
});
WARNING
Si l'assertion n'est pas attendue, vous aurez un test faussement positif qui passera à chaque fois. Pour vous assurer que les assertions ont été réellement appelées, vous pouvez utiliser expect.assertions(number)
.
Depuis Vitest 3, si une méthode n'est pas attendue, Vitest affichera un avertissement à la fin du test. Dans Vitest 4, le test sera marqué comme "échoué" si l'assertion n'est pas attendue.
expect.assertions
- Type :
(count: number) => void
Une fois le test réussi ou échoué, vérifiez qu'un certain nombre d'assertions ont été appelées pendant un test. Un cas utile serait de vérifier si un code asynchrone a été appelé.
Par exemple, si nous avons une fonction qui appelle de manière asynchrone deux comparateurs, nous pouvons affirmer qu'ils ont été réellement appelés.
import { expect, test } from 'vitest';
async function doAsync(...cbs) {
await Promise.all(cbs.map((cb, index) => cb({ index })));
}
test('all assertions are called', async () => {
expect.assertions(2);
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}
await doAsync(callback1, callback2);
});
WARNING
Lors de l'utilisation des assertions
avec des tests asynchrones concurrents, expect
du Contexte de test local doit être utilisé pour s'assurer que le bon test est détecté.
expect.hasAssertions
- Type :
() => void
Une fois le test réussi ou échoué, vérifiez qu'au moins une assertion a été appelée pendant un test. Un cas utile serait de vérifier si un code asynchrone a été appelé.
Par exemple, si vous avez un code qui appelle un rappel, nous pouvons faire une assertion à l'intérieur d'un rappel, mais le test passera toujours si nous ne vérifions pas qu'une assertion a bien été appelée.
import { expect, test } from 'vitest';
import { db } from './db.js';
const cbs = [];
function onSelect(cb) {
cbs.push(cb);
}
// après avoir sélectionné dans la base de données, nous appelons tous les rappels
function select(id) {
return db.select({ id }).then(data => {
return Promise.all(cbs.map(cb => cb(data)));
});
}
test('callback was called', async () => {
expect.hasAssertions();
onSelect(data => {
// devrait être appelé lors de la sélection
expect(data).toBeTruthy();
});
// si non attendu, le test échouera
// si vous n'avez pas expect.hasAssertions(), le test passera
await select(3);
});
expect.unreachable
- Type :
(message?: string) => never
Cette méthode est utilisée pour affirmer qu'une ligne ne devrait jamais être atteinte.
Par exemple, si nous voulons tester que build()
lève une erreur parce que les répertoires cibles n'ont pas de dossier src
, et aussi 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 fails with "%s"', async dir => {
try {
await build(dir);
expect.unreachable('Should not pass build');
} 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:
// pour épuiser tous les tests d'erreur
expect.unreachable('All error test must be handled');
break;
}
}
});
expect.anything
- Type :
() => any
Ce comparateur asymétrique, lorsqu'il est utilisé avec une vérification d'égalité, renverra toujours true
. Utile si vous souhaitez simplement vous assurer que la propriété existe.
import { expect, test } from 'vitest';
test('object has "apples" key', () => {
expect({ apples: 22 }).toEqual({ apples: expect.anything() });
});
expect.any
- Type :
(constructor: unknown) => any
Ce comparateur asymétrique, lorsqu'il est utilisé avec une vérification d'égalité, renverra true
uniquement si la valeur est une instance d'un constructeur spécifié. Utile si vous avez une valeur générée dynamiquement et que vous souhaitez uniquement vérifier qu'elle est du bon type.
import { expect, test } from 'vitest';
import { generateId } from './generators.js';
test('"id" is a number', () => {
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 (c'est-à-dire, 10 ** -2 / 2)
.
Par exemple, ce test passe avec une précision de 5 chiffres :
test('compare float in object properties', () => {
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
Lorsqu'il est utilisé avec une vérification d'égalité, ce comparateur asymétrique renverra true
si la valeur est un tableau et contient les éléments spécifiés.
import { expect, test } from 'vitest';
test('basket includes 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 comparateur pour inverser la valeur attendue.
expect.objectContaining
- Type :
(expected: any) => any
Lorsqu'il est utilisé avec une vérification d'égalité, ce comparateur asymétrique renverra true
si la valeur a une forme similaire.
import { expect, test } from 'vitest';
test('basket has empire apples', () => {
const basket = {
varieties: [
{
name: 'Empire',
count: 1,
},
],
};
expect(basket).toEqual({
varieties: [expect.objectContaining({ name: 'Empire' })],
});
});
TIP
Vous pouvez utiliser expect.not
avec ce comparateur pour inverser la valeur attendue.
expect.stringContaining
- Type :
(expected: any) => any
Lorsqu'il est utilisé avec une vérification d'égalité, ce comparateur asymétrique renverra true
si la valeur est une chaîne et contient une sous-chaîne spécifiée.
import { expect, test } from 'vitest';
test('variety has "Emp" in its name', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringContaining('Emp'),
count: 1,
});
});
TIP
Vous pouvez utiliser expect.not
avec ce comparateur pour inverser la valeur attendue.
expect.stringMatching
- Type :
(expected: any) => any
Lorsqu'il est utilisé avec une vérification d'égalité, ce comparateur asymétrique renverra true
si la valeur est une chaîne et correspond à une expression régulière.
import { expect, test } from 'vitest';
test('variety ends with "re"', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringMatching(/re$/),
count: 1,
});
});
TIP
Vous pouvez utiliser expect.not
avec ce comparateur pour inverser 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 instantané. 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 à l'intérieur de setupFiles
. Cela affectera chaque instantané.
TIP
Si vous avez déjà utilisé Vue CLI avec Jest, vous voudrez peut-être installer jest-serializer-vue. Sinon, vos instantanés seront enveloppés dans une chaîne, ce qui entraînera l'échappement des "
.
expect.extend
- Type :
(matchers: MatchersObject) => void
Vous pouvez étendre les comparateurs par défaut avec les vôtres. Cette fonction est utilisée pour étendre l'objet comparateurs avec des comparateurs personnalisés.
Lorsque vous définissez des comparateurs de cette manière, vous créez également des comparateurs asymétriques qui peuvent être utilisés comme expect.stringContaining
.
import { expect, test } from 'vitest';
test('custom matchers', () => {
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
Si vous voulez que vos comparateurs apparaissent dans chaque test, vous devez appeler cette méthode à l'intérieur de setupFiles
.
Cette fonction est compatible avec expect.extend
de Jest, donc toute bibliothèque qui l'utilise pour créer des comparateurs 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 global (par exemple : vitest.d.ts
) avec le code ci-dessous :
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 global dans votre tsconfig.json
.
TIP
Si vous voulez en savoir plus, consultez le guide sur l'extension des comparateurs.
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 comparateurs pour vérifier si deux objets sont égaux. Elle 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('custom equality tester', () => {
expect(new AnagramComparator('listen')).toEqual(
new AnagramComparator('silent')
);
});