expect
В приведенных ниже сигнатурах типов используются следующие типы:
type Awaitable<T> = T | PromiseLike<T>;expect используется для создания утверждений. В данном контексте, утверждения — это функции, которые проверяют, выполняется ли определенное условие. Vitest по умолчанию предоставляет утверждения chai, а также утверждения, совместимые с Jest, основанные на chai.
Например, этот код утверждает, что значение input равно 2. Если это не так, утверждение вызовет ошибку, и тест завершится неудачей.
import { expect } from 'vitest';
const input = Math.sqrt(4);
expect(input).to.equal(2); // chai API
expect(input).toBe(2); // jest APIТехнически, этот пример не использует функцию test, поэтому в консоли вы увидите ошибку Node.js вместо вывода Vitest. Чтобы узнать больше о test, обратитесь к Test API Reference.
Кроме того, expect можно использовать статически для доступа к функциям сопоставления, описанным далее, и другим возможностям.
WARNING
expect не влияет на проверку типов, если в выражении нет ошибки типа. Если вы хотите использовать Vitest для проверки типов, используйте expectTypeOf или assertType.
soft
- Тип:
ExpectStatic & (actual: any) => Assertions
expect.soft работает аналогично expect, но вместо того, чтобы завершать выполнение теста при неудачном утверждении, он продолжает выполняться и помечает неудачу как сбой теста. Все ошибки, возникшие во время теста, будут показаны после его завершения.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // помечает тест как провалившийся и продолжает выполнение
expect.soft(1 + 2).toBe(4); // помечает тест как провалившийся и продолжает выполнение
});
// В конце теста будут выведены вышеуказанные ошибки.Его также можно использовать вместе с expect. Если утверждение expect завершается неудачей, тест будет завершен, и все ошибки будут отображены.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // помечает тест как провалившийся и продолжает выполнение
expect(1 + 2).toBe(3); // провалился и завершил тест, все предыдущие ошибки будут выведены
expect.soft(1 + 2).toBe(4); // не выполняется
});WARNING
expect.soft можно использовать только внутри функции test.
not
Использование not инвертирует утверждение. Например, этот код утверждает, что значение input не равно 2. Если оно равно, утверждение вызовет ошибку, и тест завершится неудачей.
import { expect, test } from 'vitest';
const input = Math.sqrt(16);
expect(input).not.to.equal(2); // chai API
expect(input).not.toBe(2); // jest APItoBe
Тип:
(value: any) => Awaitable<void>toBeможно использовать для утверждения, равны ли примитивы, или что объекты имеют одну и ту же ссылку. Это аналогично вызовуexpect(Object.is(3, 3)).toBe(true). Если объекты не совпадают, но вы хотите проверить, идентичны ли их структуры, используйтеtoEqual.Например, код ниже проверяет, есть ли у трейдера 13 яблок.
tsimport { 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; // same reference expect(stock).toBe(refStock); });Старайтесь не использовать
toBeс числами с плавающей точкой. Поскольку JavaScript округляет их,0.1 + 0.2не является строго0.3. Чтобы надежно утверждать числа с плавающей точкой, используйте утверждениеtoBeCloseTo.
toBeCloseTo
Тип:
(value: number, numDigits?: number) => Awaitable<void>Используйте
toBeCloseToдля сравнения чисел с плавающей точкой. Необязательный аргументnumDigitsуказывает, сколько знаков после запятой следует учитывать при сравнении. Например:tsimport { expect, test } from 'vitest'; test.fails('decimals are not equal in javascript', () => { expect(0.2 + 0.1).toBe(0.3); // 0.2 + 0.1 is 0.30000000000000004 }); test('decimals are rounded to 5 after the point', () => { // 0.2 + 0.1 is 0.30000 | "000000000004" removed expect(0.2 + 0.1).toBeCloseTo(0.3, 5); // nothing from 0.30000000000000004 is removed expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50); });
toBeDefined
Тип:
() => Awaitable<void>toBeDefinedпроверяет, что значение не равноundefined. Полезно для проверки, возвращает ли функция какое-либо значение.tsimport { expect, test } from 'vitest'; function getApples() { return 3; } test('function returned something', () => { expect(getApples()).toBeDefined(); });
toBeUndefined
Тип:
() => Awaitable<void>Обратное утверждение
toBeDefined,toBeUndefinedпроверяет, что значение равноundefined. Полезно для проверки, не возвращает ли функция какое-либо значение.tsimport { expect, test } from 'vitest'; function getApplesFromStock(stock) { if (stock === 'Bill') return 13; } test("mary doesn't have a stock", () => { expect(getApplesFromStock('Mary')).toBeUndefined(); });
toBeTruthy
Тип:
() => Awaitable<void>toBeTruthyпроверяет, что значение истинно при преобразовании в boolean. Полезно, когда важен не сам результат, а возможность его приведения кtrue.Например, имея этот код, вам не важно возвращаемое значение
stocks.getInfo- это может быть сложный объект, строка или что-то еще. Код все равно будет работать.tsimport { Stocks } from './stocks.js'; const stocks = new Stocks(); stocks.sync('Bill'); if (stocks.getInfo('Bill')) stocks.sell('apples', 'Bill');Итак, если вы хотите проверить, что
stocks.getInfoбудет истинным, вы можете написать:tsimport { 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(); });В JavaScript любое значение считается истинным, кроме
false,0,'',null,undefinedиNaN.
toBeFalsy
Тип:
() => Awaitable<void>toBeFalsyпроверяет, что значение ложно при преобразовании в boolean. Полезно, когда важен не сам результат, а возможность его приведения кfalse.Например, имея этот код, вам не важно возвращаемое значение
stocks.stockFailed- он может вернуть любое ложное значение, но код все равно будет работать.tsimport { Stocks } from './stocks.js'; const stocks = new Stocks(); stocks.sync('Bill'); if (!stocks.stockFailed('Bill')) stocks.sell('apples', 'Bill');Итак, если вы хотите проверить, что
stocks.stockFailedбудет ложным, вы можете написать:tsimport { 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(); });В JavaScript любое значение считается истинным, кроме
false,0,'',null,undefinedиNaN.
toBeNull
Тип:
() => Awaitable<void>toBeNullпросто проверяет, является ли что-тоnull. Это псевдоним для.toBe(null).tsimport { expect, test } from 'vitest'; function apples() { return null; } test("we don't have apples", () => { expect(apples()).toBeNull(); });
toBeNaN
Тип:
() => Awaitable<void>toBeNaNпросто проверяет, является ли что-тоNaN. Это псевдоним для.toBe(NaN).tsimport { 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
Тип:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>toBeTypeOfпроверяет, имеет ли фактическое значение тип, соответствующий полученному типу.tsimport { expect, test } from 'vitest'; const actual = 'stock'; test('stock is type of string', () => { expect(actual).toBeTypeOf('string'); });
toBeInstanceOf
Тип:
(c: any) => Awaitable<void>toBeInstanceOfпроверяет, является ли фактическое значение экземпляром полученного класса.tsimport { expect, test } from 'vitest'; import { Stocks } from './stocks.js'; const stocks = new Stocks(); test('stocks are instance of Stocks', () => { expect(stocks).toBeInstanceOf(Stocks); });
toBeGreaterThan
Тип:
(n: number | bigint) => Awaitable<void>toBeGreaterThanпроверяет, что фактическое значение больше полученного. Равные значения приведут к сбою теста.tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have more then 10 apples', () => { expect(getApples()).toBeGreaterThan(10); });
toBeGreaterThanOrEqual
Тип:
(n: number | bigint) => Awaitable<void>toBeGreaterThanOrEqualпроверяет, что фактическое значение больше полученного или равно ему.tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have 11 apples or more', () => { expect(getApples()).toBeGreaterThanOrEqual(11); });
toBeLessThan
Тип:
(n: number | bigint) => Awaitable<void>toBeLessThanпроверяет, что фактическое значение меньше полученного. Равные значения приведут к сбою теста.tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have less then 20 apples', () => { expect(getApples()).toBeLessThan(20); });
toBeLessThanOrEqual
Тип:
(n: number | bigint) => Awaitable<void>toBeLessThanOrEqualпроверяет, что фактическое значение меньше полученного или равно ему.tsimport { expect, test } from 'vitest'; import { getApples } from './stocks.js'; test('have 11 apples or less', () => { expect(getApples()).toBeLessThanOrEqual(11); });
toEqual
Тип:
(received: any) => Awaitable<void>toEqualпроверяет, что фактическое значение равно полученному или имеет ту же структуру, если это объект (сравнивает их рекурсивно). Разница междуtoEqualиtoBeпоказана в следующем примере:tsimport { 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
Глубокое сравнение на равенство не будет выполняться для объектов
Error. Чтобы проверить, было ли что-то выброшено, используйте утверждениеtoThrowError.
toStrictEqual
Тип:
(received: any) => Awaitable<void>toStrictEqualпроверяет, что фактическое значение равно полученному или имеет ту же структуру, если это объект (сравнивает их рекурсивно), и того же типа.Отличия от
.toEqual:- Проверяются ключи со свойствами
undefined. Например,{a: undefined, b: 2}не соответствует{b: 2}при использовании.toStrictEqual. - Проверяется наличие пропусков в массиве. Например,
[, 1]не соответствует[undefined, 1]при использовании.toStrictEqual. - Проверяется идентичность типов объектов. Например, экземпляр класса с полями
aиbне будет эквивалентен литеральному объекту с полямиaиb.
tsimport { 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
Тип:
(received: string) => Awaitable<void>toContainпроверяет, содержится ли фактическое значение в массиве.toContainтакже может проверить, является ли строка подстрокой другой строки.tsimport { expect, test } from 'vitest'; import { getAllFruits } from './stocks.js'; test('the fruit list contains orange', () => { expect(getAllFruits()).toContain('orange'); });
toContainEqual
Тип:
(received: any) => Awaitable<void>toContainEqualпроверяет, что элемент с определенной структурой и значениями содержится в массиве. Он работает какtoEqualвнутри для каждого элемента.tsimport { expect, test } from 'vitest'; import { getFruitStock } from './stocks.js'; test('apple available', () => { expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 }); });
toHaveLength
Тип:
(received: number) => Awaitable<void>toHaveLengthпроверяет, имеет ли объект свойство.lengthс определенным числовым значением.tsimport { expect, test } from 'vitest'; test('toHaveLength', () => { expect('abc').toHaveLength(3); expect([1, 2, 3]).toHaveLength(3); expect('').not.toHaveLength(3); // не имеет .length равным 3 expect({ length: 3 }).toHaveLength(3); });
toHaveProperty
Type:
(key: any, received?: any) => Awaitable<void>toHavePropertyпроверяет наличие свойства с указанным ключомkeyв объекте.Вы можете также передать необязательный аргумент
valueдля сравнения значения свойства с ожидаемым значением (глубокое равенство, как вtoEqual).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); // Проверяет, что ключ существует и значение равно 5000 expect(invoice).not.toHaveProperty('account'); // Проверяет, что ключ не существует // Доступ к вложенным свойствам через точечную нотацию expect(invoice).toHaveProperty('customer.first_name'); expect(invoice).toHaveProperty('customer.last_name', 'Doe'); expect(invoice).not.toHaveProperty('customer.location', 'India'); // Доступ к вложенным свойствам через массив, содержащий ключ expect(invoice).toHaveProperty('items[0].type', 'apples'); expect(invoice).toHaveProperty('items.0.type', 'apples'); // Точечная нотация также работает // Доступ к вложенным свойствам через массив, содержащий путь к ключу expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples'); expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // Строковая нотация также работает // Заключите ключ в массив, чтобы избежать его интерпретации как пути к вложенному свойству expect(invoice).toHaveProperty(['P.O'], '12345'); });
toMatch
Type:
(received: string | regexp) => Awaitable<void>toMatchпроверяет, соответствует ли строка регулярному выражению или другой строке.tsimport { expect, test } from 'vitest'; test('top fruits', () => { expect('top fruits include apple, orange and grape').toMatch(/apple/); expect('applefruits').toMatch('fruit'); // toMatch также принимает строку });
TIP
Если сообщение об ошибке слишком короткое, вы можете увеличить значение параметра chaiConfig.truncateThreshold в вашем файле конфигурации: chaiConfig.truncateThreshold.
toMatchObject
Type:
(received: object | array) => Awaitable<void>toMatchObjectпроверяет, содержит ли объект подмножество свойств другого объекта.Вы также можете передать массив объектов. Это полезно, если вы хотите проверить, что два массива содержат одинаковое количество элементов и соответствующие элементы совпадают, в отличие от
arrayContaining, который допускает наличие дополнительных элементов в проверяемом массиве.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', () => { // Проверяет, что массивы объектов совпадают expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([ { foo: 'bar' }, { baz: 1 }, ]); });
toThrowError
Type:
(received: any) => Awaitable<void>Alias:
toThrowtoThrowErrorпроверяет, выбрасывает ли функция ошибку при вызове.Вы можете передать необязательный аргумент для проверки типа выбрасываемой ошибки:
- regular expression: сообщение об ошибке соответствует регулярному выражению
- string: сообщение об ошибке содержит указанную подстроку
TIP
Обязательно оберните код в функцию, иначе ошибка не будет перехвачена, и тест завершится неудачей.
Например, чтобы проверить, что
getFruitStock('pineapples')выбрасывает ошибку, можно написать:tsimport { expect, test } from 'vitest'; function getFruitStock(type) { if (type === 'pineapples') throw new DiabetesError( 'Pineapples are not good for people with diabetes' ); // Выполнение других действий } test('throws on pineapples', () => { // Проверяет, что сообщение об ошибке содержит "diabetes": эти записи эквивалентны expect(() => getFruitStock('pineapples')).toThrowError(/diabetes/); expect(() => getFruitStock('pineapples')).toThrowError('diabetes'); // Проверяет точное сообщение об ошибке expect(() => getFruitStock('pineapples')).toThrowError( /^Pineapples are not good for people with diabetes$/ ); });TIP
Для тестирования асинхронных функций используйте в сочетании с rejects.
jsfunction getAsyncFruitStock() { return Promise.reject(new Error('empty')); } test('throws on pineapples', async () => { await expect(() => getAsyncFruitStock()).rejects.toThrowError('empty'); });
toMatchSnapshot
Type:
<T>(shape?: Partial<T> | string, message?: string) => voidПроверяет, что значение соответствует сохраненному снимку (snapshot).
Вы можете передать необязательный строковый аргумент
hint, который будет добавлен к имени теста. Vitest всегда добавляет число в конце имени снимка, но короткие описательные подсказки могут быть полезнее чисел для различения нескольких снимков в одном блокеitилиtest. Vitest сортирует снимки по имени в соответствующем файле.snap.TIP
Когда снимок не совпадает и тест завершается с ошибкой, вы можете нажать клавишу
uдля однократного обновления снимка. Или вы можете использовать параметры командной строки-uили--update, чтобы Vitest всегда обновлял снимки.tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchSnapshot(); });Вы также можете предоставить структуру объекта (shape of an object), если вы тестируете только структуру объекта и не требуете 100% соответствия данным:
tsimport { expect, test } from 'vitest'; test('matches snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; expect(data).toMatchSnapshot({ foo: expect.any(Set) }); });
toMatchInlineSnapshot
Type:
<T>(shape?: Partial<T> | string, snapshot?: string, message?: string) => voidПроверяет, что значение соответствует встроенному снимку (inline snapshot).
Vitest добавляет и обновляет строковый аргумент
inlineSnapshotдля матчера непосредственно в файле теста (вместо внешнего файла.snap).tsimport { expect, test } from 'vitest'; test('matches inline snapshot', () => { const data = { foo: new Set(['bar', 'snapshot']) }; // Vitest обновит следующее содержимое при обновлении моментального снимка expect(data).toMatchInlineSnapshot(` { "foo": Set { "bar", "snapshot", }, } `); });Вы также можете предоставить структуру объекта, если вы тестируете только структуру объекта и не требуете 100% соответствия данным:
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
Type:
<T>(filepath: string, message?: string) => Promise<void>Version: Since Vitest 0.30.0
Сравнивает или обновляет снимок с содержимым файла, указанного явно (вместо файла
.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'); });Обратите внимание, что поскольку операция с файловой системой является асинхронной, необходимо использовать
awaitсtoMatchFileSnapshot().
toThrowErrorMatchingSnapshot
Type:
(message?: string) => voidАналогичен
toMatchSnapshot, но применяется к значению, которое, как ожидается, будет выброшено функцией (как вtoThrowError).Если функция выбрасывает
Error, снимком будет сообщение об ошибке. В противном случае снимком будет значение, выброшенное функцией.
toThrowErrorMatchingInlineSnapshot
Type:
(snapshot?: string, message?: string) => voidАналогичен
toMatchInlineSnapshot, но применяется к значению, которое, как ожидается, будет выброшено функцией (как вtoThrowError).Если функция выбрасывает
Error, снимком будет сообщение об ошибке. В противном случае снимком будет значение, выброшенное функцией.
toHaveBeenCalled
Type:
() => Awaitable<void>Проверяет, была ли вызвана функция. Требует, чтобы в
expectбыла передана шпионская функция (spy function).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
- Type:
(amount: number) => Awaitable<void>
Проверяет, что функция была вызвана указанное количество раз. Требует, чтобы в expect была передана шпионская функция.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function called two times', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenCalledTimes(2);
});toHaveBeenCalledWith
- Type:
(...args: any[]) => Awaitable<void>
Проверяет, что функция была вызвана хотя бы один раз с указанными аргументами. Требует, чтобы в 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
- Type:
(...args: any[]) => Awaitable<void>
Проверяет, что при последнем вызове функция была вызвана с указанными аргументами. Требует, чтобы в expect была передана шпионская функция.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).not.toHaveBeenLastCalledWith('apples', 10);
expect(buySpy).toHaveBeenLastCalledWith('apples', 20);
});toHaveBeenNthCalledWith
- Type:
(time: number, ...args: any[]) => Awaitable<void>
Проверяет, была ли функция вызвана с определенными аргументами при конкретном вызове (нумерация начинается с 1). Например, чтобы проверить второй вызов, используйте .toHaveBeenNthCalledWith(2, ...) .
Требует, чтобы в expect была передана шпионская функция.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('first call of spy function called with right params', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenNthCalledWith(1, 'apples', 10);
});toHaveReturned
- Type:
() => Awaitable<void>
Проверяет, вернула ли функция какое-либо значение хотя бы один раз (успешно, без выброса ошибки). Требует, чтобы в expect была передана шпионская функция.
import { expect, test, vi } from 'vitest';
function getApplesPrice(amount: number) {
const PRICE = 10;
return amount * PRICE;
}
test('spy function returned a value', () => {
const getPriceSpy = vi.fn(getApplesPrice);
const price = getPriceSpy(10);
expect(price).toBe(100);
expect(getPriceSpy).toHaveReturned();
});toHaveReturnedTimes
- Type:
(amount: number) => Awaitable<void>
Проверяет, что функция успешно вернула значение указанное количество раз (т.е. не выбрасывала ошибку). Требует, чтобы в 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
- Тип:
(returnValue: any) => Awaitable<void>
Вы можете использовать это утверждение, чтобы проверить, возвращала ли функция значение, соответствующее указанному, хотя бы один раз. Шпион (spy function) должен быть передан в expect.
import { expect, test, vi } from 'vitest';
test('spy function returns a product', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
expect(sell).toHaveReturnedWith({ product: 'apples' });
});toHaveLastReturnedWith
- Тип:
(returnValue: any) => Awaitable<void>
Вы можете использовать это утверждение, чтобы проверить, возвращала ли функция значение, соответствующее указанному, при последнем вызове. Шпион (spy function) должен быть передан в expect.
import { expect, test, vi } from 'vitest';
test('spy function returns bananas on a last call', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveLastReturnedWith({ product: 'bananas' });
});toHaveNthReturnedWith
- Тип:
(time: number, returnValue: any) => Awaitable<void>
Вы можете использовать это утверждение, чтобы проверить, возвращала ли функция значение, соответствующее указанному, при определенном вызове (например, при втором вызове). Шпион (spy function) должен быть передан в expect.
import { expect, test, vi } from 'vitest';
test('spy function returns bananas on second call', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveNthReturnedWith(2, { product: 'bananas' });
});toSatisfy
- Тип:
(predicate: (value: any) => boolean) => Awaitable<void>
Это утверждение проверяет, удовлетворяет ли значение заданному предикату (функции, возвращающей true или false).
describe('toSatisfy()', () => {
const isOdd = (value: number) => value % 2 !== 0;
it('pass with 0', () => {
expect(1).toSatisfy(isOdd);
});
it('pass with negotiation', () => {
expect(2).not.toSatisfy(isOdd);
});
});resolves
Тип:
Promisify<Assertions>resolvesупрощает утверждения для асинхронного кода. Используйте его, чтобы получить значение из разрешенного промиса и проверить его с помощью обычных утверждений. Если промис отклоняется, утверждение завершится с ошибкой.Он возвращает тот же объект
Assertions, но теперь все матчеры возвращаютPromise, поэтому необходимо использоватьawait. Также работает с утверждениямиchai.Например, если у вас есть функция, которая выполняет вызов API и возвращает данные, вы можете использовать следующий код для проверки возвращаемого значения:
tsimport { expect, test } from 'vitest'; async function buyApples() { return fetch('/buy/apples').then(r => r.json()); } test('buyApples returns new stock id', async () => { // toEqual теперь возвращает промис, поэтому вы ДОЛЖНЫ дождаться его await expect(buyApples()).resolves.toEqual({ id: 1 }); // jest API await expect(buyApples()).resolves.to.equal({ id: 1 }); // chai API });WARNING
Если не дождаться выполнения утверждения, тест может дать ложноположительный результат. Чтобы убедиться, что утверждения действительно вызываются, используйте
expect.assertions(number).
rejects
Тип:
Promisify<Assertions>rejectsупрощает утверждения для асинхронного кода. Используйте его, чтобы получить причину отклонения промиса и проверить ее с помощью обычных утверждений. Если промис успешно разрешается, утверждение завершится с ошибкой.Он возвращает тот же объект
Assertions, но теперь все матчеры возвращаютPromise, поэтому необходимо использоватьawait. Также работает с утверждениямиchai.Например, если у вас есть функция, которая завершается с ошибкой при вызове, вы можете использовать следующий код для проверки причины ошибки:
tsimport { expect, test } from 'vitest'; async function buyApples(id) { if (!id) throw new Error('no id'); } test('buyApples throws an error when no id provided', async () => { // toThrow теперь возвращает промис, поэтому вы ДОЛЖНЫ дождаться его await expect(buyApples()).rejects.toThrow('no id'); });WARNING
Если не дождаться выполнения утверждения, тест может дать ложноположительный результат. Чтобы убедиться, что утверждения действительно вызываются, используйте
expect.assertions(number).
expect.assertions
Тип:
(count: number) => voidПроверяет, было ли вызвано указанное количество утверждений после завершения теста (независимо от того, пройден он или нет). Это полезно для проверки того, был ли вызван асинхронный код.
Например, если у нас есть функция, которая асинхронно вызывает два матчера, мы можем убедиться, что они действительно были вызваны.
tsimport { expect, test } from 'vitest'; async function doAsync(...cbs) { await Promise.all(cbs.map((cb, index) => cb({ index }))); } test('all assertions are called', async () => { expect.assertions(2); function callback1(data) { expect(data).toBeTruthy(); } function callback2(data) { expect(data).toBeTruthy(); } await doAsync(callback1, callback2); });WARNING
При использовании
assertionsс асинхронными конкурентными тестами необходимо использоватьexpectиз локального Контекста теста, чтобы убедиться, что обнаружен правильный тест.
expect.hasAssertions
Тип:
() => voidПроверяет, было ли вызвано хотя бы одно утверждение после завершения теста (независимо от того, пройден он или нет). Это полезно для проверки того, был ли вызван асинхронный код.
Например, если у вас есть код, который вызывает обратный вызов, мы можем сделать утверждение внутри обратного вызова, но тест всегда будет проходить, если мы не проверим, было ли вызвано утверждение.
tsimport { expect, test } from 'vitest'; import { db } from './db.js'; const cbs = []; function onSelect(cb) { cbs.push(cb); } // после выбора из базы данных мы вызываем все обратные вызовы function select(id) { return db.select({ id }).then(data => { return Promise.all(cbs.map(cb => cb(data))); }); } test('callback was called', async () => { expect.hasAssertions(); onSelect(data => { // должен быть вызван при выборе expect(data).toBeTruthy(); }); // если не ожидать, тест завершится неудачей // если у вас нет expect.hasAssertions(), тест пройдет await select(3); });
expect.unreachable
Тип:
(message?: string) => neverЭтот метод используется для указания, что определенная строка кода никогда не должна быть достигнута. Если она будет достигнута, тест завершится с ошибкой.
Например, если мы хотим проверить, что
build()выдает исключение из-за отсутствия папкиsrcв указанных каталогах, и обрабатывать каждую ошибку отдельно, мы можем сделать это: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.each(errorDirs)('build fails with "%s"', async dir => { try { await build(dir); expect.unreachable('Should not pass build'); } catch (err: any) { expect(err).toBeInstanceOf(Error); expect(err.stack).toContain('build'); switch (dir) { case 'no-src-folder': expect(err.message).toBe(`${dir}/src does not exist`); break; default: // для обработки всех возможных ошибок expect.unreachable('All error test must be handled'); break; } } });
expect.anything
Тип:
() => anyЭтот асимметричный матчер всегда возвращает
trueпри использовании в проверке на равенство. Полезно, если вам просто нужно убедиться, что свойство существует.tsimport { expect, test } from 'vitest'; test('object has "apples" key', () => { expect({ apples: 22 }).toEqual({ apples: expect.anything() }); });
expect.any
Тип:
(constructor: unknown) => anyЭтот асимметричный матчер возвращает
trueпри использовании в проверке на равенство, только если значение является экземпляром указанного конструктора. Полезно, если у вас есть значение, которое генерируется каждый раз, и вы хотите проверить только его тип.tsimport { expect, test } from 'vitest'; import { generateId } from './generators.js'; test('"id" is a number', () => { expect({ id: generateId() }).toEqual({ id: expect.any(Number) }); });
expect.arrayContaining
Тип:
<T>(expected: T[]) => anyПри использовании в проверке на равенство, этот асимметричный матчер возвращает
true, если значение является массивом и содержит указанные элементы.tsimport { expect, test } from 'vitest'; test('basket includes fuji', () => { const basket = { varieties: ['Empire', 'Fuji', 'Gala'], count: 3, }; expect(basket).toEqual({ count: 3, varieties: expect.arrayContaining(['Fuji']), }); });TIP
Вы можете использовать
expect.notс этим матчером, чтобы инвертировать ожидаемое значение.
expect.objectContaining
Тип:
(expected: any) => anyПри использовании в проверке на равенство, этот асимметричный матчер возвращает
true, если значение имеет аналогичную структуру (содержит указанные свойства).tsimport { expect, test } from 'vitest'; test('basket has empire apples', () => { const basket = { varieties: [ { name: 'Empire', count: 1, }, ], }; expect(basket).toEqual({ varieties: [expect.objectContaining({ name: 'Empire' })], }); });TIP
Вы можете использовать
expect.notс этим матчером, чтобы инвертировать ожидаемое значение.
expect.stringContaining
Тип:
(expected: any) => anyПри использовании в проверке на равенство, этот асимметричный матчер возвращает
true, если значение является строкой и содержит указанную подстроку.tsimport { expect, test } from 'vitest'; test('variety has "Emp" in its name', () => { const variety = { name: 'Empire', count: 1, }; expect(variety).toEqual({ name: expect.stringContaining('Emp'), count: 1, }); });TIP
Вы можете использовать
expect.notс этим матчером, чтобы инвертировать ожидаемое значение.
expect.stringMatching
Тип:
(expected: any) => anyПри использовании в проверке на равенство, этот асимметричный матчер возвращает
true, если значение является строкой и содержит указанную подстроку или соответствует регулярному выражению.tsimport { expect, test } from 'vitest'; test('variety ends with "re"', () => { const variety = { name: 'Empire', count: 1, }; expect(variety).toEqual({ name: expect.stringMatching(/re$/), count: 1, }); });TIP
Вы можете использовать
expect.notс этим матчером, чтобы инвертировать ожидаемое значение.
expect.addSnapshotSerializer
Тип:
(plugin: PrettyFormatPlugin) => voidЭтот метод добавляет пользовательские сериализаторы, которые вызываются при создании снимка (snapshot). Это продвинутая функциональность. Для получения дополнительной информации ознакомьтесь с руководством по пользовательским сериализаторам.
Если вы добавляете пользовательские сериализаторы, вы должны вызвать этот метод внутри
setupFiles. Это повлияет на каждый снимок.TIP
Если вы ранее использовали Vue CLI с Jest, вы можете установить jest-serializer-vue. В противном случае ваши снимки будут обернуты в строку, что приведет к экранированию
".
expect.extend
Тип:
(matchers: MatchersObject) => voidВы можете расширить стандартные матчеры своими собственными. Эта функция используется для добавления пользовательских матчеров в объект матчеров.
При определении матчеров таким образом, вы также создаете асимметричные матчеры, которые можно использовать, например,
expect.stringContaining.tsimport { expect, test } from 'vitest'; test('custom matchers', () => { expect.extend({ toBeFoo: (received, expected) => { if (received !== 'foo') { return { message: () => `expected ${received} to be foo`, pass: false, }; } }, }); expect('foo').toBeFoo(); expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() }); });TIP
Если вы хотите, чтобы ваши матчеры были доступны в каждом тесте, вы должны вызвать этот метод внутри
setupFiles.Эта функция совместима с
expect.extendJest, поэтому любая библиотека, использующая ее для создания пользовательских матчеров, будет работать с Vitest.Если вы используете TypeScript, начиная с Vitest 0.31.0, вы можете расширить интерфейс
Assertionпо умолчанию в файле декларации окружения (например:vitest.d.ts) с помощью следующего кода:tsinterface CustomMatchers<R = unknown> { toBeFoo(): R; } declare module 'vitest' { interface Assertion<T = any> extends CustomMatchers<T> {} interface AsymmetricMatchersContaining extends CustomMatchers {} }WARNING
Не забудьте включить файл декларации окружения в ваш
tsconfig.json.TIP
Для получения дополнительной информации ознакомьтесь с руководством по расширению матчеров.