expect
Die folgenden Typen werden in den nachstehenden Typsignaturen verwendet:
type Awaitable<T> = T | PromiseLike<T>;
In Vitest wird expect
verwendet, um Assertions (Zusicherungen) zu erstellen. Assertions sind Funktionen, die aufgerufen werden, um eine Aussage zu überprüfen. Vitest stellt standardmäßig chai
-Assertions und Jest
-kompatible Assertions bereit, die auf chai
aufbauen.
Beispielsweise prüft dieser Code, ob ein input
-Wert gleich 2
ist. Wenn dies nicht der Fall ist, wird ein Fehler ausgelöst und der Test schlägt fehl.
import { expect } from 'vitest';
const input = Math.sqrt(4);
expect(input).to.equal(2); // chai API
expect(input).toBe(2); // jest API
Technisch gesehen verwendet dieses Beispiel nicht die Funktion test
, weshalb in der Konsole ein Node.js-Fehler anstelle der Vitest-Ausgabe angezeigt wird. Um mehr über test
zu erfahren, lesen Sie bitte die Test API Referenz.
Zusätzlich kann expect
statisch verwendet werden, um auf Matcher-Funktionen (weiter unten beschrieben) und andere Features zuzugreifen.
WARNING
expect
hat keine Auswirkung auf die Typüberprüfung, wenn der Ausdruck keinen Typfehler aufweist. Um Vitest zur Typüberprüfung zu nutzen, verwenden Sie entweder expectTypeOf
oder assertType
.
soft
- Typ:
ExpectStatic & (actual: any) => Assertions
expect.soft
ähnelt expect
, beendet aber die Testausführung nicht bei einer fehlgeschlagenen Assertion. Stattdessen wird der Fehler als fehlgeschlagener Test markiert und die Testausführung wird fortgesetzt.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // Markiert den Test als fehlgeschlagen und setzt die Ausführung fort
expect.soft(1 + 2).toBe(4); // Markiert den Test als fehlgeschlagen und setzt die Ausführung fort
});
// Am Ende des Tests werden die obigen Fehler ausgegeben.
Die Kombination mit expect
ist ebenfalls möglich. Schlägt eine expect
-Assertion fehl, wird der Test beendet und alle bis dahin aufgetretenen Fehler werden ausgegeben.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // Markiert den Test als fehlgeschlagen und setzt die Ausführung fort
expect(1 + 2).toBe(3); // Fehlgeschlagen und beendet den Test, alle vorherigen Fehler werden ausgegeben
expect.soft(1 + 2).toBe(4); // Wird nicht ausgeführt
});
WARNING
expect.soft
kann nur innerhalb der Funktion test
verwendet werden.
not
Die Verwendung von not
kehrt die Assertion um. Beispielsweise prüft dieser Code, ob ein input
-Wert nicht gleich 2
ist. Wenn er gleich ist, wird ein Fehler ausgelöst und der Test schlägt fehl.
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
dient dazu, zu prüfen, ob primitive Datentypen gleich sind oder ob Objekte auf dieselbe Speicherstelle im Speicher verweisen. Dies entspricht dem Aufruf von expect(Object.is(3, 3)).toBe(true)
. Wenn die Objekte nicht identisch sind, Sie aber ihre Struktur vergleichen möchten, verwenden Sie toEqual
.
Beispielsweise prüft der folgende Code, ob der Händler 13 Äpfel hat.
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; // die gleiche Referenz
expect(stock).toBe(refStock);
});
Vermeiden Sie die Verwendung von toBe
mit Fließkommazahlen, da JavaScript diese rundet und 0.1 + 0.2
nicht exakt 0.3
entspricht. Verwenden Sie stattdessen toBeCloseTo
, um Fließkommazahlen zuverlässig zu vergleichen.
toBeCloseTo
- Typ:
(value: number, numDigits?: number) => Awaitable<void>
Verwenden Sie toBeCloseTo
, um Fließkommazahlen zu vergleichen. Das optionale Argument numDigits
gibt an, auf wie viele Nachkommastellen verglichen werden soll. Zum Beispiel:
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 ist 0.30000000000000004
});
test('decimals are rounded to 5 after the point', () => {
// 0.2 + 0.1 ist 0.30000 | "000000000004" entfernt
expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
// nichts von 0.30000000000000004 wird entfernt
expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50);
});
toBeDefined
- Typ:
() => Awaitable<void>
toBeDefined
prüft, ob ein Wert nicht undefined
ist. Dies ist nützlich, um zu überprüfen, ob eine Funktion einen Wert zurückgibt.
import { expect, test } from 'vitest';
function getApples() {
return 3;
}
test('function returned something', () => {
expect(getApples()).toBeDefined();
});
toBeUndefined
- Typ:
() => Awaitable<void>
Im Gegensatz zu toBeDefined
prüft toBeUndefined
, ob ein Wert undefined
ist. Dies ist nützlich, um zu überprüfen, ob eine Funktion keinen Wert zurückgibt.
import { expect, test } from 'vitest';
function getApplesFromStock(stock) {
if (stock === 'Bill') return 13;
}
test("mary doesn't have a stock", () => {
expect(getApplesFromStock('Mary')).toBeUndefined();
});
toBeTruthy
- Typ:
() => Awaitable<void>
toBeTruthy
prüft, ob ein Wert bei der Konvertierung in einen booleschen Wert true
ergibt. Dies ist nützlich, wenn der genaue Wert irrelevant ist, aber sichergestellt werden muss, dass er als true
interpretiert wird.
Betrachten Sie beispielsweise den Rückgabewert von stocks.getInfo
. Dieser kann ein komplexes Objekt, eine Zeichenkette oder ein anderer Datentyp sein. Der Code funktioniert unabhängig davon.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (stocks.getInfo('Bill')) stocks.sell('apples', 'Bill');
Um zu testen, ob stocks.getInfo
einen "truthy" Wert zurückgibt, können Sie folgenden Code verwenden:
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();
});
Alles in JavaScript ist "truthy", außer false
, 0
, ''
, null
, undefined
und NaN
.
toBeFalsy
- Typ:
() => Awaitable<void>
toBeFalsy
prüft, ob ein Wert bei der Konvertierung in einen booleschen Wert false
ergibt. Dies ist nützlich, wenn der genaue Wert irrelevant ist, aber sichergestellt werden muss, dass er als false
interpretiert wird.
Betrachten Sie beispielsweise den Rückgabewert von stocks.stockFailed
. Dieser kann ein beliebiger "falsy" Wert sein, aber der Code funktioniert trotzdem.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (!stocks.stockFailed('Bill')) stocks.sell('apples', 'Bill');
Um zu testen, ob stocks.stockFailed
einen "falsy" Wert zurückgibt, können Sie folgenden Code verwenden:
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();
});
Alles in JavaScript ist "truthy", außer false
, 0
, ''
, null
, undefined
und NaN
.
toBeNull
- Typ:
() => Awaitable<void>
toBeNull
prüft, ob ein Wert null
ist. Dies ist ein Alias für .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
prüft, ob ein Wert NaN
ist. Dies ist ein Alias für .toBe(NaN)
.
import { expect, test } from 'vitest';
let i = 0;
function getApplesCount() {
i++;
return i > 1 ? Number.NaN : i;
}
test('getApplesCount has some unusual side effects...', () => {
expect(getApplesCount()).not.toBeNaN();
expect(getApplesCount()).toBeNaN();
});
toBeTypeOf
- Typ:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
prüft, ob der tatsächliche Wert dem erwarteten Datentyp entspricht.
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
prüft, ob der tatsächliche Wert eine Instanz der erwarteten Klasse ist.
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
prüft, ob der tatsächliche Wert größer als der erwartete Wert ist. Bei gleichen Werten schlägt der Test fehl.
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
prüft, ob der tatsächliche Wert größer oder gleich dem erwarteten Wert ist.
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
prüft, ob der tatsächliche Wert kleiner als der erwartete Wert ist. Bei gleichen Werten schlägt der Test fehl.
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
prüft, ob der tatsächliche Wert kleiner oder gleich dem erwarteten Wert ist.
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
prüft, ob der tatsächliche Wert gleich dem erwarteten Wert ist oder, im Falle von Objekten, die gleiche Struktur aufweist (rekursiver Vergleich). Das folgende Beispiel verdeutlicht den Unterschied zwischen toEqual
und toBe
:
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
Ein Deep Equality Check wird für Error
-Objekte nicht durchgeführt. Um zu testen, ob eine Exception geworfen wurde, verwenden Sie die Assertion toThrowError
.
toStrictEqual
- Typ:
(received: any) => Awaitable<void>
toStrictEqual
prüft, ob der tatsächliche Wert gleich dem erwarteten Wert ist, die gleiche Struktur aufweist (rekursiver Vergleich) und vom gleichen Typ ist.
Unterschiede zu .toEqual
:
- Es werden auch Schlüssel mit
undefined
-Werten berücksichtigt. Beispielsweise führt{a: undefined, b: 2}
bei Verwendung von.toStrictEqual
nicht zu einem positiven Vergleich mit{b: 2}
. - Die "Dünnheit" (sparseness) von Arrays wird berücksichtigt. Beispielsweise führt
[, 1]
bei Verwendung von.toStrictEqual
nicht zu einem positiven Vergleich mit[undefined, 1]
. - Die Objekttypen müssen übereinstimmen. Beispielsweise wird eine Klasseninstanz mit den Feldern
a
undb
nicht als gleichwertig zu einem Literalobjekt mit den gleichen Feldern betrachtet.
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
prüft, ob ein Wert in einem Array enthalten ist oder ob eine Zeichenkette eine Teilzeichenkette einer anderen Zeichenkette ist.
import { expect, test } from 'vitest';
import { getAllFruits } from './stocks.js';
test('the fruit list contains orange', () => {
expect(getAllFruits()).toContain('orange');
});
toContainEqual
- Typ:
(received: any) => Awaitable<void>
toContainEqual
prüft, ob ein Array ein Element mit einer bestimmten Struktur und bestimmten Werten enthält. Die Funktionsweise entspricht toEqual
, angewendet auf jedes Element des Arrays.
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
prüft, ob ein Objekt eine .length
-Eigenschaft mit einem bestimmten numerischen Wert besitzt.
import { expect, test } from 'vitest';
test('toHaveLength', () => {
expect('abc').toHaveLength(3);
expect([1, 2, 3]).toHaveLength(3);
expect('').not.toHaveLength(3); // hat keine .length-Eigenschaft mit dem Wert 3
expect({ length: 3 }).toHaveLength(3);
});
toHaveProperty
Typ:
(key: any, received?: any) => Awaitable<void>
toHaveProperty
prüft, ob ein Objekt eine Eigenschaft mit dem angegebenen Schlüsselkey
besitzt.Optional kann ein Wertargument angegeben werden, das mit dem Wert der Eigenschaft verglichen wird. Dieser Vergleich erfolgt mittels tiefer Gleichheit (Deep Equality), ähnlich wie beim
toEqual
-Matcher.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'); expect(invoice).toHaveProperty('total_amount', 5000); expect(invoice).not.toHaveProperty('account'); // Tiefe Referenzierung mittels Punktnotation expect(invoice).toHaveProperty('customer.first_name'); expect(invoice).toHaveProperty('customer.last_name', 'Doe'); expect(invoice).not.toHaveProperty('customer.location', 'India'); // Tiefe Referenzierung mittels eines Arrays, das den Schlüssel enthält expect(invoice).toHaveProperty('items[0].type', 'apples'); expect(invoice).toHaveProperty('items.0.type', 'apples'); // Tiefe Referenzierung mit einem Array, das den KeyPath enthält expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples'); expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // Schließen Sie Ihren Schlüssel in ein Array ein, um zu verhindern, dass er als tiefe Referenz interpretiert wird expect(invoice).toHaveProperty(['P.O'], '12345'); });
toMatch
Typ:
(received: string | regexp) => Awaitable<void>
toMatch
prüft, ob eine Zeichenkette mit einem regulären Ausdruck oder einer anderen Zeichenkette übereinstimmt.tsimport { expect, test } from 'vitest'; test('top fruits', () => { expect('top fruits include apple, orange and grape').toMatch(/apple/); expect('applefruits').toMatch('fruit'); // toMatch akzeptiert ebenfalls einen String });
TIP
Wenn der Wert in der Fehlermeldung zu stark abgeschnitten ist, können Sie chaiConfig.truncateThreshold
in Ihrer Konfigurationsdatei erhöhen. Siehe chaiConfig.truncateThreshold.
toMatchObject
Typ:
(received: object | array) => Awaitable<void>
toMatchObject
prüft, ob ein Objekt mit einem Teil der Eigenschaften eines anderen Objekts übereinstimmt. Es wird geprüft, ob das erwartete Objekt im empfangenen Objekt enthalten ist.Sie können auch ein Array von Objekten übergeben. Dies ist nützlich, um zu überprüfen, ob zwei Arrays die gleiche Anzahl an Elementen haben und die Elemente übereinstimmen. Im Gegensatz zu
arrayContaining
erlaubttoMatchObject
keine zusätzlichen Elemente im empfangenen Array.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', () => { // stellt fest, dass ein Array von Objekten übereinstimmt expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([ { foo: 'bar' }, { baz: 1 }, ]); });
toThrowError
Typ:
(received: any) => Awaitable<void>
Alias:
toThrow
toThrowError
prüft, ob eine Funktion beim Aufruf einen Fehler auslöst.Sie können optional ein Argument angeben, um zu prüfen, ob ein bestimmter Fehler ausgelöst wird:
- Regulärer Ausdruck: Die Fehlermeldung muss dem Muster entsprechen.
- Zeichenkette: Die Fehlermeldung muss den Text enthalten.
TIP
Sie müssen den Code in eine Funktion einbetten, da der Fehler sonst nicht abgefangen wird und der Test fehlschlägt.
Um beispielsweise zu testen, ob
getFruitStock('pineapples')
einen Fehler auslöst, können Sie Folgendes schreiben:tsimport { expect, test } from 'vitest'; function getFruitStock(type) { if (type === 'pineapples') throw new DiabetesError( 'Pineapples are not good for people with diabetes' ); // Führe andere Operationen aus } test('throws on pineapples', () => { // Überprüfen, ob die Fehlermeldung irgendwo 'diabetes' enthält: diese sind äquivalent expect(() => getFruitStock('pineapples')).toThrowError(/diabetes/); expect(() => getFruitStock('pineapples')).toThrowError('diabetes'); // Testen der genauen Fehlermeldung expect(() => getFruitStock('pineapples')).toThrowError( /^Pineapples are not good for people with diabetes$/ ); });
TIP
Um asynchrone Funktionen zu testen, verwenden Sie
toThrowError
in Kombination mit 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
Stellt sicher, dass ein Wert mit dem aktuellsten Snapshot übereinstimmt.
Sie können optional ein
hint
-String-Argument angeben, das an den Testnamen angehängt wird. Vitest hängt zwar immer eine Zahl an das Ende eines Snapshot-Namens an, aber kurze, beschreibende Hinweise können nützlicher sein als Zahlen, um mehrere Snapshots in einem einzelnen Testblock zu unterscheiden. Vitest sortiert Snapshots nach Namen in der entsprechenden.snap
-Datei.TIP
Wenn ein Snapshot nicht übereinstimmt und der Test fehlschlägt, können Sie die Taste
u
drücken, um den Snapshot einmalig zu aktualisieren. Alternativ können Sie die CLI-Optionen-u
oder--update
übergeben, damit Vitest die Tests immer aktualisiert.tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchSnapshot(); });
Sie können auch eine Form eines Objekts angeben, wenn Sie nur die Struktur eines Objekts testen und keine 100%ige Übereinstimmung benötigen:
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
Stellt sicher, dass ein Wert mit dem aktuellsten Inline-Snapshot übereinstimmt.
Vitest fügt das InlineSnapshot-String-Argument zum Matcher in der Testdatei hinzu und aktualisiert es (anstelle einer externen
.snap
-Datei).tsimport { expect, test } from 'vitest'; test('matches inline snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; // Vitest passt den folgenden Inhalt beim Aktualisieren des Snapshots an expect(data).toMatchInlineSnapshot(` { "foo": Set { "bar", "snapshot", }, } `); });
Sie können auch eine Form eines Objekts angeben, wenn Sie nur die Struktur eines Objekts testen und keine 100%ige Übereinstimmung benötigen:
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>
Version: Seit Vitest 0.30.0
Vergleicht oder aktualisiert den Snapshot mit dem Inhalt einer explizit angegebenen Datei (anstelle der
.snap
-Datei).tsimport { expect, it } from 'vitest'; it('render basic', async () => { const result = renderHTML(h('div', { class: 'foo' })); await expect(result).toMatchFileSnapshot('./test/basic.output.html'); });
Beachten Sie, dass Sie
await
mittoMatchFileSnapshot()
verwenden müssen, da die Dateisystemoperation asynchron abläuft.
toThrowErrorMatchingSnapshot
Typ:
(message?: string) => void
Funktioniert wie
toMatchSnapshot
, erwartet aber den gleichen Wert wietoThrowError
.Wenn die Funktion einen
Error
auslöst, ist die Fehlermeldung der Snapshot. Andernfalls ist der Snapshot der von der Funktion ausgelöste Wert.
toThrowErrorMatchingInlineSnapshot
Typ:
(snapshot?: string, message?: string) => void
Funktioniert wie
toMatchInlineSnapshot
, erwartet aber den gleichen Wert wietoThrowError
.Wenn die Funktion einen
Error
auslöst, ist die Fehlermeldung der Snapshot. Andernfalls ist der Snapshot der von der Funktion ausgelöste Wert.
toHaveBeenCalled
Typ:
() => Awaitable<void>
Diese Assertion prüft, ob eine Funktion aufgerufen wurde. Erfordert eine Mock-Funktion als Parameter für
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>
Diese Assertion prüft, ob eine Funktion eine bestimmte Anzahl von Malen aufgerufen wurde. Erfordert eine Mock-Funktion als Parameter für 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>
Diese Assertion prüft, ob eine Funktion mindestens einmal mit bestimmten Parametern aufgerufen wurde. Erfordert eine Mock-Funktion als Parameter für 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>
Diese Assertion prüft, ob eine Funktion bei ihrem letzten Aufruf mit bestimmten Parametern aufgerufen wurde. Erfordert eine Mock-Funktion als Parameter für 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>
Diese Assertion prüft, ob eine Funktion zum n-ten Mal mit bestimmten Parametern aufgerufen wurde. Die Nummerierung beginnt bei 1. Um also den zweiten Aufruf zu überprüfen, würden Sie .toHaveBeenNthCalledWith(2, ...)
schreiben.
Erfordert eine Mock-Funktion als Parameter für 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>
Diese Assertion prüft, ob eine Funktion mindestens einmal erfolgreich einen Wert zurückgegeben hat (d. h. keine Exception ausgelöst hat). Erfordert eine Mock-Funktion als Parameter für 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>
Diese Assertion prüft, ob eine Funktion genau die angegebene Anzahl an Malen erfolgreich einen Wert zurückgegeben hat (d. h. keine Exception ausgelöst hat). Erfordert eine Mock-Funktion als Parameter für 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>
Mit dieser Assertion können Sie prüfen, ob eine Funktion mindestens einmal erfolgreich einen Wert mit bestimmten Parametern zurückgegeben hat. Dies erfordert, dass Sie eine Spy-Funktion an expect
übergeben.
import { expect, test, vi } from 'vitest';
test('Spy-Funktion gibt ein Produkt zurück', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
expect(sell).toHaveReturnedWith({ product: 'apples' });
});
toHaveLastReturnedWith
- Typ:
(returnValue: any) => Awaitable<void>
Mit dieser Assertion können Sie prüfen, ob eine Funktion beim letzten Aufruf erfolgreich einen Wert mit bestimmten Parametern zurückgegeben hat. Dies erfordert, dass Sie eine Spy-Funktion an expect
übergeben.
import { expect, test, vi } from 'vitest';
test('Spy-Funktion gibt beim letzten Aufruf Bananen zurück', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveLastReturnedWith({ product: 'bananas' });
});
toHaveNthReturnedWith
- Typ:
(time: number, returnValue: any) => Awaitable<void>
Mit dieser Assertion können Sie prüfen, ob eine Funktion bei einem bestimmten Aufruf erfolgreich einen Wert mit bestimmten Parametern zurückgegeben hat. Dies erfordert, dass Sie eine Spy-Funktion an expect
übergeben.
import { expect, test, vi } from 'vitest';
test('Spy-Funktion gibt beim zweiten Aufruf Bananen zurück', () => {
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>
Diese Assertion prüft, ob ein Wert ein bestimmtes Prädikat erfüllt.
describe('toSatisfy()', () => {
const isOdd = (value: number) => value % 2 !== 0;
it('besteht mit 0', () => {
expect(1).toSatisfy(isOdd);
});
it('besteht mit Verhandlung', () => {
expect(2).not.toSatisfy(isOdd);
});
});
resolves
- Typ:
Promisify<Assertions>
resolves
vereinfacht das Assertieren von asynchronem Code. Verwenden Sie es, um den Wert eines Promises zu extrahieren und ihn mit üblichen Assertions zu prüfen. Wenn das Promise fehlschlägt (rejected wird), schlägt die Assertion fehl.
Es gibt dasselbe Assertions
-Objekt zurück, aber alle Matcher geben jetzt ein Promise
zurück, sodass Sie await
verwenden müssen. Funktioniert auch mit chai
-Assertions.
Wenn Sie beispielsweise eine Funktion haben, die einen API-Aufruf durchführt und Daten zurückgibt, können Sie diesen Code verwenden, um den Rückgabewert zu prüfen:
import { expect, test } from 'vitest';
async function buyApples() {
return fetch('/buy/apples').then(r => r.json());
}
test('buyApples gibt neue Lager-ID zurück', async () => {
// toEqual gibt jetzt ein Promise zurück, also müssen Sie es abwarten
await expect(buyApples()).resolves.toEqual({ id: 1 }); // jest API
await expect(buyApples()).resolves.to.equal({ id: 1 }); // chai API
});
WARNING
Wenn die Assertion nicht mit await
erwartet wird, erhalten Sie einen falsch positiven Test, der immer bestanden wird. Um sicherzustellen, dass Assertions tatsächlich ausgeführt werden, können Sie expect.assertions(number)
verwenden.
rejects
- Typ:
Promisify<Assertions>
rejects
vereinfacht das Assertieren von asynchronem Code. Verwenden Sie es, um den Grund für die Ablehnung (rejection) des Promises zu extrahieren und ihn mit üblichen Assertions zu prüfen. Wenn das Promise erfolgreich aufgelöst wird (resolved wird), schlägt die Assertion fehl.
Es gibt dasselbe Assertions
-Objekt zurück, aber alle Matcher geben jetzt ein Promise
zurück, sodass Sie await
verwenden müssen. Funktioniert auch mit chai
-Assertions.
Wenn Sie beispielsweise eine Funktion haben, die fehlschlägt, wenn Sie sie aufrufen, können Sie diesen Code verwenden, um den Grund zu prüfen:
import { expect, test } from 'vitest';
async function buyApples(id) {
if (!id) throw new Error('no id');
}
test('buyApples wirft einen Fehler aus, wenn keine ID angegeben wurde', async () => {
// toThrow gibt jetzt ein Promise zurück, also müssen Sie es abwarten
await expect(buyApples()).rejects.toThrow('no id');
});
WARNING
Wenn die Assertion nicht mit await
erwartet wird, erhalten Sie einen falsch positiven Test, der immer bestanden wird. Um sicherzustellen, dass Assertions tatsächlich ausgeführt wurden, können Sie expect.assertions(number)
verwenden.
expect.assertions
- Typ:
(count: number) => void
Überprüft, nachdem der Test bestanden oder fehlgeschlagen ist, ob eine bestimmte Anzahl von Assertions während eines Tests ausgeführt wurde. Dies ist nützlich, um zu prüfen, ob asynchroner Code ausgeführt wurde.
Wenn wir beispielsweise eine Funktion haben, die asynchron zwei Matcher aufruft, können wir prüfen, ob sie tatsächlich ausgeführt wurden.
import { expect, test } from 'vitest';
async function doAsync(...cbs) {
await Promise.all(cbs.map((cb, index) => cb({ index })));
}
test('alle Assertions werden ausgeführt', async () => {
expect.assertions(2);
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}
await doAsync(callback1, callback2);
});
WARNING
Bei Verwendung von assertions
mit asynchronen, gleichzeitigen Tests muss expect
aus dem lokalen Testkontext verwendet werden, um sicherzustellen, dass der richtige Test erkannt wird.
expect.hasAssertions
- Typ:
() => void
Überprüft, nachdem der Test bestanden oder fehlgeschlagen ist, ob mindestens eine Assertion während eines Tests aufgerufen wurde. Dies ist nützlich, um zu prüfen, ob asynchroner Code aufgerufen wurde.
Wenn Sie beispielsweise Code haben, der einen Callback aufruft, können wir eine Assertion innerhalb eines Callbacks machen, aber der Test würde trotzdem bestanden, selbst wenn keine Assertion aufgerufen wurde.
import { expect, test } from 'vitest';
import { db } from './db.js';
const cbs = [];
function onSelect(cb) {
cbs.push(cb);
}
// nach dem Auswählen aus der Datenbank rufen wir alle Callbacks auf
function select(id) {
return db.select({ id }).then(data => {
return Promise.all(cbs.map(cb => cb(data)));
});
}
test('Der Callback wurde aufgerufen', async () => {
expect.hasAssertions();
onSelect(data => {
// sollte bei select aufgerufen werden
expect(data).toBeTruthy();
});
// wenn nicht mit `await` erwartet, schlägt der Test fehl
// wenn Sie expect.hasAssertions() nicht haben, wird der Test bestanden
await select(3);
});
expect.unreachable
- Typ:
(message?: string) => never
Diese Methode wird verwendet, um zu bestätigen, dass eine bestimmte Codezeile niemals erreicht werden sollte.
Wenn wir beispielsweise testen möchten, dass build()
aufgrund des Empfangs von Verzeichnissen ohne src
-Ordner einen Fehler auslöst, und auch jeden Fehler separat behandeln möchten, könnten wir Folgendes tun:
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 schlägt mit "%s" fehl', async dir => {
try {
await build(dir);
expect.unreachable('Der Build sollte nicht bestehen');
} 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:
// um alle Fehlerfälle abzudecken
expect.unreachable('Alle Fehlertests müssen behandelt werden');
break;
}
}
});
expect.anything
- Typ:
() => any
Dieser asymmetrische Matcher gibt bei Verwendung mit einer Gleichheitsprüfung immer true
zurück. Nützlich, wenn Sie nur sicherstellen möchten, dass die Eigenschaft vorhanden ist.
import { expect, test } from 'vitest';
test('Objekt hat den Schlüssel "apples"', () => {
expect({ apples: 22 }).toEqual({ apples: expect.anything() });
});
expect.any
- Typ:
(constructor: unknown) => any
Dieser asymmetrische Matcher gibt bei Verwendung mit einer Gleichheitsprüfung nur dann true
zurück, wenn der Wert eine Instanz eines angegebenen Konstruktors ist. Nützlich, wenn Sie einen Wert haben, der jedes Mal generiert wird, und Sie nur wissen möchten, dass er mit einem geeigneten Typ vorhanden ist.
import { expect, test } from 'vitest';
import { generateId } from './generators.js';
test('"id" ist eine Zahl', () => {
expect({ id: generateId() }).toEqual({ id: expect.any(Number) });
});
expect.arrayContaining
- Typ:
<T>(expected: T[]) => any
Bei Verwendung mit einer Gleichheitsprüfung gibt dieser asymmetrische Matcher true
zurück, wenn der Wert ein Array ist und die angegebenen Elemente enthält.
import { expect, test } from 'vitest';
test('Der Korb enthält Fuji-Äpfel', () => {
const basket = {
varieties: ['Empire', 'Fuji', 'Gala'],
count: 3,
};
expect(basket).toEqual({
count: 3,
varieties: expect.arrayContaining(['Fuji']),
});
});
TIP
Sie können expect.not
mit diesem Matcher verwenden, um den erwarteten Wert zu negieren.
expect.objectContaining
- Typ:
(expected: any) => any
Bei Verwendung mit einer Gleichheitsprüfung gibt dieser asymmetrische Matcher true
zurück, wenn der Wert eine ähnliche Form hat.
import { expect, test } from 'vitest';
test('Der Korb hat Empire-Äpfel', () => {
const basket = {
varieties: [
{
name: 'Empire',
count: 1,
},
],
};
expect(basket).toEqual({
varieties: [expect.objectContaining({ name: 'Empire' })],
});
});
TIP
Sie können expect.not
mit diesem Matcher verwenden, um den erwarteten Wert zu negieren.
expect.stringContaining
- Typ:
(expected: any) => any
Bei Verwendung mit einer Gleichheitsprüfung gibt dieser asymmetrische Matcher true
zurück, wenn der Wert eine Zeichenkette ist und eine angegebene Teilzeichenkette enthält.
import { expect, test } from 'vitest';
test('Die Apfelsorte enthält "Emp" im Namen', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringContaining('Emp'),
count: 1,
});
});
TIP
Sie können expect.not
mit diesem Matcher verwenden, um den erwarteten Wert zu negieren.
expect.stringMatching
- Typ:
(expected: any) => any
Bei Verwendung mit einer Gleichheitsprüfung gibt dieser asymmetrische Matcher true
zurück, wenn der Wert eine Zeichenkette ist und eine angegebene Teilzeichenkette enthält oder wenn die Zeichenkette einem regulären Ausdruck entspricht.
import { expect, test } from 'vitest';
test('Die Sorte endet mit "re"', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringMatching(/re$/),
count: 1,
});
});
TIP
Sie können expect.not
mit diesem Matcher verwenden, um den erwarteten Wert zu negieren.
expect.addSnapshotSerializer
- Typ:
(plugin: PrettyFormatPlugin) => void
Diese Methode fügt benutzerdefinierte Serialisierer hinzu, die beim Erstellen eines Snapshots aufgerufen werden. Dies ist eine erweiterte Funktion - wenn Sie mehr erfahren möchten, lesen Sie bitte eine Anleitung zu benutzerdefinierten Serialisierern.
Wenn Sie benutzerdefinierte Serialisierer hinzufügen, sollten Sie diese Methode innerhalb von setupFiles
aufrufen. Dies wirkt sich auf jeden Snapshot aus.
TIP
Wenn Sie zuvor Vue CLI mit Jest verwendet haben, sollten Sie jest-serializer-vue installieren. Andernfalls werden Ihre Snapshots in eine Zeichenkette eingeschlossen, wodurch die Zeichen "
maskiert werden müssen.
expect.extend
- Typ:
(matchers: MatchersObject) => void
Sie können Standard-Matcher mit Ihren eigenen erweitern. Diese Funktion wird verwendet, um das Matcher-Objekt mit benutzerdefinierten Matchern zu erweitern.
Wenn Sie Matcher auf diese Weise definieren, erstellen Sie auch asymmetrische Matcher, die wie expect.stringContaining
verwendet werden können.
import { expect, test } from 'vitest';
test('Benutzerdefinierte Matcher', () => {
expect.extend({
toBeFoo: (received, expected) => {
if (received !== 'foo') {
return {
message: () => `erwartet, dass ${received} gleich foo ist`,
pass: false,
};
}
},
});
expect('foo').toBeFoo();
expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() });
});
TIP
Wenn Ihre Matcher in jedem Test verfügbar sein sollen, sollten Sie diese Methode innerhalb von setupFiles
aufrufen.
Diese Funktion ist mit Jests expect.extend
kompatibel, sodass jede Bibliothek, die sie zum Erstellen benutzerdefinierter Matcher verwendet, mit Vitest funktioniert.
Wenn Sie TypeScript verwenden, können Sie seit Vitest 0.31.0 die Standard-Assertion
-Schnittstelle in einer Ambient-Deklarationsdatei (z. B. vitest.d.ts
) mit dem folgenden Code erweitern:
interface CustomMatchers<R = unknown> {
toBeFoo(): R;
}
declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}
WARNING
Vergessen Sie nicht, die Ambient-Deklarationsdatei in Ihre tsconfig.json
aufzunehmen.
TIP
Wenn Sie mehr erfahren möchten, lesen Sie die Anleitung zum Erweitern von Matchern.