expect
Následující typy jsou použity v níže uvedených signaturách typů:
type Awaitable<T> = T | PromiseLike<T>;
expect
se používá k vytváření tvrzení. V tomto kontextu jsou assertions
funkce, které lze volat k ověření tvrzení. Vitest ve výchozím nastavení poskytuje chai
tvrzení a také Jest
kompatibilní tvrzení postavená na chai
. Na rozdíl od Jest
Vitest podporuje zprávu jako druhý argument – pokud tvrzení selže, chybová zpráva se bude rovnat této zprávě.
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;
}
Například tento kód tvrdí, že hodnota input
je rovna 2
. Pokud není, tvrzení vyvolá chybu a test selže.
import { expect } from 'vitest';
const input = Math.sqrt(4);
expect(input).to.equal(2); // chai API
expect(input).toBe(2); // jest API
Technicky vzato tento příklad nepoužívá funkci test
, takže v konzoli uvidíte chybu Node.js namísto výstupu Vitest. Chcete-li se dozvědět více o test
, přečtěte si Referenci k Test API.
Také expect
lze použít staticky pro přístup k funkcím matcherů, popsaným později, a dalším souvisejícím funkcím.
WARNING
expect
nemá žádný vliv na testování typů, pokud výraz nemá chybu typu. Pokud chcete Vitest použít jako kontrolu typů, použijte expectTypeOf
nebo assertType
.
soft
- Typ:
ExpectStatic & (actual: any) => Assertions
expect.soft
funguje podobně jako expect
, ale namísto ukončení provádění testu při selhání tvrzení pokračuje v běhu a označí selhání jako selhání testu. Všechny chyby, které se během testu vyskytnou, budou zobrazeny až po dokončení testu.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // označí test jako selhání a pokračuje
expect.soft(1 + 2).toBe(4); // označí test jako selhání a pokračuje
});
// reportér nahlásí obě chyby na konci spuštění
Lze jej také použít s expect
. Pokud tvrzení expect
selže, test bude ukončen a všechny předchozí chyby budou zobrazeny.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // označí test jako selhání a pokračuje
expect(1 + 2).toBe(4); // selže a ukončí test, všechny předchozí chyby budou zobrazeny
expect.soft(1 + 3).toBe(5); // nespustí se
});
WARNING
expect.soft
lze použít pouze uvnitř funkce test
.
poll
interface ExpectPoll extends ExpectStatic {
(actual: () => T, options: { interval; timeout; message }): Promise<
Assertions<T>
>;
}
expect.poll
opakovaně spouští tvrzení, dokud není úspěšné. Můžete nakonfigurovat, kolikrát má Vitest opakovaně spouštět callback expect.poll
nastavením možností interval
a timeout
.
Pokud je uvnitř callbacku expect.poll
vyvolána chyba, Vitest se pokusí znovu, dokud nevyprší časový limit.
import { expect, test } from 'vitest';
test('element exists', async () => {
asyncInjectElement();
await expect.poll(() => document.querySelector('.element')).toBeTruthy();
});
WARNING
expect.poll
činí každé tvrzení asynchronním, takže je třeba na něj čekat (await
). Od Vitest 3, pokud na něj zapomenete čekat, test selže s varováním, abyste tak učinili.
expect.poll
nefunguje s několika matchery:
- Snapshot matchery nejsou podporovány, protože vždy uspějí. Pokud je vaše podmínka nestabilní, zvažte místo toho použití
vi.waitFor
k jejímu vyřešení:
import { expect, vi } from 'vitest';
const flakyValue = await vi.waitFor(() => getFlakyValue());
expect(flakyValue).toMatchSnapshot();
.resolves
a.rejects
nejsou podporovány.expect.poll
již čeká na podmínku, pokud je asynchronní.toThrow
a jeho aliasy nejsou podporovány, protože podmínkaexpect.poll
je vždy vyřešena předtím, než matcher získá hodnotu.
not
Použití not
neguje tvrzení. Například tento kód tvrdí, že hodnota input
není rovna 2
. Pokud je rovna, tvrzení vyvolá chybu a test selže.
import { expect, test } from 'vitest';
const input = Math.sqrt(16);
expect(input).not.to.equal(2); // chai API
expect(input).not.toBe(2); // jest API
toBe
- Typ:
(value: any) => Awaitable<void>
toBe
lze použít k tvrzení, zda jsou primitivní hodnoty stejné nebo zda objekty sdílejí stejnou referenci. Je to ekvivalent volání expect(Object.is(3, 3)).toBe(true)
. Pokud objekty nejsou stejné, ale chcete zkontrolovat, zda jsou jejich struktury identické, můžete použít toEqual
.
Například níže uvedený kód kontroluje, zda má obchodník 13 jablek.
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; // stejná reference
expect(stock).toBe(refStock);
});
S čísly s plovoucí desetinnou čárkou se snažte nepoužívat toBe
. Jelikož JavaScript zaokrouhluje čísla s plovoucí desetinnou čárkou, 0.1 + 0.2
není striktně 0.3
. Pro spolehlivé tvrzení čísel s plovoucí desetinnou čárkou použijte tvrzení toBeCloseTo
.
toBeCloseTo
- Typ:
(value: number, numDigits?: number) => Awaitable<void>
Použijte toBeCloseTo
pro porovnání čísel s plovoucí desetinnou čárkou. Volitelný argument numDigits
omezuje počet číslic, které se mají zkontrolovat za desetinnou čárkou. Například:
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 je 0.30000000000000004
});
test('decimals are rounded to 5 after the point', () => {
// 0.2 + 0.1 je 0.30000 | "000000000004" odstraněno
expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
// nic z 0.30000000000000004 není odstraněno
expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50);
});
toBeDefined
- Typ:
() => Awaitable<void>
toBeDefined
tvrdí, že hodnota není rovna undefined
. Užitečné je zkontrolovat, zda funkce vrátila něco.
import { expect, test } from 'vitest';
function getApples() {
return 3;
}
test('function returned something', () => {
expect(getApples()).toBeDefined();
});
toBeUndefined
- Typ:
() => Awaitable<void>
Opakem toBeDefined
je toBeUndefined
, který tvrdí, že hodnota je rovna undefined
. Užitečné je zkontrolovat, zda funkce nic nevrátila.
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
- Typ:
() => Awaitable<void>
toBeTruthy
tvrdí, že hodnota je pravdivá, když je převedena na boolean. Užitečné, pokud vám nezáleží na konkrétní hodnotě, ale jen chcete vědět, že ji lze převést na true
.
Například, s tímto kódem vám nezáleží na návratové hodnotě stocks.getInfo
– může to být složitý objekt, řetězec nebo cokoli jiného. Kód bude stále fungovat.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (stocks.getInfo('Bill')) {
stocks.sell('apples', 'Bill');
}
Takže pokud chcete otestovat, že stocks.getInfo
bude pravdivé, můžete napsat:
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();
});
V JavaScriptu jsou všechny hodnoty pravdivé, s výjimkou false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
a document.all
.
toBeFalsy
- Typ:
() => Awaitable<void>
toBeFalsy
tvrdí, že hodnota je nepravdivá, když je převedena na boolean. Užitečné, pokud vám nezáleží na konkrétní hodnotě, ale jen chcete vědět, zda ji lze převést na false
.
Například, s tímto kódem vám nezáleží na návratové hodnotě stocks.stockFailed
– může vrátit jakoukoli nepravdivou hodnotu, ale kód bude stále fungovat.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (!stocks.stockFailed('Bill')) {
stocks.sell('apples', 'Bill');
}
Takže pokud chcete otestovat, že stocks.stockFailed
bude nepravdivé, můžete napsat:
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();
});
V JavaScriptu jsou všechny hodnoty pravdivé, s výjimkou false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
a document.all
.
toBeNull
- Typ:
() => Awaitable<void>
toBeNull
jednoduše tvrdí, zda je něco null
. Alias pro .toBe(null)
.
import { expect, test } from 'vitest';
function apples() {
return null;
}
test("we don't have apples", () => {
expect(apples()).toBeNull();
});
toBeNaN
- Typ:
() => Awaitable<void>
toBeNaN
jednoduše tvrdí, zda je něco NaN
. Alias pro .toBe(NaN)
.
import { expect, test } from 'vitest';
let i = 0;
function getApplesCount() {
i++;
return i > 1 ? Number.NaN : i;
}
test('getApplesCount má některé neobvyklé vedlejší účinky...', () => {
expect(getApplesCount()).not.toBeNaN();
expect(getApplesCount()).toBeNaN();
});
toBeOneOf
- Typ:
(sample: Array<any>) => any
toBeOneOf
tvrdí, zda se hodnota shoduje s některou z hodnot v poskytnutém poli.
import { expect, test } from 'vitest';
test('fruit is one of the allowed values', () => {
expect(fruit).toBeOneOf(['apple', 'banana', 'orange']);
});
Asymetrický matcher je obzvláště užitečný při testování volitelných vlastností, které mohou nabývat hodnot null
nebo 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
S tímto matcherem můžete použít expect.not
k negaci očekávané hodnoty.
toBeTypeOf
- Typ:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
tvrdí, zda je skutečná hodnota typu přijatého typu.
import { expect, test } from 'vitest';
const actual = 'stock';
test('stock is type of string', () => {
expect(actual).toBeTypeOf('string');
});
toBeInstanceOf
- Typ:
(c: any) => Awaitable<void>
toBeInstanceOf
tvrdí, zda je skutečná hodnota instancí přijaté třídy.
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
- Typ:
(n: number | bigint) => Awaitable<void>
toBeGreaterThan
tvrdí, zda je skutečná hodnota větší než přijatá. Stejné hodnoty způsobí selhání testu.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have more then 10 apples', () => {
expect(getApples()).toBeGreaterThan(10);
});
toBeGreaterThanOrEqual
- Typ:
(n: number | bigint) => Awaitable<void>
toBeGreaterThanOrEqual
tvrdí, zda je skutečná hodnota větší než přijatá nebo jí rovna.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have 11 apples or more', () => {
expect(getApples()).toBeGreaterThanOrEqual(11);
});
toBeLessThan
- Typ:
(n: number | bigint) => Awaitable<void>
toBeLessThan
tvrdí, zda je skutečná hodnota menší než přijatá. Stejné hodnoty způsobí selhání testu.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have less then 20 apples', () => {
expect(getApples()).toBeLessThan(20);
});
toBeLessThanOrEqual
- Typ:
(n: number | bigint) => Awaitable<void>
toBeLessThanOrEqual
tvrdí, zda je skutečná hodnota menší než přijatá nebo jí rovna.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have 11 apples or less', () => {
expect(getApples()).toBeLessThanOrEqual(11);
});
toEqual
- Typ:
(received: any) => Awaitable<void>
toEqual
tvrdí, zda je skutečná hodnota rovna přijaté nebo má stejnou strukturu, pokud se jedná o objekt (porovnává je rekurzivně). Rozdíl mezi toEqual
a toBe
můžete vidět v tomto příkladu:
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
U objektů Error
se porovnávají také nevýčtové vlastnosti, jako jsou name
, message
, cause
a AggregateError.errors
. U Error.cause
se porovnání provádí asymetricky:
// úspěch
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi'));
// selhání
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' }));
Chcete-li otestovat, zda bylo něco vyvoláno, použijte tvrzení toThrowError
.
toStrictEqual
- Typ:
(received: any) => Awaitable<void>
toStrictEqual
tvrdí, zda je skutečná hodnota rovna přijaté nebo má stejnou strukturu, pokud se jedná o objekt (porovnává je rekurzivně), a stejného typu.
Rozdíly oproti .toEqual
:
- Kontrolují se klíče s
undefined
vlastnostmi. Např.{a: undefined, b: 2}
se neshoduje s{b: 2}
při použití.toStrictEqual
. - Kontroluje se řídkost pole. Např.
[, 1]
se neshoduje s[undefined, 1]
při použití.toStrictEqual
. - Kontroluje se, zda jsou typy objektů stejné. Např. instance třídy s poli
a
ab
se nebude rovnat literálovému objektu s polia
ab
.
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
- Typ:
(received: string) => Awaitable<void>
toContain
tvrdí, zda se skutečná hodnota nachází v poli. toContain
může také zkontrolovat, zda je řetězec podřetězcem jiného řetězce. Pokud spouštíte testy v prostředí podobném prohlížeči, toto tvrzení může také zkontrolovat, zda je třída obsažena v classList
, nebo zda je prvek uvnitř jiného.
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');
// element má třídu
expect(element.classList).toContain('flex');
// element je uvnitř jiného
expect(document.querySelector('#wrapper')).toContain(element);
});
toContainEqual
- Typ:
(received: any) => Awaitable<void>
toContainEqual
tvrdí, zda je položka s konkrétní strukturou a hodnotami obsažena v poli. Funguje jako toEqual
uvnitř pro každý prvek.
import { expect, test } from 'vitest';
import { getFruitStock } from './stocks.js';
test('apple available', () => {
expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 });
});
toHaveLength
- Typ:
(received: number) => Awaitable<void>
toHaveLength
tvrdí, zda má objekt vlastnost .length
a zda je nastavena na určitou číselnou hodnotu.
import { expect, test } from 'vitest';
test('toHaveLength', () => {
expect('abc').toHaveLength(3);
expect([1, 2, 3]).toHaveLength(3);
expect('').not.toHaveLength(3); // nemá .length 3
expect({ length: 3 }).toHaveLength(3);
});
toHaveProperty
- Typ:
(key: any, received?: any) => Awaitable<void>
toHaveProperty
tvrdí, zda vlastnost na poskytnutém referenčním key
existuje pro objekt.
Můžete poskytnout volitelný argument hodnoty, známý také jako hluboká rovnost, podobně jako matcher toEqual
pro porovnání přijaté hodnoty vlastnosti.
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'); // tvrdí, že klíč existuje
expect(invoice).toHaveProperty('total_amount', 5000); // tvrdí, že klíč existuje a hodnota je rovna
expect(invoice).not.toHaveProperty('account'); // tvrdí, že tento klíč neexistuje
// Hluboká reference pomocí tečkové notace
expect(invoice).toHaveProperty('customer.first_name');
expect(invoice).toHaveProperty('customer.last_name', 'Doe');
expect(invoice).not.toHaveProperty('customer.location', 'India');
// Hluboká reference pomocí pole obsahujícího klíč
expect(invoice).toHaveProperty('items[0].type', 'apples');
expect(invoice).toHaveProperty('items.0.type', 'apples'); // tečková notace také funguje
// Hluboká reference pomocí pole obsahujícího cestu klíče
expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples');
expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // řetězcová notace také funguje
// Zabalte klíč do pole, abyste zabránili jeho parsování jako hluboké reference
expect(invoice).toHaveProperty(['P.O'], '12345');
});
toMatch
- Typ:
(received: string | regexp) => Awaitable<void>
toMatch
tvrdí, zda se řetězec shoduje s regulárním výrazem nebo řetězcem.
import { expect, test } from 'vitest';
test('top fruits', () => {
expect('top fruits include apple, orange and grape').toMatch(/apple/);
expect('applefruits').toMatch('fruit'); // toMatch také přijímá řetězec
});
toMatchObject
- Typ:
(received: object | array) => Awaitable<void>
toMatchObject
tvrdí, zda se objekt shoduje s podmnožinou vlastností objektu.
Můžete také předat pole objektů. To je užitečné, pokud chcete zkontrolovat, zda se dvě pole shodují v počtu prvků, na rozdíl od arrayContaining
, které umožňuje extra prvky v přijatém poli.
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', () => {
// Ověřuje, že se pole objektů shoduje
expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([
{ foo: 'bar' },
{ baz: 1 },
]);
});
toThrowError
Typ:
(received: any) => Awaitable<void>
Alias:
toThrow
toThrowError
tvrdí, zda funkce vyvolá chybu, když je volána.
Můžete poskytnout volitelný argument pro testování, zda je vyvolána konkrétní chyba:
RegExp
: chybová zpráva odpovídá vzorustring
: chybová zpráva obsahuje podřetězecError
,AsymmetricMatcher
: porovnání s přijatým objektem podobně jakotoEqual(received)
TIP
Kód je nutné zabalit do funkce, jinak chyba nebude zachycena a test selže.
To neplatí pro asynchronní volání, protože rejects správně rozbalí promise:
test('expect rejects toThrow', async ({ expect }) => {
const promise = Promise.reject(new Error('Test'));
await expect(promise).rejects.toThrowError();
});
Například, pokud chceme otestovat, že getFruitStock('pineapples')
vyvolá chybu, mohli bychom napsat:
import { expect, test } from 'vitest';
function getFruitStock(type: string) {
if (type === 'pineapples') {
throw new Error('Pineapples are not in stock');
}
// Udělejte něco jiného
}
test('throws on pineapples', () => {
// Otestujte, zda chybová zpráva někde obsahuje "stock": tyto jsou ekvivalentní
expect(() => getFruitStock('pineapples')).toThrowError(/stock/);
expect(() => getFruitStock('pineapples')).toThrowError('stock');
// Otestujte přesnou chybovou zprávu
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
Pro testování asynchronních funkcí použijte v kombinaci s rejects.
function getAsyncFruitStock() {
return Promise.reject(new Error('empty'));
}
test('throws on pineapples', async () => {
await expect(() => getAsyncFruitStock()).rejects.toThrowError('empty');
});
toMatchSnapshot
- Typ:
<T>(shape?: Partial<T> | string, hint?: string) => void
Zajišťuje, že hodnota odpovídá nejnovějšímu snímku.
Můžete poskytnout volitelný řetězcový argument hint
, který se připojí k názvu testu. Ačkoli Vitest vždy připojí číslo na konec názvu snímku, krátké popisné nápovědy mohou být užitečnější než čísla pro rozlišení více snímků v rámci jednoho bloku it
nebo test
. Vitest řadí snímky podle názvu v odpovídajícím souboru .snap
.
TIP
Pokud se snímek neshoduje a způsobí selhání testu, a je-li neshoda očekávaná, můžete stisknout klávesu u
pro jednorázovou aktualizaci snímku. Nebo můžete předat volby CLI -u
nebo --update
, aby Vitest vždy aktualizoval testy.
import { expect, test } from 'vitest';
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
expect(data).toMatchSnapshot();
});
Můžete také poskytnout tvar objektu, pokud testujete pouze tvar objektu a nepotřebujete, aby byl 100% kompatibilní:
import { expect, test } from 'vitest';
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
expect(data).toMatchSnapshot({ foo: expect.any(Set) });
});
toMatchInlineSnapshot
- Typ:
<T>(shape?: Partial<T> | string, snapshot?: string, hint?: string) => void
Zajišťuje, že hodnota odpovídá nejnovějšímu snímku.
Vitest přidá a aktualizuje argument inlineSnapshot
(jako řetězec) k matcheru v testovacím souboru (namísto externího souboru .snap
).
import { expect, test } from 'vitest';
test('matches inline snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
// Vitest aktualizuje následující obsah při aktualizaci snímku
expect(data).toMatchInlineSnapshot(`
{
"foo": Set {
"bar",
"snapshot",
},
}
`);
});
Můžete také poskytnout tvar objektu, pokud testujete pouze tvar objektu a nepotřebujete, aby byl 100% kompatibilní:
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
- Typ:
<T>(filepath: string, hint?: string) => Promise<void>
Porovnejte nebo aktualizujte snímek s obsahem explicitně zadaného souboru (namísto souboru .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');
});
Všimněte si, že vzhledem k tomu, že operace se souborovým systémem je asynchronní, musíte s toMatchFileSnapshot()
použít await
. Pokud await
není použit, Vitest to považuje za expect.soft
, což znamená, že kód po příkazu bude pokračovat v běhu, i když se snímek neshoduje. Po dokončení testu Vitest zkontroluje snímek a selže, pokud dojde k neshodě.
toThrowErrorMatchingSnapshot
- Typ:
(hint?: string) => void
Stejné jako toMatchSnapshot
, ale očekává stejnou hodnotu jako toThrowError
.
toThrowErrorMatchingInlineSnapshot
- Typ:
(snapshot?: string, hint?: string) => void
Stejné jako toMatchInlineSnapshot
, ale očekává stejnou hodnotu jako toThrowError
.
toHaveBeenCalled
- Typ:
() => Awaitable<void>
Toto tvrzení je užitečné k ověření, zda byla funkce volána. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
(amount: number) => Awaitable<void>
Toto tvrzení kontroluje, zda byla funkce volána přesně daný početkrát. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
(...args: any[]) => Awaitable<void>
Toto tvrzení kontroluje, zda byla funkce volána s určitými parametry alespoň jednou. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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+
- Typ:
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable<void>
Toto tvrzení kontroluje, zda byl Mock
volán před jiným Mock
objektem.
test('calls mock1 before mock2', () => {
const mock1 = vi.fn();
const mock2 = vi.fn();
mock1();
mock2();
mock1();
expect(mock1).toHaveBeenCalledBefore(mock2);
});
toHaveBeenCalledAfter 3.0.0+
- Typ:
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable<void>
Toto tvrzení kontroluje, zda byl Mock
volán po jiném Mock
objektu.
test('calls mock1 after mock2', () => {
const mock1 = vi.fn();
const mock2 = vi.fn();
mock2();
mock1();
mock2();
expect(mock1).toHaveBeenCalledAfter(mock2);
});
toHaveBeenCalledExactlyOnceWith 3.0.0+
- Typ:
(...args: any[]) => Awaitable<void>
Toto tvrzení kontroluje, zda byla funkce volána přesně jednou a s danými parametry. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
(...args: any[]) => Awaitable<void>
Toto tvrzení kontroluje, zda byla funkce volána s určitými parametry při svém posledním volání. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
(time: number, ...args: any[]) => Awaitable<void>
Toto tvrzení kontroluje, zda byla funkce volána s určitými parametry při konkrétním volání (N-tém volání). Počet začíná na 1. Takže pro kontrolu druhého volání byste napsali .toHaveBeenNthCalledWith(2, ...)
.
Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
() => Awaitable<void>
Toto tvrzení kontroluje, zda funkce úspěšně vrátila hodnotu (tj. nevyvolala chybu) alespoň jednou. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
(amount: number) => Awaitable<void>
Toto tvrzení kontroluje, zda funkce úspěšně vrátila hodnotu (tj. nevyvolala chybu) přesný početkrát. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
(returnValue: any) => Awaitable<void>
Toto tvrzení můžete volat pro kontrolu, zda funkce úspěšně vrátila hodnotu s určitými parametry alespoň jednou. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
(returnValue: any) => Awaitable<void>
Toto tvrzení můžete volat pro kontrolu, zda funkce úspěšně vrátila určitou hodnotu při svém posledním volání. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
(time: number, returnValue: any) => Awaitable<void>
Toto tvrzení můžete volat pro kontrolu, zda funkce úspěšně vrátila hodnotu s určitými parametry při konkrétním volání. Vyžaduje, aby expect
pracoval se špionážní funkcí.
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
- Typ:
() => Awaitable<void>
Toto tvrzení kontroluje, zda funkce úspěšně vyřešila hodnotu (tj. neodmítla) alespoň jednou. Vyžaduje, aby expect
pracoval se špionážní funkcí.
Pokud funkce vrátila promise, která ještě nebyla vyřešena, toto selže.
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
- Typ:
(amount: number) => Awaitable<void>
Toto tvrzení kontroluje, zda funkce úspěšně vyřešila hodnotu (tj. neodmítla) přesný početkrát. Vyžaduje, aby expect
pracoval se špionážní funkcí.
Toto bude počítat pouze promises, které byly vyřešeny. Pokud funkce vrátila promise, která ještě nebyla vyřešena, nebude započítána.
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
- Typ:
(returnValue: any) => Awaitable<void>
Toto tvrzení můžete volat pro kontrolu, zda funkce úspěšně vyřešila určitou hodnotu alespoň jednou. Vyžaduje, aby expect
pracoval se špionážní funkcí.
Pokud funkce vrátila promise, která ještě nebyla vyřešena, toto selže.
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
- Typ:
(returnValue: any) => Awaitable<void>
Toto tvrzení můžete volat pro kontrolu, zda funkce úspěšně vyřešila určitou hodnotu při svém posledním volání. Vyžaduje, aby expect
pracoval se špionážní funkcí.
Pokud funkce vrátila promise, která ještě nebyla vyřešena, toto selže.
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
- Typ:
(time: number, returnValue: any) => Awaitable<void>
Toto tvrzení můžete volat pro kontrolu, zda funkce úspěšně vyřešila hodnotu s určitými parametry při konkrétním volání. Vyžaduje, aby expect
pracoval se špionážní funkcí.
Pokud funkce vrátila promise, která ještě nebyla vyřešena, toto selže.
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
- Typ:
(predicate: (value: any) => boolean) => Awaitable<void>
Toto tvrzení kontroluje, zda hodnota splňuje určitý predikát.
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
- Typ:
Promisify<Assertions>
resolves
je určen k odstranění boilerplate kódu při tvrzení asynchronního kódu. Použijte jej k rozbalení hodnoty z čekající promise a ověření její hodnoty pomocí obvyklých tvrzení. Pokud promise odmítne, tvrzení selže.
Vrací stejný objekt Assertions
, ale všechny matchery nyní vracejí Promise
, takže je nutné na ně čekat (await
). Funguje také s tvrzeními chai
.
Například, pokud máte funkci, která provádí volání API a vrací nějaká data, můžete použít tento kód k tvrzení její návratové hodnoty:
import { expect, test } from 'vitest';
async function buyApples() {
return fetch('/buy/apples').then(r => r.json());
}
test('buyApples returns new stock id', async () => {
// toEqual nyní vrací promise, takže MUSÍTE na ni čekat
await expect(buyApples()).resolves.toEqual({ id: 1 }); // jest API
await expect(buyApples()).resolves.to.equal({ id: 1 }); // chai API
});
WARNING
Pokud na tvrzení nečekáte (await
), pak budete mít falešně pozitivní test, který vždy projde. Abyste se ujistili, že tvrzení byla skutečně provedena, můžete použít expect.assertions(number)
.
Od Vitest 3, pokud se na metodu nečeká, Vitest zobrazí varování na konci testu. Ve Vitest 4 bude test označen jako "selhal", pokud se na tvrzení nečeká.
rejects
- Typ:
Promisify<Assertions>
rejects
je určen k odstranění boilerplate kódu při tvrzení asynchronního kódu. Použijte jej k rozbalení důvodu, proč byla promise odmítnuta, a ověření její hodnoty pomocí obvyklých tvrzení. Pokud se promise úspěšně vyřeší, tvrzení selže.
Vrací stejný objekt Assertions
, ale všechny matchery nyní vracejí Promise
, takže je nutné na ně čekat (await
). Funguje také s tvrzeními chai
.
Například, pokud máte funkci, která selže, když ji zavoláte, můžete použít tento kód k tvrzení důvodu:
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 nyní vrací promise, takže MUSÍTE na ni čekat
await expect(buyApples()).rejects.toThrow('no id');
});
WARNING
Pokud na tvrzení nečekáte (await
), pak budete mít falešně pozitivní test, který vždy projde. Abyste se ujistili, že tvrzení byla skutečně provedena, můžete použít expect.assertions(number)
.
Od Vitest 3, pokud se na metodu nečeká, Vitest zobrazí varování na konci testu. Ve Vitest 4 bude test označen jako "selhal", pokud se na tvrzení nečeká.
expect.assertions
- Typ:
(count: number) => void
Po úspěšném nebo neúspěšném testu ověřte, že během testu byl proveden určitý počet tvrzení. Užitečné je zkontrolovat, zda byl volán asynchronní kód.
Například, pokud máme funkci, která asynchronně volá dva matchery, můžeme tvrdit, že byly skutečně volány.
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
Při použití assertions
s asynchronními souběžnými testy musí být použit expect
z lokálního Test Contextu, aby se zajistilo, že je správně detekován test.
expect.hasAssertions
- Typ:
() => void
Po úspěšném nebo neúspěšném testu ověřte, že během testu bylo voláno alespoň jedno tvrzení. Užitečné je zkontrolovat, zda byl volán asynchronní kód.
Například, pokud máte kód, který volá callback, můžeme provést tvrzení uvnitř callbacku, ale test vždy projde, pokud nezkontrolujeme, zda bylo tvrzení provedeno.
import { expect, test } from 'vitest';
import { db } from './db.js';
const cbs = [];
function onSelect(cb) {
cbs.push(cb);
}
// po výběru z db voláme všechny callbacky
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 => {
// mělo by být voláno při výběru
expect(data).toBeTruthy();
});
// if not awaited, test will fail
// if you don't have expect.hasAssertions(), test will pass
await select(3);
});
expect.unreachable
- Typ:
(message?: string) => never
Tato metoda se používá k tvrzení, že daný řádek kódu by nikdy neměl být dosažen.
Například, pokud chceme otestovat, že build()
vyvolá chybu, protože cílové adresáře nemají složku src
, a také zpracovat každou chybu samostatně, mohli bychom to udělat takto:
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'); // Nemělo by projít sestavením
} 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:
// pro vyčerpání všech chybových testů
expect.unreachable('All error test must be handled');
break;
}
}
});
expect.anything
- Typ:
() => any
Tento asymetrický matcher, pokud je použit při kontrole rovnosti, vždy vrátí true
. Užitečné, pokud si jen chcete být jisti existencí vlastnosti.
import { expect, test } from 'vitest';
test('object has "apples" key', () => {
expect({ apples: 22 }).toEqual({ apples: expect.anything() });
});
expect.any
- Typ:
(constructor: unknown) => any
Tento asymetrický matcher, pokud je použit při kontrole rovnosti, vrátí true
pouze v případě, že hodnota je instancí zadaného konstruktoru. Užitečné, pokud máte hodnotu, která je generována pokaždé, a chcete pouze vědět, že existuje a má správný typ.
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
- Typ:
(expected: any, precision?: number) => any
expect.closeTo
je užitečné při porovnávání čísel s plovoucí desetinnou čárkou ve vlastnostech objektů nebo prvcích polí. Pokud potřebujete porovnat číslo, použijte místo toho .toBeCloseTo
.
Volitelný argument precision
omezuje počet číslic, které se mají zkontrolovat za desetinnou čárkou. Pro výchozí hodnotu 2
je kritériem testu Math.abs(expected - received) < 0.005 (tj. 10 ** -2 / 2)
.
Například tento test projde s přesností 5 číslic:
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
- Typ:
<T>(expected: T[]) => any
Při použití s kontrolou rovnosti tento asymetrický matcher vrátí true
, pokud je hodnota pole a obsahuje zadané položky.
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
S tímto matcherem můžete použít expect.not
k negaci očekávané hodnoty.
expect.objectContaining
- Typ:
(expected: any) => any
Při použití s kontrolou rovnosti tento asymetrický matcher vrátí true
, pokud má hodnota podobný tvar.
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
S tímto matcherem můžete použít expect.not
k negaci očekávané hodnoty.
expect.stringContaining
- Typ:
(expected: any) => any
Při použití s kontrolou rovnosti tento asymetrický matcher vrátí true
, pokud je hodnota řetězec a obsahuje zadaný podřetězec.
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
S tímto matcherem můžete použít expect.not
k negaci očekávané hodnoty.
expect.stringMatching
- Typ:
(expected: any) => any
Při použití s kontrolou rovnosti tento asymetrický matcher vrátí true
, pokud je hodnota řetězec a obsahuje zadaný podřetězec nebo pokud se řetězec shoduje s regulárním výrazem.
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
S tímto matcherem můžete použít expect.not
k negaci očekávané hodnoty.
expect.addSnapshotSerializer
- Typ:
(plugin: PrettyFormatPlugin) => void
Tato metoda přidává vlastní serializátory, které se volají při vytváření snímku. Jedná se o pokročilou funkci. Pokud se chcete dozvědět více, přečtěte si průvodce vlastními serializátory.
Pokud přidáváte vlastní serializátory, doporučuje se tuto metodu volat uvnitř setupFiles
. To ovlivní každý snímek.
TIP
Pokud jste dříve používali Vue CLI s Jestem, možná budete chtít nainstalovat jest-serializer-vue. Jinak budou vaše snímky zabaleny do řetězce, což povede k escapování "
."
expect.extend
- Typ:
(matchers: MatchersObject) => void
Výchozí matchery můžete rozšířit o své vlastní. Tato funkce se používá k rozšíření objektu matcherů o vlastní matchery.
Když takto definujete matchery, vytvoříte také asymetrické matchery, které lze použít podobně jako 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
Pokud chcete, aby se vaše matchery objevily v každém testu, doporučuje se tuto metodu volat uvnitř setupFiles
.
Tato funkce je kompatibilní s expect.extend
z Jesta, takže jakákoli knihovna, která ji používá k vytváření vlastních matcherů, bude fungovat s Vitestem.
Pokud používáte TypeScript, od Vitest 0.31.0 můžete rozšířit výchozí rozhraní Assertion
v souboru s globální deklarací (např. vitest.d.ts
) pomocí níže uvedeného kódu:
interface CustomMatchers<R = unknown> {
toBeFoo: () => R;
}
declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}
WARNING
Nezapomeňte zahrnout soubor s globální deklarací do vašeho tsconfig.json
.
TIP
Pokud se chcete dozvědět více, podívejte se na průvodce rozšířením matcherů.
expect.addEqualityTesters
- Typ:
(tester: Array<Tester>) => void
Tuto metodu můžete použít k definování vlastních testerů, což jsou metody, které matchery používají k testování, zda jsou dva objekty stejné. Je kompatibilní s expect.addEqualityTesters
z Jesta.
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')
);
});