Skip to content
Vitest 1
Main Navigation РуководствоAPIКонфигурацияПродвинутый
1.6.1
0.34.6

Русский

English
简体中文
繁體中文
Español
Français
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

Русский

English
简体中文
繁體中文
Español
Français
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

Внешний вид

Sidebar Navigation

Руководство

Зачем Vitest

Начало работы

Функциональность

Рабочая область

Интерфейс командной строки

Фильтрация тестов

Репортёры

Покрытие кода

Снапшоты

Мокирование

Тестирование типов

Vitest UI

Режим браузера

In-source тестирование (Тестирование в исходном коде)

Контекст теста

Тестовая среда

Расширение проверок (matchers)

Интеграции с IDE

Отладка

Сравнения с другими тестовыми фреймворками

Руководство по миграции

Распространенные ошибки

Улучшение производительности

API

Справочник по Test API

Mock-функции

Vitest

expect

expectTypeOf

assert

assertType

Конфигурация

Настройка конфигурационного файла Vitest

Настройка Vitest

Содержание страницы

expect ​

В приведенных ниже сигнатурах типов используются следующие типы:

ts
type Awaitable<T> = T | PromiseLike<T>;

expect используется для создания утверждений. В данном контексте, утверждения — это функции, которые проверяют, выполняется ли определенное условие. Vitest по умолчанию предоставляет утверждения chai, а также утверждения, совместимые с Jest, основанные на chai.

Например, этот код утверждает, что значение input равно 2. Если это не так, утверждение вызовет ошибку, и тест завершится неудачей.

ts
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, но вместо того, чтобы завершать выполнение теста при неудачном утверждении, он продолжает выполняться и помечает неудачу как сбой теста. Все ошибки, возникшие во время теста, будут показаны после его завершения.

ts
import { expect, test } from 'vitest';

test('expect.soft test', () => {
  expect.soft(1 + 1).toBe(3); // помечает тест как провалившийся и продолжает выполнение
  expect.soft(1 + 2).toBe(4); // помечает тест как провалившийся и продолжает выполнение
});
// В конце теста будут выведены вышеуказанные ошибки.

Его также можно использовать вместе с expect. Если утверждение expect завершается неудачей, тест будет завершен, и все ошибки будут отображены.

ts
import { expect, test } from 'vitest';

test('expect.soft test', () => {
  expect.soft(1 + 1).toBe(3); // помечает тест как провалившийся и продолжает выполнение
  expect(1 + 2).toBe(4); // провалился и завершил тест, все предыдущие ошибки будут выведены
  expect.soft(1 + 3).toBe(5); // не выполняется
});

WARNING

expect.soft можно использовать только внутри функции test.

not ​

Использование not инвертирует утверждение. Например, этот код утверждает, что значение input не равно 2. Если оно равно, утверждение вызовет ошибку, и тест завершится неудачей.

ts
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 ​

  • Тип: (value: any) => Awaitable<void>

toBe можно использовать для утверждения, равны ли примитивы, или что объекты имеют одну и ту же ссылку. Это аналогично вызову expect(Object.is(3, 3)).toBe(true). Если объекты не совпадают, но вы хотите проверить, идентичны ли их структуры, используйте toEqual.

Например, код ниже проверяет, есть ли у трейдера 13 яблок.

ts
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; // same reference

  expect(stock).toBe(refStock);
});

Старайтесь не использовать toBe с числами с плавающей точкой. Поскольку JavaScript округляет их, 0.1 + 0.2 не является строго 0.3. Чтобы надежно утверждать числа с плавающей точкой, используйте утверждение toBeCloseTo.

toBeCloseTo ​

  • Тип: (value: number, numDigits?: number) => Awaitable<void>

Используйте toBeCloseTo для сравнения чисел с плавающей точкой. Необязательный аргумент numDigits указывает, сколько знаков после запятой следует учитывать при сравнении. Например:

ts
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 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. Полезно для проверки, возвращает ли функция какое-либо значение.

ts
import { expect, test } from 'vitest';

function getApples() {
  return 3;
}

test('function returned something', () => {
  expect(getApples()).toBeDefined();
});

toBeUndefined ​

  • Тип: () => Awaitable<void>

Обратное утверждение toBeDefined, toBeUndefined проверяет, что значение равно undefined. Полезно для проверки, не возвращает ли функция какое-либо значение.

ts
import { expect, test } from 'vitest';

function getApplesFromStock(stock: string) {
  if (stock === 'Bill') return 13;
}

test("mary doesn't have a stock", () => {
  expect(getApplesFromStock('Mary')).toBeUndefined();
});

toBeTruthy ​

  • Тип: () => Awaitable<void>

toBeTruthy проверяет, что значение истинно при преобразовании в boolean. Полезно, когда важен не сам результат, а возможность его приведения к true.

Например, имея этот код, вам не важно возвращаемое значение stocks.getInfo - это может быть сложный объект, строка или что-то еще. Код все равно будет работать.

ts
import { Stocks } from './stocks.js';

const stocks = new Stocks();
stocks.sync('Bill');
if (stocks.getInfo('Bill')) stocks.sell('apples', 'Bill');

Итак, если вы хотите проверить, что stocks.getInfo будет истинным, вы можете написать:

ts
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();
});

В JavaScript любое значение считается истинным, кроме false, null, undefined, NaN, 0, -0, 0n, "" и document.all.

toBeFalsy ​

  • Тип: () => Awaitable<void>

toBeFalsy проверяет, что значение ложно при преобразовании в boolean. Полезно, когда важен не сам результат, а возможность его приведения к false.

Например, имея этот код, вам не важно возвращаемое значение stocks.stockFailed - он может вернуть любое ложное значение, но код все равно будет работать.

ts
import { Stocks } from './stocks.js';

const stocks = new Stocks();
stocks.sync('Bill');
if (!stocks.stockFailed('Bill')) stocks.sell('apples', 'Bill');

Итак, если вы хотите проверить, что stocks.stockFailed будет ложным, вы можете написать:

ts
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();
});

В JavaScript любое значение считается истинным, кроме false, null, undefined, NaN, 0, -0, 0n, "" и document.all.

toBeNull ​

  • Тип: () => Awaitable<void>

toBeNull просто проверяет, является ли что-то null. Это псевдоним для .toBe(null).

ts
import { expect, test } from 'vitest';

function apples() {
  return null;
}

test("we don't have apples", () => {
  expect(apples()).toBeNull();
});

toBeNaN ​

  • Тип: () => Awaitable<void>

toBeNaN просто проверяет, является ли что-то NaN. Это псевдоним для .toBe(NaN).

ts
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 ​

  • Тип: (c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>

toBeTypeOf проверяет, имеет ли фактическое значение тип, соответствующий полученному типу.

ts
import { expect, test } from 'vitest';

const actual = 'stock';

test('stock is type of string', () => {
  expect(actual).toBeTypeOf('string');
});

toBeInstanceOf ​

  • Тип: (c: any) => Awaitable<void>

toBeInstanceOf проверяет, является ли фактическое значение экземпляром полученного класса.

ts
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 ​

  • Тип: (n: number | bigint) => Awaitable<void>

toBeGreaterThan проверяет, что фактическое значение больше полученного. Равные значения приведут к сбою теста.

ts
import { 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 проверяет, что фактическое значение больше полученного или равно ему.

ts
import { 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 проверяет, что фактическое значение меньше полученного. Равные значения приведут к сбою теста.

ts
import { 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 проверяет, что фактическое значение меньше полученного или равно ему.

ts
import { 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 показана в следующем примере:

ts
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

Глубокое сравнение на равенство не будет выполняться для объектов Error. Для определения равенства учитывается только свойство message объекта Error. Чтобы настроить проверку на равенство для свойств, отличных от message, используйте expect.addEqualityTesters. Чтобы проверить, было ли что-то выброшено, используйте утверждение toThrowError.

toStrictEqual ​

  • Тип: (received: any) => Awaitable<void>

toStrictEqual проверяет, что фактическое значение равно полученному или имеет ту же структуру, если это объект (сравнивает их рекурсивно), и того же типа.

Отличия от .toEqual:

  • Проверяются ключи со свойствами undefined. Например, {a: undefined, b: 2} не соответствует {b: 2} при использовании .toStrictEqual.
  • Проверяется наличие пропусков в массиве. Например, [, 1] не соответствует [undefined, 1] при использовании .toStrictEqual.
  • Проверяется идентичность типов объектов. Например, экземпляр класса с полями a и b не будет эквивалентен литеральному объекту с полями a и b.
ts
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 ​

  • Тип: (received: string) => Awaitable<void>

toContain утверждает, что фактическое значение находится в массиве. toContain также может проверить, является ли одна строка подстрокой другой строки. Начиная с Vitest 1.0, если вы запускаете тесты в браузерной среде, это утверждение также может проверить, содержится ли класс в classList или элемент находится внутри другого элемента.

ts
import { expect, test } from 'vitest';
import { getAllFruits } from './stocks.js';

test('the fruit list contains orange', () => {
  expect(getAllFruits()).toContain('orange');

  const element = document.querySelector('#el');
  // element has a class
  expect(element.classList).toContain('flex');
  // element is inside another one
  expect(document.querySelector('#wrapper')).toContain(element);
});

toContainEqual ​

  • Тип: (received: any) => Awaitable<void>

toContainEqual проверяет, что элемент с определенной структурой и значениями содержится в массиве. Он работает как toEqual внутри для каждого элемента.

ts
import { 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 с определенным числовым значением.

ts
import { 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).

ts
import { expect, test } from 'vitest';

const invoice = {
  isActive: true,
  'P.O': '12345',
  customer: {
    first_name: 'John',
    last_name: 'Doe',
    location: 'China',
  },
  total_amount: 5000,
  items: [
    {
      type: 'apples',
      quantity: 10,
    },
    {
      type: 'oranges',
      quantity: 5,
    },
  ],
};

test('John Doe Invoice', () => {
  expect(invoice).toHaveProperty('isActive'); // Проверяет, что ключ существует
  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 проверяет, соответствует ли строка регулярному выражению или другой строке.

ts
import { expect, test } from 'vitest';

test('top fruits', () => {
  expect('top fruits include apple, orange and grape').toMatch(/apple/);
  expect('applefruits').toMatch('fruit'); // toMatch также принимает строку
});

toMatchObject ​

  • Type: (received: object | array) => Awaitable<void>

toMatchObject проверяет, содержит ли объект подмножество свойств другого объекта.

Вы также можете передать массив объектов. Это полезно, если вы хотите проверить, что два массива содержат одинаковое количество элементов и соответствующие элементы совпадают, в отличие от arrayContaining, который допускает наличие дополнительных элементов в проверяемом массиве.

ts
import { expect, test } from 'vitest';

const johnInvoice = {
  isActive: true,
  customer: {
    first_name: 'John',
    last_name: 'Doe',
    location: 'China',
  },
  total_amount: 5000,
  items: [
    {
      type: 'apples',
      quantity: 10,
    },
    {
      type: 'oranges',
      quantity: 5,
    },
  ],
};

const johnDetails = {
  customer: {
    first_name: 'John',
    last_name: 'Doe',
    location: 'China',
  },
};

test('invoice has john personal details', () => {
  expect(johnInvoice).toMatchObject(johnDetails);
});

test('the number of elements must match exactly', () => {
  // Проверяет, что массивы объектов совпадают
  expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([
    { foo: 'bar' },
    { baz: 1 },
  ]);
});

toThrowError ​

  • Type: (received: any) => Awaitable<void>

  • Alias: toThrow

toThrowError проверяет, выбрасывает ли функция ошибку при вызове.

Вы можете передать необязательный аргумент для проверки типа выбрасываемой ошибки:

  • regular expression: сообщение об ошибке соответствует регулярному выражению
  • string: сообщение об ошибке содержит указанную подстроку

TIP

Обязательно оберните код в функцию, иначе ошибка не будет перехвачена, и тест завершится неудачей.

Например, чтобы проверить, что getFruitStock('pineapples') выбрасывает ошибку, можно написать:

ts
import { expect, test } from 'vitest';

function getFruitStock(type: string) {
  if (type === 'pineapples') throw new Error('Pineapples are not in stock');

  // Выполнение других действий
}

test('throws on pineapples', () => {
  // Проверяет, что сообщение об ошибке содержит "stock": эти записи эквивалентны
  expect(() => getFruitStock('pineapples')).toThrowError(/stock/);
  expect(() => getFruitStock('pineapples')).toThrowError('stock');

  // Проверяет точное сообщение об ошибке
  expect(() => getFruitStock('pineapples')).toThrowError(
    /^Pineapples are not in stock$/
  );
});

TIP

Для тестирования асинхронных функций используйте в сочетании с rejects.

js
function 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 всегда обновлял снимки.

ts
import { expect, test } from 'vitest';

test('matches snapshot', () => {
  const data = { foo: new Set(['bar', 'snapshot']) };
  expect(data).toMatchSnapshot();
});

Вы также можете предоставить структуру объекта (shape of an object), если вы тестируете только структуру объекта и не требуете 100% соответствия данным:

ts
import { 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).

ts
import { expect, test } from 'vitest';

test('matches inline snapshot', () => {
  const data = { foo: new Set(['bar', 'snapshot']) };
  // Vitest обновит следующее содержимое при обновлении моментального снимка
  expect(data).toMatchInlineSnapshot(`
    {
      "foo": Set {
        "bar",
        "snapshot",
      },
    }
  `);
});

Вы также можете предоставить структуру объекта, если вы тестируете только структуру объекта и не требуете 100% соответствия данным:

ts
import { expect, test } from 'vitest';

test('matches snapshot', () => {
  const data = { foo: new Set(['bar', 'snapshot']) };
  expect(data).toMatchInlineSnapshot(
    { foo: expect.any(Set) },
    `
    {
      "foo": Any<Set>,
    }
  `
  );
});

toMatchFileSnapshot 0.30.0+ ​

  • Type: <T>(filepath: string, message?: string) => Promise<void>

Сравнивает или обновляет снимок с содержимым файла, указанного явно (вместо файла .snap).

ts
import { 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).

toThrowErrorMatchingInlineSnapshot ​

  • Type: (snapshot?: string, message?: string) => void

Аналогичен toMatchInlineSnapshot, но применяется к значению, которое, как ожидается, будет выброшено функцией (как в toThrowError).

toHaveBeenCalled ​

  • Type: () => Awaitable<void>

Проверяет, была ли вызвана функция. Требует, чтобы в expect была передана шпионская функция (spy function).

ts
import { expect, test, vi } from 'vitest';

const market = {
  buy(subject: string, amount: number) {
    // ...
  },
};

test('spy function', () => {
  const buySpy = vi.spyOn(market, 'buy');

  expect(buySpy).not.toHaveBeenCalled();

  market.buy('apples', 10);

  expect(buySpy).toHaveBeenCalled();
});

toHaveBeenCalledTimes ​

  • Type: (amount: number) => Awaitable<void>

Проверяет, что функция была вызвана указанное количество раз. Требует, чтобы в expect была передана шпионская функция.

ts
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 была передана шпионская функция.

ts
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 была передана шпионская функция.

ts
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 была передана шпионская функция.

ts
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 была передана шпионская функция.

ts
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 была передана шпионская функция.

ts
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.

ts
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.

ts
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.

ts
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).

ts
import { describe, expect, it } from 'vitest';
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 и возвращает данные, вы можете использовать следующий код для проверки возвращаемого значения:

ts
import { 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.

Например, если у вас есть функция, которая завершается с ошибкой при вызове, вы можете использовать следующий код для проверки причины ошибки:

ts
import { expect, test } from 'vitest';

async function buyApples(id) {
  if (!id) throw new Error('no id');
}

test('buyApples throws an error when no id provided', async () => {
  // toThrow теперь возвращает промис, поэтому вы ДОЛЖНЫ дождаться его
  await expect(buyApples()).rejects.toThrow('no id');
});

WARNING

Если не дождаться выполнения утверждения, тест может дать ложноположительный результат. Чтобы убедиться, что утверждения действительно вызываются, используйте expect.assertions(number).

expect.assertions ​

  • Тип: (count: number) => void

Проверяет, было ли вызвано указанное количество утверждений после завершения теста (независимо от того, пройден он или нет). Это полезно для проверки того, был ли вызван асинхронный код.

Например, если у нас есть функция, которая асинхронно вызывает два матчера, мы можем убедиться, что они действительно были вызваны.

ts
import { expect, test } from 'vitest';

async function doAsync(...cbs) {
  await Promise.all(cbs.map((cb, index) => cb({ index })));
}

test('all assertions are called', async () => {
  expect.assertions(2);
  function callback1(data) {
    expect(data).toBeTruthy();
  }
  function callback2(data) {
    expect(data).toBeTruthy();
  }

  await doAsync(callback1, callback2);
});

WARNING

При использовании assertions с асинхронными конкурентными тестами необходимо использовать expect из локального Контекста теста, чтобы убедиться, что обнаружен правильный тест.

expect.hasAssertions ​

  • Тип: () => void

Проверяет, было ли вызвано хотя бы одно утверждение после завершения теста (независимо от того, пройден он или нет). Это полезно для проверки того, был ли вызван асинхронный код.

Например, если у вас есть код, который вызывает обратный вызов, мы можем сделать утверждение внутри обратного вызова, но тест всегда будет проходить, если мы не проверим, было ли вызвано утверждение.

ts
import { 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 в указанных каталогах, и обрабатывать каждую ошибку отдельно, мы можем сделать это:

ts
import { expect, test } from 'vitest';

async function build(dir) {
  if (dir.includes('no-src')) throw new Error(`${dir}/src does not exist`);
}

const errorDirs = [
  'no-src-folder',
  // ...
];

test.each(errorDirs)('build fails with "%s"', async dir => {
  try {
    await build(dir);
    expect.unreachable('Should not pass build');
  } 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 при использовании в проверке на равенство. Полезно, если вам просто нужно убедиться, что свойство существует.

ts
import { expect, test } from 'vitest';

test('object has "apples" key', () => {
  expect({ apples: 22 }).toEqual({ apples: expect.anything() });
});

expect.any ​

  • Тип: (constructor: unknown) => any

Этот асимметричный матчер возвращает true при использовании в проверке на равенство, только если значение является экземпляром указанного конструктора. Полезно, если у вас есть значение, которое генерируется каждый раз, и вы хотите проверить только его тип.

ts
import { expect, test } from 'vitest';
import { generateId } from './generators.js';

test('"id" is a number', () => {
  expect({ id: generateId() }).toEqual({ id: expect.any(Number) });
});

expect.closeTo 1.0.0+ ​

  • Тип: (expected: any, precision?: number) => any

expect.closeTo полезен при сравнении чисел с плавающей точкой в свойствах объекта или элементах массива. Если вам нужно сравнить число, используйте .toBeCloseTo вместо этого.

Необязательный аргумент numDigits ограничивает количество цифр для проверки после десятичной точки. Для значения по умолчанию 2 критерий проверки равен Math.abs(expected - received) < 0.005 (то есть 10 ** -2 / 2).

Например, этот тест проходит с точностью до 5 знаков:

js
test('compare float in object properties', () => {
  expect({
    title: '0.1 + 0.2',
    sum: 0.1 + 0.2,
  }).toEqual({
    title: '0.1 + 0.2',
    sum: expect.closeTo(0.3, 5),
  });
});

expect.arrayContaining ​

  • Тип: <T>(expected: T[]) => any

При использовании в проверке на равенство, этот асимметричный матчер возвращает true, если значение является массивом и содержит указанные элементы.

ts
import { expect, test } from 'vitest';

test('basket includes fuji', () => {
  const basket = {
    varieties: ['Empire', 'Fuji', 'Gala'],
    count: 3,
  };
  expect(basket).toEqual({
    count: 3,
    varieties: expect.arrayContaining(['Fuji']),
  });
});

TIP

Вы можете использовать expect.not с этим матчером, чтобы инвертировать ожидаемое значение.

expect.objectContaining ​

  • Тип: (expected: any) => any

При использовании в проверке на равенство, этот асимметричный матчер возвращает true, если значение имеет аналогичную структуру (содержит указанные свойства).

ts
import { expect, test } from 'vitest';

test('basket has empire apples', () => {
  const basket = {
    varieties: [
      {
        name: 'Empire',
        count: 1,
      },
    ],
  };
  expect(basket).toEqual({
    varieties: [expect.objectContaining({ name: 'Empire' })],
  });
});

TIP

Вы можете использовать expect.not с этим матчером, чтобы инвертировать ожидаемое значение.

expect.stringContaining ​

  • Тип: (expected: any) => any

При использовании в проверке на равенство, этот асимметричный матчер возвращает true, если значение является строкой и содержит указанную подстроку.

ts
import { expect, test } from 'vitest';

test('variety has "Emp" in its name', () => {
  const variety = {
    name: 'Empire',
    count: 1,
  };
  expect(variety).toEqual({
    name: expect.stringContaining('Emp'),
    count: 1,
  });
});

TIP

Вы можете использовать expect.not с этим матчером, чтобы инвертировать ожидаемое значение.

expect.stringMatching ​

  • Тип: (expected: any) => any

При использовании в проверке на равенство, этот асимметричный матчер возвращает true, если значение является строкой и содержит указанную подстроку или соответствует регулярному выражению.

ts
import { expect, test } from 'vitest';

test('variety ends with "re"', () => {
  const variety = {
    name: 'Empire',
    count: 1,
  };
  expect(variety).toEqual({
    name: expect.stringMatching(/re$/),
    count: 1,
  });
});

TIP

Вы можете использовать expect.not с этим матчером, чтобы инвертировать ожидаемое значение.

expect.addSnapshotSerializer ​

  • Тип: (plugin: PrettyFormatPlugin) => void

Этот метод добавляет пользовательские сериализаторы, которые вызываются при создании снимка (snapshot). Это продвинутая функциональность. Для получения дополнительной информации ознакомьтесь с руководством по пользовательским сериализаторам.

Если вы добавляете пользовательские сериализаторы, вы должны вызвать этот метод внутри setupFiles. Это повлияет на каждый снимок.

TIP

Если вы ранее использовали Vue CLI с Jest, вы можете установить jest-serializer-vue. В противном случае ваши снимки будут обернуты в строку, что приведет к экранированию " .

expect.extend ​

  • Тип: (matchers: MatchersObject) => void

Вы можете расширить стандартные матчеры своими собственными. Эта функция используется для добавления пользовательских матчеров в объект матчеров.

При определении матчеров таким образом, вы также создаете асимметричные матчеры, которые можно использовать, например, expect.stringContaining.

ts
import { expect, test } from 'vitest';

test('custom matchers', () => {
  expect.extend({
    toBeFoo: (received, expected) => {
      if (received !== 'foo') {
        return {
          message: () => `expected ${received} to be foo`,
          pass: false,
        };
      }
    },
  });

  expect('foo').toBeFoo();
  expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() });
});

TIP

Если вы хотите, чтобы ваши матчеры были доступны в каждом тесте, вы должны вызвать этот метод внутри setupFiles.

Эта функция совместима с expect.extend Jest, поэтому любая библиотека, использующая ее для создания пользовательских матчеров, будет работать с Vitest.

Если вы используете TypeScript, начиная с Vitest 0.31.0, вы можете расширить интерфейс Assertion по умолчанию в файле декларации окружения (например: vitest.d.ts) с помощью следующего кода:

ts
interface CustomMatchers<R = unknown> {
  toBeFoo: () => R;
}

declare module 'vitest' {
  interface Assertion<T = any> extends CustomMatchers<T> {}
  interface AsymmetricMatchersContaining extends CustomMatchers {}
}

WARNING

Не забудьте включить файл декларации окружения в ваш tsconfig.json.

TIP

Для получения дополнительной информации ознакомьтесь с руководством по расширению матчеров.

expect.addEqualityTesters 1.2.0+ ​

  • Тип: (tester: Array<Tester>) => void

Вы можете использовать этот метод для определения пользовательских тестеров, которые являются методами, используемыми сопоставителями для проверки равенства двух объектов. Он совместим с expect.addEqualityTesters в Jest.

ts
import { expect, test } from 'vitest';

class AnagramComparator {
  public word: string;

  constructor(word: string) {
    this.word = word;
  }

  equals(other: AnagramComparator): boolean {
    const cleanStr1 = this.word.replace(/ /g, '').toLowerCase();
    const cleanStr2 = other.word.replace(/ /g, '').toLowerCase();

    const sortedStr1 = cleanStr1.split('').sort().join('');
    const sortedStr2 = cleanStr2.split('').sort().join('');

    return sortedStr1 === sortedStr2;
  }
}

function isAnagramComparator(a: unknown): a is AnagramComparator {
  return a instanceof AnagramComparator;
}

function areAnagramsEqual(a: unknown, b: unknown): boolean | undefined {
  const isAAnagramComparator = isAnagramComparator(a);
  const isBAnagramComparator = isBAnagramComparator(b);

  if (isAAnagramComparator && isBAnagramComparator) return a.equals(b);
  else if (isAAnagramComparator === isBAnagramComparator) return undefined;
  else return false;
}

expect.addEqualityTesters([areAnagramsEqual]);

test('custom equality tester', () => {
  expect(new AnagramComparator('listen')).toEqual(
    new AnagramComparator('silent')
  );
});
Pager
Предыдущая страницаVitest
Следующая страницаexpectTypeOf

Выпущено на условиях лицензии MIT.

Авторские права (c) 2024 Mithril Contributors

https://v1.vitest.dev/api/expect

Выпущено на условиях лицензии MIT.

Авторские права (c) 2024 Mithril Contributors