expect
Poniższe typy są używane w sygnaturach typów poniżej:
type Awaitable<T> = T | PromiseLike<T>;
expect
służy do tworzenia asercji. W tym kontekście, asercje
to funkcje, które wywołuje się, aby potwierdzić określone założenie. Vitest domyślnie udostępnia asercje chai
, a także asercje kompatybilne z Jest
, zbudowane w oparciu o chai
.
Na przykład, poniższy kod sprawdza, czy wartość input
jest równa 2
. Jeśli tak nie jest, asercja zgłosi błąd, a test zakończy się niepowodzeniem.
import { expect } from 'vitest';
const input = Math.sqrt(4);
expect(input).to.equal(2); // API chai
expect(input).toBe(2); // API Jest
Technicznie, ten przykład nie używa funkcji test
, więc w konsoli zobaczysz błąd Node.js zamiast wyniku Vitest. Aby dowiedzieć się więcej o test
, przeczytaj Dokumentację API Testu.
Ponadto, expect
może być używany statycznie, aby uzyskać dostęp do funkcji dopasowujących (ang. matchers), opisanych w dalszej części dokumentu.
WARNING
expect
nie ma wpływu na testowanie typów, jeśli wyrażenie nie zawiera błędu typu. Jeśli chcesz używać Vitest do sprawdzania typów, użyj expectTypeOf
lub assertType
.
soft
- Typ:
ExpectStatic & (actual: any) => Assertions
expect.soft
działa podobnie do expect
, ale zamiast przerywać wykonanie testu po nieudanej asercji, kontynuuje działanie i oznacza niepowodzenie jako błąd testowy. Wszystkie błędy napotkane podczas testu zostaną wyświetlone po jego zakończeniu.
import { expect, test } from 'vitest';
test('test expect.soft', () => {
expect.soft(1 + 1).toBe(3); // oznacz test jako nieudany i kontynuuj jego wykonanie
expect.soft(1 + 2).toBe(4); // oznacz test jako nieudany i kontynuuj jego wykonanie
});
// Po zakończeniu testu zostaną wyświetlone powyższe błędy.
Można go również używać w połączeniu z expect
. Jeśli asercja expect
zakończy się niepowodzeniem, test zostanie przerwany, a wszystkie dotychczasowe błędy zostaną wyświetlone.
import { expect, test } from 'vitest';
test('test expect.soft', () => {
expect.soft(1 + 1).toBe(3); // oznacz test jako nieudany i kontynuuj jego wykonanie
expect(1 + 2).toBe(4); // niepowodzenie, co skutkuje przerwaniem testu, wszystkie poprzednie błędy zostaną wyświetlone
expect.soft(1 + 3).toBe(5); // nie zostanie uruchomiony
});
WARNING
expect.soft
może być używany tylko wewnątrz funkcji test
.
not
Użycie not
neguje asercję. Na przykład, poniższy kod sprawdza, czy wartość input
nie jest równa 2
. Jeśli jest równa, asercja zgłosi błąd, a test zakończy się niepowodzeniem.
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
- Typ:
(value: any) => Awaitable<void>
toBe
może być używane do potwierdzenia, czy prymitywy są równe, lub czy obiekty wskazują na to samo miejsce w pamięci (referencję). Jest to odpowiednik wywołania expect(Object.is(3, 3)).toBe(true)
. Jeśli obiekty nie są takie same, ale chcesz sprawdzić, czy ich struktury są identyczne, możesz użyć toEqual
.
Na przykład, poniższy kod sprawdza, czy magazyn ma 13 jabłek.
import { expect, test } from 'vitest';
const stock = {
type: 'apples',
count: 13,
};
test('stock ma 13 jabłek', () => {
expect(stock.type).toBe('apples');
expect(stock.count).toBe(13);
});
test('`stock` i `refStock` wskazują na ten sam obiekt', () => {
const refStock = stock; // to samo odniesienie
expect(stock).toBe(refStock);
});
Zaleca się unikanie używania toBe
z liczbami zmiennoprzecinkowymi. Ponieważ JavaScript je zaokrągla, 0.1 + 0.2
nie jest ściśle 0.3
. Aby niezawodnie potwierdzać liczby zmiennoprzecinkowe, użyj asercji toBeCloseTo
.
toBeCloseTo
- Typ:
(value: number, numDigits?: number) => Awaitable<void>
Użyj toBeCloseTo
do porównywania liczb zmiennoprzecinkowych. Opcjonalny argument numDigits
określa liczbę cyfr po przecinku, które mają być uwzględnione w porównaniu. Na przykład:
import { expect, test } from 'vitest';
test.fails('liczby dziesiętne w JavaScript nie są równe', () => {
expect(0.2 + 0.1).toBe(0.3); // 0.2 + 0.1 to 0.30000000000000004
});
test('liczby dziesiętne są zaokrąglane do 5 miejsc po przecinku', () => {
// 0.2 + 0.1 to 0.30000 | "000000000004" usunięte
expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
// nic z 0.30000000000000004 nie jest usuwane
expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50);
});
toBeDefined
- Typ:
() => Awaitable<void>
toBeDefined
potwierdza, że wartość nie jest równa undefined
. Przykładem użycia może być sprawdzenie, czy funkcja zwróciła jakąkolwiek wartość.
import { expect, test } from 'vitest';
function getApples() {
return 3;
}
test('funkcja coś zwróciła', () => {
expect(getApples()).toBeDefined();
});
toBeUndefined
- Typ:
() => Awaitable<void>
Przeciwieństwo toBeDefined
, toBeUndefined
potwierdza, że wartość jest równa undefined
. Przykładem użycia może być sprawdzenie, czy funkcja niczego nie zwróciła.
import { expect, test } from 'vitest';
function getApplesFromStock(stock: string) {
if (stock === 'Bill') return 13;
}
test("Funkcja `getApplesFromStock('Mary')` zwraca `undefined`", () => {
expect(getApplesFromStock('Mary')).toBeUndefined();
});
toBeTruthy
- Typ:
() => Awaitable<void>
toBeTruthy
potwierdza, że wartość jest prawdziwa (truthy) po przekonwertowaniu na typ boolean. Przydatne, jeśli nie zależy Ci na konkretnej wartości, ale chcesz wiedzieć, czy można ją przekonwertować na true
.
Na przykład, mając ten kod, nie zależy Ci na wartości zwracanej przez stocks.getInfo
- może to być złożony obiekt, tekst lub cokolwiek innego. Kod nadal będzie działał.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (stocks.getInfo('Bill')) stocks.sell('apples', 'Bill');
Zatem, aby przetestować, czy stocks.getInfo
zwróci wartość truthy, możesz napisać:
import { expect, test } from 'vitest';
import { Stocks } from './stocks.js';
const stocks = new Stocks();
test('jeśli znamy stan magazynowy Billa, sprzedaj mu jabłka', () => {
stocks.sync('Bill');
expect(stocks.getInfo('Bill')).toBeTruthy();
});
W JavaScript wszystkie wartości są truthy z wyjątkiem: false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
i document.all
.
toBeFalsy
- Typ:
() => Awaitable<void>
toBeFalsy
potwierdza, że wartość jest fałszywa (falsy) po przekonwertowaniu na typ boolean. Przydatne, jeśli nie zależy Ci na konkretnej wartości, ale chcesz wiedzieć, czy można ją przekonwertować na false
.
Na przykład, mając ten kod, nie zależy Ci na wartości zwracanej przez stocks.stockFailed
- może zwrócić dowolną wartość fałszywą (falsy), ale kod nadal będzie działał.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (!stocks.stockFailed('Bill')) stocks.sell('apples', 'Bill');
Zatem, aby przetestować, czy stocks.stockFailed
zwróci wartość falsy, możesz napisać:
import { expect, test } from 'vitest';
import { Stocks } from './stocks.js';
const stocks = new Stocks();
test("jeśli funkcja `stocks.stockFailed('Bill')` zwróci wartość *falsy*, sprzedaj mu jabłka", () => {
stocks.syncStocks('Bill');
expect(stocks.stockFailed('Bill')).toBeFalsy();
});
W JavaScript wszystkie wartości są truthy z wyjątkiem: false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
i document.all
.
toBeNull
- Typ:
() => Awaitable<void>
toBeNull
po prostu potwierdza, czy coś jest null
. Alias dla .toBe(null)
.
import { expect, test } from 'vitest';
function apples() {
return null;
}
test('nie mamy jabłek', () => {
expect(apples()).toBeNull();
});
toBeNaN
- Typ:
() => Awaitable<void>
toBeNaN
po prostu potwierdza, czy coś jest NaN
. Alias dla .toBe(NaN)
.
import { expect, test } from 'vitest';
let i = 0;
function getApplesCount() {
i++;
return i > 1 ? Number.NaN : i;
}
test('Funkcja `getApplesCount` ma pewne nietypowe efekty uboczne...', () => {
expect(getApplesCount()).not.toBeNaN();
expect(getApplesCount()).toBeNaN();
});
toBeTypeOf
- Typ:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
potwierdza, czy rzeczywista wartość jest typu, który został przekazany.
import { expect, test } from 'vitest';
const actual = 'stock';
test('stock jest typu string', () => {
expect(actual).toBeTypeOf('string');
});
toBeInstanceOf
- Typ:
(c: any) => Awaitable<void>
toBeInstanceOf
potwierdza, czy rzeczywista wartość jest instancją otrzymanej klasy.
import { expect, test } from 'vitest';
import { Stocks } from './stocks.js';
const stocks = new Stocks();
test('`stocks` jest instancją klasy `Stocks`', () => {
expect(stocks).toBeInstanceOf(Stocks);
});
toBeGreaterThan
- Typ:
(n: number | bigint) => Awaitable<void>
toBeGreaterThan
potwierdza, czy rzeczywista wartość jest większa niż otrzymana. Równe wartości spowodują niepowodzenie testu.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('funkcja `getApples()` zwraca wartość większą niż 10', () => {
expect(getApples()).toBeGreaterThan(10);
});
toBeGreaterThanOrEqual
- Typ:
(n: number | bigint) => Awaitable<void>
toBeGreaterThanOrEqual
potwierdza, czy rzeczywista wartość jest większa lub równa otrzymanej.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('funkcja `getApples()` zwraca wartość równą lub większą niż 11', () => {
expect(getApples()).toBeGreaterThanOrEqual(11);
});
toBeLessThan
- Typ:
(n: number | bigint) => Awaitable<void>
toBeLessThan
potwierdza, czy rzeczywista wartość jest mniejsza niż otrzymana. Równe wartości spowodują niepowodzenie testu.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('funkcja `getApples()` zwraca wartość mniejszą niż 20', () => {
expect(getApples()).toBeLessThan(20);
});
toBeLessThanOrEqual
- Typ:
(n: number | bigint) => Awaitable<void>
toBeLessThanOrEqual
potwierdza, czy rzeczywista wartość jest mniejsza lub równa otrzymanej.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('funkcja `getApples()` zwraca wartość równą lub mniejszą niż 11', () => {
expect(getApples()).toBeLessThanOrEqual(11);
});
toEqual
- Typ:
(received: any) => Awaitable<void>
toEqual
potwierdza, czy rzeczywista wartość jest równa otrzymanej, lub czy ma taką samą strukturę, jeśli jest obiektem (porównuje je rekurencyjnie). Możesz zobaczyć różnicę między toEqual
i toBe
w tym przykładzie:
import { expect, test } from 'vitest';
const stockBill = {
type: 'apples',
count: 13,
};
const stockMary = {
type: 'apples',
count: 13,
};
test('`stockBill` i `stockMary` mają te same właściwości i wartości', () => {
expect(stockBill).toEqual(stockMary);
});
test('`stockBill` i `stockMary` nie wskazują na ten sam obiekt', () => {
expect(stockBill).not.toBe(stockMary);
});
WARNING
Głębokie porównanie równości nie zostanie wykonane dla obiektów Error
. Do porównania równości brana jest pod uwagę tylko właściwość message
obiektu Error. Aby dostosować porównanie równości i sprawdzić inne właściwości niż message
, użyj expect.addEqualityTesters
. Aby sprawdzić, czy coś zostało rzucone, użyj asercji toThrowError
.
toStrictEqual
- Typ:
(received: any) => Awaitable<void>
toStrictEqual
potwierdza, czy rzeczywista wartość jest równa otrzymanej, lub czy ma taką samą strukturę, jeśli jest obiektem (porównuje je rekurencyjnie) i jest tego samego typu.
Różnice w porównaniu z .toEqual
:
- Sprawdzane są klucze z właściwościami
undefined
. Na przykład,{a: undefined, b: 2}
nie pasuje do{b: 2}
podczas używania.toStrictEqual
. - Sprawdzana jest, czy tablica jest rzadka (ang. sparseness). Na przykład,
[, 1]
nie pasuje do[undefined, 1]
podczas używania.toStrictEqual
. - Sprawdzane jest, czy typy obiektów są równe. Na przykład, instancja klasy z polami
a
ib
nie będzie równa literałowi obiektu z polamia
ib
.
import { expect, test } from 'vitest';
class Stock {
constructor(type) {
this.type = type;
}
}
test('mają identyczną strukturę, ale reprezentują różne typy', () => {
expect(new Stock('apples')).toEqual({ type: 'apples' });
expect(new Stock('apples')).not.toStrictEqual({ type: 'apples' });
});
toContain
- Typ:
(received: string) => Awaitable<void>
toContain
sprawdza, czy rzeczywista wartość znajduje się w tablicy. toContain
może również sprawdzić, czy ciąg znaków jest podciągiem innego ciągu znaków. Od Vitest 1.0, jeśli uruchamiasz testy w środowisku przypominającym przeglądarkę, ta asercja może również sprawdzić, czy klasa znajduje się w classList
, lub czy element znajduje się wewnątrz innego elementu.
import { expect, test } from 'vitest';
import { getAllFruits } from './stocks.js';
test('lista owoców zawiera orange', () => {
expect(getAllFruits()).toContain('orange');
const element = document.querySelector('#el');
// element ma klasę
expect(element.classList).toContain('flex');
// element znajduje się wewnątrz innego elementu
expect(document.querySelector('#wrapper')).toContain(element);
});
toContainEqual
- Typ:
(received: any) => Awaitable<void>
toContainEqual
potwierdza, czy element o określonej strukturze i wartościach znajduje się w tablicy. Działa jak toEqual
dla każdego elementu tablicy.
import { expect, test } from 'vitest';
import { getFruitStock } from './stocks.js';
test("tablica zwracana przez `getFruitStock()` zawiera obiekt `{ fruit: 'apple', count: 5 }`", () => {
expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 });
});
toHaveLength
- Typ:
(received: number) => Awaitable<void>
toHaveLength
potwierdza, czy obiekt ma właściwość .length
i czy jest ona ustawiona na określoną wartość liczbową.
import { expect, test } from 'vitest';
test('toHaveLength', () => {
expect('abc').toHaveLength(3);
expect([1, 2, 3]).toHaveLength(3);
expect('').not.toHaveLength(3); // właściwość `.length` nie ma wartości 3
expect({ length: 3 }).toHaveLength(3);
});
toHaveProperty
- Typ:
(key: any, received?: any) => Awaitable<void>
toHaveProperty
sprawdza, czy obiekt posiada właściwość o podanym kluczu key
.
Opcjonalnie, możesz podać argument received
(wartość), aby sprawdzić, czy wartość właściwości jest głęboko równa (ang. deep equality) podanej wartości, podobnie jak w przypadku matchera toEqual
.
import { expect, test } from 'vitest';
const invoice = {
isActive: true,
'P.O': '12345',
customer: {
first_name: 'John',
last_name: 'Doe',
location: 'China',
},
total_amount: 5000,
items: [
{
type: 'apples',
quantity: 10,
},
{
type: 'oranges',
quantity: 5,
},
],
};
test('John Doe Invoice', () => {
expect(invoice).toHaveProperty('isActive'); // Sprawdź, czy klucz istnieje
expect(invoice).toHaveProperty('total_amount', 5000); // Sprawdź, czy klucz istnieje i czy wartość jest równa
expect(invoice).not.toHaveProperty('account'); // Sprawdź, czy klucz nie istnieje
// Dostęp do zagnieżdżonych właściwości za pomocą notacji kropkowej
expect(invoice).toHaveProperty('customer.first_name');
expect(invoice).toHaveProperty('customer.last_name', 'Doe');
expect(invoice).not.toHaveProperty('customer.location', 'India');
// Dostęp do elementów tablicy za pomocą notacji tablicowej
expect(invoice).toHaveProperty('items[0].type', 'apples');
expect(invoice).toHaveProperty('items.0.type', 'apples'); // Notacja kropkowa również działa
// Dostęp do elementów tablicy za pomocą tablicy kluczy
expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples');
expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // Notacja tekstowa również działa
// Użyj tablicy, aby uniknąć interpretacji klucza jako ścieżki do zagnieżdżonej właściwości
expect(invoice).toHaveProperty(['P.O'], '12345');
});
toMatch
- Typ:
(received: string | regexp) => Awaitable<void>
toMatch
sprawdza, czy łańcuch znaków pasuje do wyrażenia regularnego lub innego łańcucha znaków.
import { expect, test } from 'vitest';
test('top fruits', () => {
expect('top fruits include apple, orange and grape').toMatch(/apple/);
expect('applefruits').toMatch('fruit'); // toMatch akceptuje również argument typu string
});
toMatchObject
- Typ:
(received: object | array) => Awaitable<void>
toMatchObject
sprawdza, czy obiekt pasuje do podzbioru właściwości innego obiektu. Innymi słowy, sprawdza, czy received
zawiera wszystkie właściwości i wartości z obiektu oczekiwanego.
Możesz również przekazać tablicę obiektów. Jest to przydatne, gdy chcesz sprawdzić, czy dwie tablice mają pasującą liczbę elementów i zawartość, w przeciwieństwie do arrayContaining
, które dopuszcza dodatkowe elementy w tablicy received
.
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', () => {
// Sprawdź, czy tablica obiektów pasuje
expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([
{ foo: 'bar' },
{ baz: 1 },
]);
});
toThrowError
Typ:
(received: any) => Awaitable<void>
Alias:
toThrow
toThrowError
sprawdza, czy funkcja rzuca błąd podczas wywołania.
Możesz podać opcjonalny argument, aby sprawdzić, czy zgłoszony błąd spełnia określone kryteria:
- wyrażenie regularne: komunikat błędu pasuje do wzorca.
- łańcuch znaków: komunikat błędu zawiera podany łańcuch.
TIP
Kod, który ma być testowany pod kątem rzucania błędów, musi być wywoływany wewnątrz funkcji. W przeciwnym razie błąd nie zostanie przechwycony, a test zakończy się niepowodzeniem.
Przykład: aby sprawdzić, czy getFruitStock('pineapples')
rzuca błędem:
import { expect, test } from 'vitest';
function getFruitStock(type: string) {
if (type === 'pineapples') throw new Error('Pineapples are not in stock');
// Zrób coś innego
}
test('throws on pineapples', () => {
// Sprawdź, czy komunikat o błędzie zawiera słowo "stock" (równoważne):
expect(() => getFruitStock('pineapples')).toThrowError(/stock/);
expect(() => getFruitStock('pineapples')).toThrowError('stock');
// Sprawdź dokładny komunikat o błędzie
expect(() => getFruitStock('pineapples')).toThrowError(
/^Pineapples are not in stock$/
);
});
TIP
Do testowania funkcji asynchronicznych użyj w połączeniu z 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, message?: string) => void
Sprawdza, czy wartość pasuje do ostatniej zapisanej migawki.
Możesz podać opcjonalny argument message
(łańcuch znaków), który zostanie dołączony do nazwy testu. Vitest zawsze dodaje numer na końcu nazwy migawki, ale krótkie opisy mogą być bardziej przydatne niż numery do rozróżniania wielu migawek w jednym bloku it
lub test
. Vitest sortuje migawki alfabetycznie w pliku .snap
.
TIP
Jeśli migawka nie pasuje, a test zakończy się niepowodzeniem, a niezgodność jest zamierzona, możesz nacisnąć klawisz u
, aby jednorazowo zaktualizować migawkę. Możesz też użyć opcji wiersza poleceń -u
lub --update
, aby Vitest zawsze aktualizował migawki.
import { expect, test } from 'vitest';
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
expect(data).toMatchSnapshot();
});
Możesz również podać strukturę obiektu, jeśli testujesz tylko strukturę i nie potrzebujesz 100% zgodności:
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, message?: string) => void
Sprawdza, czy wartość pasuje do ostatniej zapisanej migawki inline.
Vitest dodaje i aktualizuje argument snapshot
(łańcuch znaków) bezpośrednio w pliku testowym (zamiast w zewnętrznym pliku .snap
).
import { expect, test } from 'vitest';
test('matches inline snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
// Vitest zaktualizuje poniższą zawartość podczas aktualizacji migawki
expect(data).toMatchInlineSnapshot(`
{
"foo": Set {
"bar",
"snapshot",
},
}
`);
});
Możesz również podać strukturę obiektu, jeśli testujesz tylko strukturę i nie potrzebujesz 100% zgodności:
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 0.30.0+
- Typ:
<T>(filepath: string, message?: string) => Promise<void>
Porównuje lub aktualizuje migawkę z zawartością pliku o określonej ścieżce (zamiast pliku .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');
});
Ponieważ operacje na systemie plików są asynchroniczne, musisz użyć await
z toMatchFileSnapshot()
.
toThrowErrorMatchingSnapshot
- Typ:
(message?: string) => void
Działa tak samo jak toMatchSnapshot
, ale oczekuje, że testowana funkcja rzuci błąd (tak jak w toThrowError
).
toThrowErrorMatchingInlineSnapshot
- Typ:
(snapshot?: string, message?: string) => void
Działa tak samo jak toMatchInlineSnapshot
, ale oczekuje, że testowana funkcja rzuci błąd (tak jak w toThrowError
).
toHaveBeenCalled
- Typ:
() => Awaitable<void>
Sprawdza, czy funkcja została wywołana. Wymaga przekazania funkcji szpiegowskiej (ang. spy function) do 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
- Typ:
(amount: number) => Awaitable<void>
Sprawdza, czy funkcja została wywołana określoną liczbę razy. Wymaga przekazania funkcji szpiegowskiej do 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
- Typ:
(...args: any[]) => Awaitable<void>
Sprawdza, czy funkcja została wywołana co najmniej raz z określonymi argumentami. Wymaga przekazania funkcji szpiegowskiej do expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenCalledWith('apples', 10);
expect(buySpy).toHaveBeenCalledWith('apples', 20);
});
toHaveBeenLastCalledWith
- Typ:
(...args: any[]) => Awaitable<void>
Sprawdza, czy funkcja została wywołana z określonymi argumentami podczas ostatniego wywołania. Wymaga przekazania funkcji szpiegowskiej do 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
- Typ:
(time: number, ...args: any[]) => Awaitable<void>
Sprawdza, czy funkcja została wywołana z określonymi argumentami podczas konkretnego wywołania (określonego numerem). Numeracja zaczyna się od 1. Zatem, aby sprawdzić drugie wywołanie, należy użyć .toHaveBeenNthCalledWith(2, ...)
.
Wymaga przekazania funkcji szpiegowskiej do 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
- Typ:
() => Awaitable<void>
Sprawdza, czy funkcja pomyślnie zwróciła wartość co najmniej raz (tzn. nie rzuciła błędu). Wymaga przekazania funkcji szpiegowskiej do 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
- Typ:
(amount: number) => Awaitable<void>
Sprawdza, czy funkcja pomyślnie zwróciła wartość dokładnie określoną liczbę razy (tzn. nie rzuciła błędu). Wymaga przekazania funkcji szpiegowskiej do 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
- Typ:
(returnValue: any) => Awaitable<void>
Użyj tego sprawdzenia, aby upewnić się, że funkcja szpiegowska (spy) zwróciła określoną wartość przynajmniej raz. Wymaga przekazania funkcji szpiegowskiej do expect
.
import { expect, test, vi } from 'vitest';
test('funkcja szpiegowska zwraca produkt', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
expect(sell).toHaveReturnedWith({ product: 'apples' });
});
toHaveLastReturnedWith
- Typ:
(returnValue: any) => Awaitable<void>
Użyj tego sprawdzenia, aby upewnić się, że funkcja szpiegowska (spy) zwróciła określoną wartość podczas ostatniego wywołania. Wymaga przekazania funkcji szpiegowskiej do expect
.
import { expect, test, vi } from 'vitest';
test('funkcja szpiegowska zwraca banany przy ostatnim wywołaniu', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveLastReturnedWith({ product: 'bananas' });
});
toHaveNthReturnedWith
- Typ:
(time: number, returnValue: any) => Awaitable<void>
Użyj tego sprawdzenia, aby upewnić się, że funkcja szpiegowska (spy) zwróciła określoną wartość podczas konkretnego wywołania (określonego numerem). Wymaga przekazania funkcji szpiegowskiej do expect
.
import { expect, test, vi } from 'vitest';
test('funkcja szpiegowska zwraca banany przy drugim wywołaniu', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveNthReturnedWith(2, { product: 'bananas' });
});
toSatisfy
- Typ:
(predicate: (value: any) => boolean) => Awaitable<void>
To sprawdzenie weryfikuje, czy dana wartość spełnia określony predykat (funkcję zwracającą wartość boolean).
import { describe, expect, it } from 'vitest';
describe('toSatisfy()', () => {
const isOdd = (value: number) => value % 2 !== 0;
it('przechodzi z wartością 1', () => {
expect(1).toSatisfy(isOdd);
});
it('nie przechodzi z wartością 2', () => {
expect(2).not.toSatisfy(isOdd);
});
});
resolves
- Typ:
Promisify<Assertions>
resolves
upraszcza testowanie kodu asynchronicznego. Użyj go, aby "rozpakować" wartość z pomyślnie zakończonego Promise i sprawdzić ją za pomocą standardowych asercji. Jeśli Promise zostanie odrzucony (rejected), asercja zakończy się niepowodzeniem.
Zwraca ten sam obiekt Assertions
, ale wszystkie matchery zwracają teraz Promise
, więc konieczne jest użycie await
. Działa również z asercjami chai
.
Przykład: jeśli masz funkcję, która wykonuje zapytanie API i zwraca dane, możesz użyć resolves
do sprawdzenia wartości zwracanej:
import { expect, test } from 'vitest';
async function buyApples() {
return fetch('/buy/apples').then(r => r.json());
}
test('buyApples zwraca nowy identyfikator zapasu', async () => {
// toEqual zwraca teraz Promise, więc MUSISZ użyć await
await expect(buyApples()).resolves.toEqual({ id: 1 }); // API Vitest
await expect(buyApples()).resolves.to.equal({ id: 1 }); // API Chai
});
WARNING
Jeśli asercja nie zostanie zaczekana (awaited), test może fałszywie przejść. Aby upewnić się, że asercje są rzeczywiście wykonywane, użyj expect.assertions(number)
.
rejects
- Typ:
Promisify<Assertions>
rejects
upraszcza testowanie kodu asynchronicznego. Użyj go, aby "rozpakować" powód odrzucenia (rejection) Promise i sprawdzić go za pomocą standardowych asercji. Jeśli Promise zostanie pomyślnie rozwiązany (resolved), asercja zakończy się niepowodzeniem.
Zwraca ten sam obiekt Assertions
, ale wszystkie matchery zwracają teraz Promise
, więc konieczne jest użycie await
. Działa również z asercjami chai
.
Przykład: jeśli masz funkcję, która powinna zakończyć się błędem w określonych warunkach, możesz użyć rejects
do sprawdzenia powodu błędu:
import { expect, test } from 'vitest';
async function buyApples(id) {
if (!id) throw new Error('no id');
}
test('buyApples zgłasza błąd, gdy nie podano identyfikatora', async () => {
// toThrow zwraca teraz Promise, więc MUSISZ użyć await
await expect(buyApples()).rejects.toThrow('no id');
});
WARNING
Jeśli asercja nie zostanie zaczekana (awaited), test może fałszywie przejść. Aby upewnić się, że asercje są rzeczywiście wykonywane, użyj expect.assertions(number)
.
expect.assertions
- Typ:
(count: number) => void
Sprawdza, czy podczas testu została wywołana dokładnie określona liczba asercji. Przydatne do weryfikacji, czy kod asynchroniczny został wykonany.
Przykład: jeśli funkcja asynchronicznie wywołuje dwa matchery, możesz sprawdzić, czy oba zostały rzeczywiście wywołane.
import { expect, test } from 'vitest';
async function doAsync(...cbs) {
await Promise.all(cbs.map((cb, index) => cb({ index })));
}
test('wszystkie asercje są wywoływane', async () => {
expect.assertions(2);
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}
await doAsync(callback1, callback2);
});
WARNING
Podczas używania assertions
z asynchronicznymi testami współbieżnymi, użyj expect
z lokalnego Kontekstu Testowego, aby upewnić się, że sprawdzany jest właściwy test.
expect.hasAssertions
- Typ:
() => void
Sprawdza, czy podczas testu została wywołana przynajmniej jedna asercja. Przydatne do weryfikacji, czy kod asynchroniczny został wykonany.
Przykład: jeśli masz kod, który wywołuje callback, możesz umieścić asercję wewnątrz callbacku, ale test zawsze przejdzie, jeśli nie sprawdzisz, czy asercja została w ogóle wywołana.
import { expect, test } from 'vitest';
import { db } from './db.js';
const cbs = [];
function onSelect(cb) {
cbs.push(cb);
}
// po wybraniu z bazy danych, wywołujemy wszystkie callbacki
function select(id) {
return db.select({ id }).then(data => {
return Promise.all(cbs.map(cb => cb(data)));
});
}
test('callback został wywołany poprawnie', async () => {
expect.hasAssertions();
onSelect(data => {
// powinien być wywołany przy select
expect(data).toBeTruthy();
});
// jeśli nie zaczekamy, test zakończy się niepowodzeniem
// jeśli nie masz expect.hasAssertions(), test przejdzie
await select(3);
});
expect.unreachable
- Typ:
(message?: string) => never
Ta metoda służy do oznaczenia linii kodu, która nigdy nie powinna zostać osiągnięta. Jeśli zostanie osiągnięta, test zakończy się niepowodzeniem.
Przykład: jeśli testujesz, czy funkcja build()
zgłasza wyjątek w przypadku braku folderu src
, a chcesz obsłużyć każdy błąd oddzielnie, możesz to zrobić tak:
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('budowanie nie powiódł się dla "%s"', async dir => {
try {
await build(dir);
expect.unreachable('Build nie powinien się powieść');
} 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:
// aby wyczerpać wszystkie testy błędów
expect.unreachable('Wszystkie błędy muszą być obsłużone');
break;
}
}
});
expect.anything
- Typ:
() => any
Ten asymetryczny matcher, używany w połączeniu ze sprawdzeniem równości, zawsze zwróci true
. Przydatny, gdy chcesz tylko upewnić się, że dana właściwość istnieje.
import { expect, test } from 'vitest';
test('obiekt zawiera klucz "apples"', () => {
expect({ apples: 22 }).toEqual({ apples: expect.anything() });
});
expect.any
- Typ:
(constructor: unknown) => any
Ten asymetryczny matcher, używany w połączeniu ze sprawdzeniem równości, zwróci true
tylko wtedy, gdy wartość jest instancją określonego konstruktora. Przydatny, gdy masz wartość, która jest generowana dynamicznie i chcesz tylko sprawdzić, czy jest odpowiedniego typu.
import { expect, test } from 'vitest';
import { generateId } from './generators.js';
test('"id" jest typu liczbowego', () => {
expect({ id: generateId() }).toEqual({ id: expect.any(Number) });
});
expect.closeTo 1.0.0+
- Typ:
(expected: any, precision?: number) => any
expect.closeTo
jest przydatne podczas porównywania liczb zmiennoprzecinkowych we właściwościach obiektów lub elementach tablicy. Jeśli potrzebujesz porównać liczbę, użyj zamiast tego .toBeCloseTo
.
Opcjonalny argument numDigits
ogranicza liczbę cyfr do sprawdzenia po przecinku. Dla wartości domyślnej 2
kryterium testu to Math.abs(expected - received) < 0.005 (czyli 10 ** -2 / 2)
.
Na przykład ten test przechodzi z dokładnością do 5 cyfr:
test('porównaj liczbę zmiennoprzecinkową we właściwościach obiektu', () => {
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
Używany w połączeniu ze sprawdzeniem równości, ten asymetryczny matcher zwróci true
, jeśli wartość jest tablicą i zawiera wszystkie elementy z expected
.
import { expect, test } from 'vitest';
test('koszyk zawiera jabłka Fuji', () => {
const basket = {
varieties: ['Empire', 'Fuji', 'Gala'],
count: 3,
};
expect(basket).toEqual({
count: 3,
varieties: expect.arrayContaining(['Fuji']),
});
});
TIP
Możesz użyć expect.not
z tym matcherem, aby zanegować oczekiwaną wartość.
expect.objectContaining
- Typ:
(expected: any) => any
Używany w połączeniu ze sprawdzeniem równości, ten asymetryczny matcher zwróci true
, jeśli wartość jest obiektem i ma przynajmniej właściwości z expected
o tych samych wartościach.
import { expect, test } from 'vitest';
test('koszyk zawiera jabłka Empire', () => {
const basket = {
varieties: [
{
name: 'Empire',
count: 1,
},
],
};
expect(basket).toEqual({
varieties: [expect.objectContaining({ name: 'Empire' })],
});
});
TIP
Możesz użyć expect.not
z tym matcherem, aby zanegować oczekiwaną wartość.
expect.stringContaining
- Typ:
(expected: any) => any
Używany w połączeniu ze sprawdzeniem równości, ten asymetryczny matcher zwróci true
, jeśli wartość jest ciągiem znaków i zawiera określony podciąg.
import { expect, test } from 'vitest';
test('odmiana zawiera "Emp" w nazwie', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringContaining('Emp'),
count: 1,
});
});
TIP
Możesz użyć expect.not
z tym matcherem, aby zanegować oczekiwaną wartość.
expect.stringMatching
- Typ:
(expected: any) => any
Używany w połączeniu ze sprawdzeniem równości, ten asymetryczny matcher zwróci true
, jeśli wartość jest ciągiem znaków i pasuje do określonego wyrażenia regularnego.
import { expect, test } from 'vitest';
test('nazwa odmiany kończy się na "re"', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringMatching(/re$/),
count: 1,
});
});
TIP
Możesz użyć expect.not
z tym matcherem, aby zanegować oczekiwaną wartość.
expect.addSnapshotSerializer
- Typ:
(plugin: PrettyFormatPlugin) => void
Ta metoda dodaje niestandardowe serializatory, które są wywoływane podczas tworzenia snapshotów. Jest to zaawansowana funkcja - więcej informacji znajdziesz w przewodniku po niestandardowych serializatorach.
Jeśli dodajesz niestandardowe serializatory, wywołaj tę metodę wewnątrz setupFiles
. Zmiana będzie miała wpływ na każdy snapshot.
TIP
Jeśli wcześniej używałeś Vue CLI z Jest, możesz zainstalować jest-serializer-vue. W przeciwnym razie Twoje snapshoty zostaną opakowane w ciąg znaków, co spowoduje, że "
zostaną zmienione.
expect.extend
- Typ:
(matchers: MatchersObject) => void
Pozwala rozszerzyć domyślne matchery o własne. Ta funkcja służy do dodawania niestandardowych matcherów do obiektu matcherów.
Definiując matchery w ten sposób, tworzysz również asymetryczne matchery, które mogą być używane jak expect.stringContaining
.
import { expect, test } from 'vitest';
test('własne matchery', () => {
expect.extend({
toBeFoo: (received, expected) => {
if (received !== 'foo') {
return {
message: () => `oczekiwano, że ${received} będzie równe 'foo'`,
pass: false,
};
}
},
});
expect('foo').toBeFoo();
expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() });
});
TIP
Aby Twoje matchery były dostępne w każdym teście, wywołaj tę metodę wewnątrz setupFiles
.
Ta funkcja jest kompatybilna z expect.extend
Jesta, więc każda biblioteka, która jej używa do tworzenia niestandardowych matcherów, będzie działać z Vitest.
Jeśli używasz TypeScript, od Vitest 0.31.0 możesz rozszerzyć domyślny interfejs Assertion
w pliku deklaracji otoczenia (np: vitest.d.ts
) za pomocą poniższego kodu:
interface CustomMatchers<R = unknown> {
toBeFoo: () => R;
}
declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}
WARNING
Nie zapomnij dołączyć pliku deklaracji otoczenia do swojego tsconfig.json
.
TIP
Więcej informacji znajdziesz w przewodniku po rozszerzaniu matcherów.
expect.addEqualityTesters 1.2.0+
- Typ:
(tester: Array<Tester>) => void
Możesz użyć tej metody do zdefiniowania niestandardowych testerów, które są metodami używanymi przez matchery do testowania, czy dwa obiekty są równe. Jest kompatybilna z expect.addEqualityTesters
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 = isBAnagramComparator(b);
if (isAAnagramComparator && isBAnagramComparator) return a.equals(b);
else if (isAAnagramComparator === isBAnagramComparator) return undefined;
else return false;
}
expect.addEqualityTesters([areAnagramsEqual]);
test('niestandardowy tester równości', () => {
expect(new AnagramComparator('listen')).toEqual(
new AnagramComparator('silent')
);
});