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(3); // niepowodzenie, co skutkuje przerwaniem testu, wszystkie poprzednie błędy zostaną wyświetlone
expect.soft(1 + 2).toBe(4); // 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łaniaexpect(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.
tsimport { 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śle0.3
. Aby niezawodnie potwierdzać liczby zmiennoprzecinkowe, użyj asercjitoBeCloseTo
.
toBeCloseTo
Typ:
(value: number, numDigits?: number) => Awaitable<void>
Użyj
toBeCloseTo
do porównywania liczb zmiennoprzecinkowych. Opcjonalny argumentnumDigits
określa liczbę cyfr po przecinku, które mają być uwzględnione w porównaniu. Na przykład:tsimport { 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ównaundefined
. Przykładem użycia może być sprawdzenie, czy funkcja zwróciła jakąkolwiek wartość.tsimport { 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ównaundefined
. Przykładem użycia może być sprawdzenie, czy funkcja niczego nie zwróciła.tsimport { expect, test } from 'vitest'; function getApplesFromStock(stock) { 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ć natrue
.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ł.tsimport { 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ć:tsimport { 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
,0
,''
,null
,undefined
iNaN
.
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ć nafalse
.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ł.tsimport { 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ć:tsimport { 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
,0
,''
,null
,undefined
iNaN
.
toBeNull
Typ:
() => Awaitable<void>
toBeNull
po prostu potwierdza, czy coś jestnull
. Alias dla.toBe(null)
.tsimport { 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ś jestNaN
. Alias dla.toBe(NaN)
.tsimport { 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.tsimport { 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.tsimport { 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.tsimport { 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.tsimport { 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.tsimport { 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.tsimport { 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ędzytoEqual
itoBe
w tym przykładzie:tsimport { 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łęboka równość nie zostanie wykonana dla obiektów
Error
. Aby przetestować, czy coś zostało rzucone, użyj asercjitoThrowError
.
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
.
tsimport { 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' }); });
- Sprawdzane są klucze z właściwościami
toContain
Typ:
(received: string) => Awaitable<void>
toContain
potwierdza, 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.tsimport { expect, test } from 'vitest'; import { getAllFruits } from './stocks.js'; test("tablica zwracana przez `getAllFruits()` zawiera element 'orange'", () => { expect(getAllFruits()).toContain('orange'); });
toContainEqual
Typ:
(received: any) => Awaitable<void>
toContainEqual
potwierdza, czy element o określonej strukturze i wartościach znajduje się w tablicy. Działa jaktoEqual
dla każdego elementu tablicy.tsimport { 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ą.tsimport { 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 kluczukey
.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 matcheratoEqual
.tsimport { expect, test } from 'vitest'; const invoice = { isActive: true, 'P.O': '12345', customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, total_amount: 5000, items: [ { type: 'apples', quantity: 10, }, { type: 'oranges', quantity: 5, }, ], }; test('John Doe Invoice', () => { expect(invoice).toHaveProperty('isActive'); // 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.tsimport { 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 });
TIP
Jeśli komunikat o błędzie jest obcięty, możesz zwiększyć wartość chaiConfig.truncateThreshold
w pliku konfiguracyjnym.
toMatchObject
Typ:
(received: object | array) => Awaitable<void>
toMatchObject
sprawdza, czy obiekt pasuje do podzbioru właściwości innego obiektu. Innymi słowy, sprawdza, czyreceived
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 tablicyreceived
.tsimport { expect, test } from 'vitest'; const johnInvoice = { isActive: true, customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, total_amount: 5000, items: [ { type: 'apples', quantity: 10, }, { type: 'oranges', quantity: 5, }, ], }; const johnDetails = { customer: { first_name: 'John', last_name: 'Doe', location: 'China', }, }; test('invoice has john personal details', () => { expect(johnInvoice).toMatchObject(johnDetails); }); test('the number of elements must match exactly', () => { // 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:tsimport { expect, test } from 'vitest'; function getFruitStock(type) { if (type === 'pineapples') throw new DiabetesError( 'Pineapples are not good for people with diabetes' ); // Zrób coś innego } test('throws on pineapples', () => { // Sprawdź, czy komunikat o błędzie zawiera słowo "diabetes" (równoważne): expect(() => getFruitStock('pineapples')).toThrowError(/diabetes/); expect(() => getFruitStock('pineapples')).toThrowError('diabetes'); // Sprawdź dokładny komunikat o błędzie expect(() => getFruitStock('pineapples')).toThrowError( /^Pineapples are not good for people with diabetes$/ ); });
TIP
Do testowania funkcji asynchronicznych użyj w połączeniu z rejects.
jsfunction 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 blokuit
lubtest
. 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.tsimport { 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:
tsimport { 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
).tsimport { 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:
tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchInlineSnapshot( { foo: expect.any(Set) }, ` { "foo": Any<Set>, } ` ); });
toMatchFileSnapshot
Typ:
<T>(filepath: string, message?: string) => Promise<void>
Wersja: Od Vitest 0.30.0
Porównuje lub aktualizuje migawkę z zawartością pliku o określonej ścieżce (zamiast pliku
.snap
).tsimport { expect, it } from 'vitest'; it('render basic', async () => { const result = renderHTML(h('div', { class: 'foo' })); await expect(result).toMatchFileSnapshot('./test/basic.output.html'); });
Ponieważ operacje na systemie plików są asynchroniczne, musisz użyć
await
ztoMatchFileSnapshot()
.
toThrowErrorMatchingSnapshot
Typ:
(message?: string) => void
Działa tak samo jak
toMatchSnapshot
, ale oczekuje, że testowana funkcja rzuci błąd (tak jak wtoThrowError
).Jeśli funkcja rzuci
Error
, migawka będzie zawierała komunikat o błędzie. W przeciwnym razie migawka będzie zawierała wartość zwróconą przez funkcję.
toThrowErrorMatchingInlineSnapshot
Typ:
(snapshot?: string, message?: string) => void
Działa tak samo jak
toMatchInlineSnapshot
, ale oczekuje, że testowana funkcja rzuci błąd (tak jak wtoThrowError
).Jeśli funkcja rzuci
Error
, migawka będzie zawierała komunikat o błędzie. W przeciwnym razie migawka będzie zawierała wartość zwróconą przez funkcję.
toHaveBeenCalled
Typ:
() => Awaitable<void>
Sprawdza, czy funkcja została wywołana. Wymaga przekazania funkcji szpiegowskiej (ang. spy function) do
expect
.tsimport { expect, test, vi } from 'vitest'; const market = { buy(subject: string, amount: number) { // ... }, }; test('spy function', () => { const buySpy = vi.spyOn(market, 'buy'); expect(buySpy).not.toHaveBeenCalled(); market.buy('apples', 10); expect(buySpy).toHaveBeenCalled(); });
toHaveBeenCalledTimes
Typ:
(amount: number) => Awaitable<void>
Sprawdza, czy funkcja została wywołana określoną liczbę razy. Wymaga przekazania funkcji szpiegowskiej do
expect
.tsimport { 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
.tsimport { 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
.tsimport { 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
.tsimport { 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
.tsimport { 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
.tsimport { 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).
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ą terazPromise
, więc konieczne jest użycieawait
. Działa również z asercjamichai
.Przykład: jeśli masz funkcję, która wykonuje zapytanie API i zwraca dane, możesz użyć
resolves
do sprawdzenia wartości zwracanej:tsimport { 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ą terazPromise
, więc konieczne jest użycieawait
. Działa również z asercjamichai
.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:tsimport { 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.
tsimport { 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żyjexpect
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.
tsimport { 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 folderusrc
, a chcesz obsłużyć każdy błąd oddzielnie, możesz to zrobić tak:tsimport { expect, test } from 'vitest'; async function build(dir) { if (dir.includes('no-src')) throw new Error(`${dir}/src does not exist`); } const errorDirs = [ 'no-src-folder', // ... ]; test('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.tsimport { 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.tsimport { expect, test } from 'vitest'; import { generateId } from './generators.js'; test('"id" jest typu liczbowego', () => { expect({ id: generateId() }).toEqual({ id: expect.any(Number) }); });
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 zexpected
.tsimport { 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 zexpected
o tych samych wartościach.tsimport { 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.tsimport { 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.tsimport { 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
.tsimport { 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:tsinterface 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.