Skip to content
Vitest 3
Main Navigation Руководство & APIКонфигурацияРежим браузераРасширенный API
3.2.0
2.1.9
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

API

Справочник по API тестирования

Мок-функции

Vi

expect

expectTypeOf

assert

assertType

Руководство

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

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

Тестовые проекты

Средства отчётности

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

Снапшот-тестирование

Мокирование

Параллелизм

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

Vitest UI

Тестирование в исходном коде

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

Аннотации тестов

Среда тестирования

Расширение матчеров

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

Отладка

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

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

Миграция на Vitest 3.0

Миграция с Jest

Производительность

Профилирование производительности тестов

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

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

Расширенный API

Сравнение с другими тестовыми раннерами

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

Vi ​

Vitest предоставляет вспомогательные функции через свой помощник vi. Вы можете получить к нему доступ глобально (если включена глобальная конфигурация) или импортировать его непосредственно из vitest:

js
import { vi } from 'vitest';

Мокирование Модулей ​

В этом разделе описаны API, которые вы можете использовать при мокировании модуля. Обратите внимание, что Vitest не поддерживает мокирование модулей, импортированных с помощью require().

vi.mock ​

  • Тип: (path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
  • Тип: <T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void

Заменяет все импортированные модули из указанного path на другой модуль. Вы можете использовать настроенные Vite-алиасы внутри пути. Вызов vi.mock поднимается (hoisting), поэтому неважно, где вы его вызываете. Он всегда будет выполнен перед всеми импортами. Если вам нужно сослаться на какие-либо переменные вне его области видимости, вы можете определить их внутри vi.hoisted и сослаться на них внутри vi.mock.

WARNING

vi.mock работает только для модулей, которые были импортированы с помощью ключевого слова import. Он не работает с require.

Для поднятия vi.mock Vitest статически анализирует ваши файлы. Это означает, что vi, не импортированный напрямую из пакета vitest (например, из вспомогательного файла), не может быть использован. Используйте vi.mock с vi, импортированным из vitest, или включите опцию конфигурации globals.

Vitest не будет мокировать модули, импортированные внутри файла настройки, поскольку они кэшируются к моменту запуска тестового файла. Вы можете вызвать vi.resetModules() внутри vi.hoisted, чтобы очистить все кэши модулей перед запуском тестового файла.

Если функция factory определена, все импорты будут возвращать её результат. Vitest вызывает фабрику только один раз и кэширует результаты для всех последующих импортов, пока не будет вызван vi.unmock или vi.doUnmock.

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

Вы также можете предоставить объект со свойством spy вместо функции-фабрики. Если spy равно true, то Vitest будет автоматически мокировать модуль как обычно, но не будет переопределять реализацию экспортов. Это полезно, если вы просто хотите проверить, что экспортированный метод был вызван правильно другим методом.

ts
import { calculator } from './src/calculator.ts';

vi.mock('./src/calculator.ts', { spy: true });

// вызывает оригинальную реализацию,
// но позволяет проверить поведение позже
const result = calculator(1, 2);

expect(result).toBe(3);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);

Vitest также поддерживает промис модуля вместо строки в методах vi.mock и vi.doMock для лучшей поддержки IDE. При перемещении файла путь будет обновлен, а importOriginal автоматически наследует тип. Использование этой сигнатуры также обеспечит совместимость типа возвращаемого значения фабрики с исходным модулем (сохраняя экспорты необязательными).

ts
// @filename: ./path/to/module.js
export declare function total(...numbers: number[]): number;
// @filename: test.js
import { vi } from 'vitest';
// ---cut---
vi.mock(import('./path/to/module.js'), async importOriginal => {
  const mod = await importOriginal(); // тип выводится
  //    ^?
  return {
    ...mod,
    // заменить некоторые экспорты
    total: vi.fn(),
  };
});

На низком уровне Vitest по-прежнему оперирует строкой, а не объектом модуля.

Однако, если вы используете TypeScript с алиасами paths, настроенными в tsconfig.json, компилятор не сможет корректно разрешить типы импорта. Чтобы это работало, убедитесь, что вы заменили все алиасированные импорты на соответствующие относительные пути. Например, используйте import('./path/to/module.js') вместо import('@/module').

WARNING

vi.mock поднимается (то есть перемещается) в начало файла. Это означает, что независимо от того, где вы его напишете (внутри beforeEach или test), он фактически будет вызван раньше, чем этот код.

Это также означает, что вы не можете использовать переменные внутри фабрики, если они определены вне её.

Если вам нужно использовать переменные внутри фабрики, попробуйте vi.doMock. Он работает так же, но не поднимается. Имейте в виду, что он мокирует только последующие динамические импорты.

Вы также можете ссылаться на переменные, определенные методом vi.hoisted, если он был объявлен до vi.mock:

ts
import { namedExport } from './path/to/module.js';

const mocks = vi.hoisted(() => {
  return {
    namedExport: vi.fn(),
  };
});

vi.mock('./path/to/module.js', () => {
  return {
    namedExport: mocks.namedExport,
  };
});

vi.mocked(namedExport).mockReturnValue(100);

expect(namedExport()).toBe(100);
expect(namedExport).toBe(mocks.namedExport);

WARNING

Если вы мокируете модуль с экспортом по умолчанию, вам потребуется предоставить ключ default внутри объекта функции-фабрики. Это особенность модулей ES; поэтому документация jest может отличаться, поскольку jest использует модули CommonJS. Например,

ts
vi.mock('./path/to/module.js', () => {
  return {
    default: { myDefaultKey: vi.fn() },
    namedExport: vi.fn(),
    // и т.д.
  };
});

Если рядом с мокируемым файлом есть папка __mocks__, и фабрика не предоставлена, Vitest попытается найти файл с тем же именем в подпапке __mocks__ и использовать его в качестве фактического модуля. Если вы мокируете зависимость, Vitest попытается найти папку __mocks__ в корне проекта (по умолчанию process.cwd()). Вы можете указать Vitest, где находятся зависимости, с помощью опции конфигурации deps.moduleDirectories.

Например, у вас такая структура файлов:

- __mocks__
  - axios.js
- src
  __mocks__
    - increment.js
  - increment.js
- tests
  - increment.test.js

Если вы вызываете vi.mock в тестовом файле без предоставления фабрики или опций, он найдет файл в папке __mocks__ для использования в качестве модуля:

ts
import { vi } from 'vitest';

// axios - это экспорт по умолчанию из `__mocks__/axios.js`
import axios from 'axios';

// increment - это именованный экспорт из `src/__mocks__/increment.js`
import { increment } from '../increment.js';

vi.mock('axios');
vi.mock('../increment.js');

axios.get(`/apples/${increment(1)}`);

WARNING

Обратите внимание, что если вы не вызываете vi.mock, модули не будут мокироваться автоматически. Чтобы воспроизвести поведение Jest по автоматическому мокированию, вы можете вызвать vi.mock для каждого требуемого модуля внутри setupFiles.

Если папка __mocks__ отсутствует или фабрика не предоставлена, Vitest импортирует исходный модуль и автоматически мокирует все его экспорты. Правила, применяемые в этом случае, см. в алгоритме.

vi.doMock ​

  • Тип: (path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
  • Тип: <T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void

То же, что и vi.mock, но не поднимается в начало файла, поэтому вы можете ссылаться на переменные в глобальной области видимости файла. Следующий динамический импорт этого модуля будет замокирован.

WARNING

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

ts
vi.doMock('./increment.js'); // это будет вызвано _после_ оператора import

import { increment } from './increment.js';
ts
export function increment(number) {
  return number + 1;
}
ts
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';

// модуль не замокирован, поскольку `vi.doMock` еще не был вызван
increment(1) === 2;

let mockedIncrement = 100;

beforeEach(() => {
  // вы можете получить доступ к переменным внутри фабрики
  vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});

test('импорт следующего модуля импортирует замокированный', async () => {
  // оригинальный импорт НЕ БЫЛ ЗАМОКИРОВАН, поскольку `vi.doMock` вычисляется ПОСЛЕ импортов
  expect(increment(1)).toBe(2);
  const { increment: mockedIncrement } = await import('./increment.js');
  // новый динамический импорт возвращает замокированный модуль
  expect(mockedIncrement(1)).toBe(101);
  expect(mockedIncrement(1)).toBe(102);
  expect(mockedIncrement(1)).toBe(103);
});

vi.mocked ​

  • Тип: <T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>
  • Тип: <T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>

Вспомогательная функция для TypeScript. Просто возвращает переданный объект.

Когда partial равно true, он будет ожидать Partial<T> в качестве возвращаемого значения. По умолчанию это заставит TypeScript считать, что замокированы только значения первого уровня объекта. Вы можете передать { deep: true } в качестве второго аргумента, чтобы сообщить TypeScript, что весь объект замокирован, если это действительно так.

ts
export function add(x: number, y: number): number {
  return x + y;
}

export function fetchSomething(): Promise<Response> {
  return fetch('https://vitest.dev/');
}
ts
import * as example from './example';

vi.mock('./example');

test('1 + 1 равно 10', async () => {
  vi.mocked(example.add).mockReturnValue(10);
  expect(example.add(1, 1)).toBe(10);
});

test('мокирование возвращаемого значения с частично правильной типизацией', async () => {
  vi.mocked(example.fetchSomething).mockResolvedValue(new Response('hello'));
  vi.mocked(example.fetchSomething, { partial: true }).mockResolvedValue({
    ok: false,
  });
  // vi.mocked(example.someFn).mockResolvedValue({ ok: false }) // это ошибка типа
});

vi.importActual ​

  • Тип: <T>(path: string) => Promise<T>

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

ts
vi.mock('./example.js', async () => {
  const originalModule = await vi.importActual('./example.js');

  return { ...originalModule, get: vi.fn() };
});

vi.importMock ​

  • Тип: <T>(path: string) => Promise<MaybeMockedDeep<T>>

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

vi.unmock ​

  • Тип: (path: string | Promise<Module>) => void

Удаляет модуль из реестра моков. Все вызовы импорта будут возвращать исходный модуль, даже если он был замокирован ранее. Этот вызов поднимается в начало файла, поэтому он будет размокировать только модули, которые были определены, например, в setupFiles (и уже замокированы).

vi.doUnmock ​

  • Тип: (path: string | Promise<Module>) => void

То же, что и vi.unmock, но не поднимается в начало файла. Следующий импорт модуля будет импортировать исходный модуль вместо мока. Это не размокирует ранее импортированные модули.

ts
export function increment(number) {
  return number + 1;
}
ts
import { increment } from './increment.js';

// increment уже замокирован, потому что vi.mock поднят
increment(1) === 100;

// это поднято, и фабрика вызывается до импорта на строке 1
vi.mock('./increment.js', () => ({ increment: () => 100 }));

// все вызовы замокированы, и `increment` всегда возвращает 100
increment(1) === 100;
increment(30) === 100;

// это не поднято, поэтому другой импорт вернет размокированный модуль
vi.doUnmock('./increment.js');

// это ВСЕ ЕЩЕ возвращает 100, поскольку `vi.doUnmock` не переоценивает модуль
increment(1) === 100;
increment(30) === 100;

// следующий импорт размокирован, теперь `increment` - это оригинальная функция, которая возвращает count + 1
const { increment: unmockedIncrement } = await import('./increment.js');

unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;

vi.resetModules ​

  • Тип: () => Vitest

Сбрасывает реестр модулей, очищая кэш всех модулей. Это позволяет переоценивать модули при повторном импорте. Импорты верхнего уровня (top-level imports) не могут быть переоценены. Может быть полезно для изоляции модулей, где локальное состояние конфликтует между тестами.

ts
import { vi } from 'vitest';

import { data } from './data.js'; // Не будет переоцениваться перед каждым тестом

beforeEach(() => {
  vi.resetModules();
});

test('изменить состояние', async () => {
  const mod = await import('./some/path.js'); // Будет переоцениваться
  mod.changeLocalState('новое значение');
  expect(mod.getLocalState()).toBe('новое значение');
});

test('модуль имеет старое состояние', async () => {
  const mod = await import('./some/path.js'); // Будет переоцениваться
  expect(mod.getLocalState()).toBe('старое значение');
});

WARNING

Не сбрасывает реестр моков. Чтобы очистить реестр моков, используйте vi.unmock или vi.doUnmock.

vi.dynamicImportSettled ​

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

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

// не может отслеживать импорт, потому что Promise не возвращается
function renderComponent() {
  import('./component.js').then(({ render }) => {
    render();
  });
}

test('операции разрешены', async () => {
  renderComponent();
  await vi.dynamicImportSettled();
  expect(document.querySelector('.component')).not.toBeNull();
});

TIP

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

Этот метод также будет ждать следующего тика setTimeout после разрешения импорта, чтобы все синхронные операции были завершены к моменту его завершения.

Мокирование функций и объектов ​

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

vi.fn ​

  • Тип: (fn?: Function) => Mock

Создает шпиона на функции, хотя может быть инициализирован и без нее. Каждый раз, когда функция вызывается, она сохраняет свои аргументы вызова, возвращаемые значения и экземпляры. Также вы можете управлять её поведением с помощью методов. Если функция не задана, мок вернет undefined при вызове.

ts
const getApples = vi.fn(() => 0);

getApples();

expect(getApples).toHaveBeenCalled();
expect(getApples).toHaveReturnedWith(0);

getApples.mockReturnValueOnce(5);

const res = getApples();
expect(res).toBe(5);
expect(getApples).toHaveNthReturnedWith(2, 5);

vi.mockObject 3.2.0+ ​

  • Тип: <T>(value: T) => MaybeMockedDeep<T>

Глубоко мокирует свойства и методы данного объекта так же, как vi.mock() мокирует экспорты модуля. Подробности см. в разделе автомокирование.

ts
const original = {
  simple: () => 'value',
  nested: {
    method: () => 'real',
  },
  prop: 'foo',
};

const mocked = vi.mockObject(original);
expect(mocked.simple()).toBe(undefined);
expect(mocked.nested.method()).toBe(undefined);
expect(mocked.prop).toBe('foo');

mocked.simple.mockReturnValue('mocked');
mocked.nested.method.mockReturnValue('mocked nested');

expect(mocked.simple()).toBe('mocked');
expect(mocked.nested.method()).toBe('mocked nested');

vi.isMockFunction ​

  • Тип: (fn: Function) => boolean

Проверяет, является ли данный параметр мок-функцией. Если вы используете TypeScript, он также сузит её тип.

vi.clearAllMocks ​

Вызывает .mockClear() для всех шпионов. Это очистит историю моков, не затрагивая их реализации.

vi.resetAllMocks ​

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

vi.restoreAllMocks ​

Вызывает .mockRestore() для всех шпионов. Это очистит историю моков, восстановит все исходные реализации моков и восстановит исходные дескрипторы шпионируемых объектов.

vi.spyOn ​

  • Тип: <T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance

Создает шпиона на методе или геттере/сеттере объекта, аналогично vi.fn(). Он возвращает мок-функцию.

ts
let apples = 0;
const cart = {
  getApples: () => 42,
};

const spy = vi.spyOn(cart, 'getApples').mockImplementation(() => apples);
apples = 1;

expect(cart.getApples()).toBe(1);

expect(spy).toHaveBeenCalled();
expect(spy).toHaveReturnedWith(1);

TIP

В средах, поддерживающих Explicit Resource Management, вы можете использовать using вместо const для автоматического вызова mockRestore на любой замокированной функции при выходе из содержащего блока. Это особенно полезно для шпионируемых методов:

ts
it('вызывает console.log', () => {
  using spy = vi.spyOn(console, 'log').mockImplementation(() => {})
  debug('message')
  expect(spy).toHaveBeenCalled()
})
// console.log восстанавливается здесь

TIP

Вы можете вызвать vi.restoreAllMocks внутри afterEach (или включить test.restoreMocks), чтобы восстановить все методы до их исходных реализаций. Это восстановит исходный дескриптор объекта, поэтому вы не сможете изменить реализацию метода:

ts
const cart = {
  getApples: () => 42,
};

const spy = vi.spyOn(cart, 'getApples').mockReturnValue(10);

console.log(cart.getApples()); // 10
vi.restoreAllMocks();
console.log(cart.getApples()); // 42
spy.mockReturnValue(10);
console.log(cart.getApples()); // все еще 42!

TIP

Шпионить за экспортированными методами в режиме браузера невозможно. Вместо этого вы можете шпионить за каждым экспортированным методом, вызвав vi.mock("./file-path.js", { spy: true }). Это замокирует каждый экспорт, но сохранит его реализацию нетронутой, позволяя вам убедиться, что метод был вызван правильно.

ts
import { calculator } from './src/calculator.ts';

vi.mock('./src/calculator.ts', { spy: true });

calculator(1, 2);

expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);

И хотя возможно шпионить за экспортами в jsdom или других средах Node.js, это может измениться в будущем.

vi.stubEnv ​

  • Тип: <T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => Vitest

Изменяет значение переменной окружения в process.env и import.meta.env. Вы можете восстановить её значение, вызвав vi.unstubAllEnvs.

ts
import { vi } from 'vitest';

// `process.env.NODE_ENV` и `import.meta.env.NODE_ENV`
// являются "development" до вызова "vi.stubEnv"

vi.stubEnv('NODE_ENV', 'production');

process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';

vi.stubEnv('NODE_ENV', undefined);

process.env.NODE_ENV === undefined;
import.meta.env.NODE_ENV === undefined;

// не изменяет другие переменные окружения
import.meta.env.MODE === 'development';

TIP

Вы также можете изменить значение, просто присвоив его, но вы не сможете использовать vi.unstubAllEnvs для восстановления предыдущего значения:

ts
import.meta.env.MODE = 'test';

vi.unstubAllEnvs ​

  • Тип: () => Vitest

Восстанавливает все значения import.meta.env и process.env, которые были изменены с помощью vi.stubEnv. При первом вызове Vitest запоминает исходное значение и будет хранить его до тех пор, пока unstubAllEnvs не будет вызван повторно.

ts
import { vi } from 'vitest';

// `process.env.NODE_ENV` и `import.meta.env.NODE_ENV`
// являются "development" до вызова stubEnv

vi.stubEnv('NODE_ENV', 'production');

process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';

vi.stubEnv('NODE_ENV', 'staging');

process.env.NODE_ENV === 'staging';
import.meta.env.NODE_ENV === 'staging';

vi.unstubAllEnvs();

// восстанавливает значение, которое было сохранено до первого вызова "stubEnv"
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';

vi.stubGlobal ​

  • Тип: (name: string | number | symbol, value: unknown) => Vitest

Изменяет значение глобальной переменной. Вы можете восстановить её исходное значение, вызвав vi.unstubAllGlobals.

ts
import { vi } from 'vitest';

// `innerWidth` равно "0" до вызова stubGlobal

vi.stubGlobal('innerWidth', 100);

innerWidth === 100;
globalThis.innerWidth === 100;
// если вы используете jsdom или happy-dom
window.innerWidth === 100;

TIP

Вы также можете изменить значение, просто присвоив его globalThis или window (если вы используете среду jsdom или happy-dom), но вы не сможете использовать vi.unstubAllGlobals для восстановления исходного значения:

ts
globalThis.innerWidth = 100;
// если вы используете jsdom или happy-dom
window.innerWidth = 100;

vi.unstubAllGlobals ​

  • Тип: () => Vitest

Восстанавливает все глобальные значения в globalThis/global (и window/top/self/parent, если вы используете среду jsdom или happy-dom), которые были изменены с помощью vi.stubGlobal. При первом вызове Vitest запоминает исходное значение и будет хранить его до тех пор, пока unstubAllGlobals не будет вызван повторно.

ts
import { vi } from 'vitest';

const Mock = vi.fn();

// IntersectionObserver равен "undefined" до вызова "stubGlobal"

vi.stubGlobal('IntersectionObserver', Mock);

IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// если вы используете jsdom или happy-dom
window.IntersectionObserver === Mock;

vi.unstubAllGlobals();

globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// выбрасывает ReferenceError, поскольку он не определен
IntersectionObserver === undefined;

Фейковые таймеры ​

Этот раздел описывает, как работать с фейковыми таймерами.

vi.advanceTimersByTime ​

  • Тип: (ms: number) => Vitest

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

ts
let i = 0;
setInterval(() => console.log(++i), 50);

vi.advanceTimersByTime(150);

// log: 1
// log: 2
// log: 3

vi.advanceTimersByTimeAsync ​

  • Тип: (ms: number) => Promise<Vitest>

Этот метод будет вызывать каждый инициированный таймер до тех пор, пока не пройдет указанное количество миллисекунд или очередь не опустеет — в зависимости от того, что наступит раньше. Это будет включать асинхронно установленные таймеры.

ts
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);

await vi.advanceTimersByTimeAsync(150);

// log: 1
// log: 2
// log: 3

vi.advanceTimersToNextTimer ​

  • Тип: () => Vitest

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

ts
let i = 0;
setInterval(() => console.log(++i), 50);

vi.advanceTimersToNextTimer() // log: 1
  .advanceTimersToNextTimer() // log: 2
  .advanceTimersToNextTimer(); // log: 3

vi.advanceTimersToNextTimerAsync ​

  • Тип: () => Promise<Vitest>

Вызовет следующий доступный таймер и будет ждать его разрешения, если он был установлен асинхронно. Полезно для выполнения утверждений между каждым вызовом таймера.

ts
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);

await vi.advanceTimersToNextTimerAsync(); // log: 1
expect(console.log).toHaveBeenCalledWith(1);

await vi.advanceTimersToNextTimerAsync(); // log: 2
await vi.advanceTimersToNextTimerAsync(); // log: 3

vi.advanceTimersToNextFrame 2.1.0+ ​

  • Тип: () => Vitest

Аналогично vi.advanceTimersByTime, но будет продвигать таймеры на количество миллисекунд, необходимое для выполнения колбэков, запланированных в данный момент с помощью requestAnimationFrame.

ts
let frameRendered = false;

requestAnimationFrame(() => {
  frameRendered = true;
});

vi.advanceTimersToNextFrame();

expect(frameRendered).toBe(true);

vi.getTimerCount ​

  • Тип: () => number

Получить количество ожидающих таймеров.

vi.clearAllTimers ​

Удаляет все таймеры, запланированные к выполнению. Эти таймеры никогда не будут запущены в будущем.

vi.getMockedSystemTime ​

  • Тип: () => Date | null

Возвращает замокированную текущую дату. Если дата не замокирована, метод вернет null.

vi.getRealSystemTime ​

  • Тип: () => number

При использовании vi.useFakeTimers, вызовы Date.now мокируются. Если вам нужно получить реальное время в миллисекундах, вы можете вызвать эту функцию.

vi.runAllTicks ​

  • Тип: () => Vitest

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

vi.runAllTimers ​

  • Тип: () => Vitest

Этот метод будет вызывать каждый инициированный таймер до тех пор, пока очередь таймеров не опустеет. Это означает, что каждый таймер, вызванный во время runAllTimers, будет запущен. Если у вас бесконечный интервал, он выбросит исключение после 10 000 попыток (можно настроить с помощью fakeTimers.loopLimit).

ts
let i = 0;
setTimeout(() => console.log(++i));
const interval = setInterval(() => {
  console.log(++i);
  if (i === 3) {
    clearInterval(interval);
  }
}, 50);

vi.runAllTimers();

// log: 1
// log: 2
// log: 3

vi.runAllTimersAsync ​

  • Тип: () => Promise<Vitest>

Этот метод будет асинхронно вызывать каждый инициированный таймер до тех пор, пока очередь таймеров не опустеет. Это означает, что каждый таймер, вызванный во время runAllTimersAsync, будет запущен, включая асинхронные таймеры. Если у вас бесконечный интервал, он выбросит исключение после 10 000 попыток (можно настроить с помощью fakeTimers.loopLimit).

ts
setTimeout(async () => {
  console.log(await Promise.resolve('result'));
}, 100);

await vi.runAllTimersAsync();

// log: result

vi.runOnlyPendingTimers ​

  • Тип: () => Vitest

Этот метод вызовет каждый таймер, который был инициирован после вызова vi.useFakeTimers. Он не будет запускать никакие таймеры, которые были инициированы во время его вызова.

ts
let i = 0;
setInterval(() => console.log(++i), 50);

vi.runOnlyPendingTimers();

// log: 1

vi.runOnlyPendingTimersAsync ​

  • Тип: () => Promise<Vitest>

Этот метод асинхронно вызовет каждый таймер, который был инициирован после вызова vi.useFakeTimers, включая асинхронные. Он не будет запускать никакие таймеры, которые были инициированы во время его вызова.

ts
setTimeout(() => {
  console.log(1);
}, 100);
setTimeout(() => {
  Promise.resolve().then(() => {
    console.log(2);
    setInterval(() => {
      console.log(3);
    }, 40);
  });
}, 10);

await vi.runOnlyPendingTimersAsync();

// log: 2
// log: 3
// log: 3
// log: 1

vi.setSystemTime ​

  • Тип: (date: string | number | Date) => void

Если фейковые таймеры включены, этот метод имитирует изменение системных часов пользователем (повлияет на API, связанные с датой, такие как hrtime, performance.now или new Date()) — однако он не будет запускать никакие таймеры. Если фейковые таймеры не включены, этот метод будет мокировать только вызовы Date.*.

Полезно, если вам нужно протестировать что-либо, зависящее от текущей даты — например, вызовы Luxon в вашем коде.

Принимает те же строковые и числовые аргументы, что и конструктор Date.

ts
const date = new Date(1998, 11, 19);

vi.useFakeTimers();
vi.setSystemTime(date);

expect(Date.now()).toBe(date.valueOf());

vi.useRealTimers();

vi.useFakeTimers ​

  • Тип: (config?: FakeTimerInstallOpts) => Vitest

Чтобы включить мокирование таймеров, вам нужно вызвать этот метод. Он будет оборачивать все последующие вызовы таймеров (таких как setTimeout, setInterval, clearTimeout, clearInterval, setImmediate, clearImmediate и Date) до тех пор, пока не будет вызван vi.useRealTimers().

Мокирование nextTick не поддерживается при запуске Vitest внутри node:child_process с использованием --pool=forks. NodeJS использует process.nextTick внутри node:child_process и зависает при его мокировании. Мокирование nextTick поддерживается при запуске Vitest с --pool=threads.

Реализация основана на @sinonjs/fake-timers.

TIP

vi.useFakeTimers() не мокирует автоматически process.nextTick и queueMicrotask. Но вы можете включить это, указав опцию в аргументе toFake: vi.useFakeTimers({ toFake: ['nextTick', 'queueMicrotask'] }).

vi.isFakeTimers ​

  • Тип: () => boolean

Возвращает true, если фейковые таймеры включены.

vi.useRealTimers ​

  • Тип: () => Vitest

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

Различные утилиты ​

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

vi.waitFor ​

  • Тип: <T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>

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

Если options установлено в число, эффект эквивалентен установке { timeout: options }.

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

ts
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';

test('Сервер успешно запущен', async () => {
  const server = createServer();

  await vi.waitFor(
    () => {
      if (!server.isReady) {
        throw new Error('Сервер не запущен');
      }

      console.log('Сервер запущен');
    },
    {
      timeout: 500, // по умолчанию 1000
      interval: 20, // по умолчанию 50
    }
  );
  expect(server.isReady).toBe(true);
});

Это также работает для асинхронных колбэков

ts
// @vitest-environment jsdom

import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';

test('Элемент существует в DOM', async () => {
  // начать заполнение DOM
  populateDOMAsync();

  const element = await vi.waitFor(
    async () => {
      // пытаться получить элемент, пока он не появится
      const element = (await getDOMElementAsync()) as HTMLElement | null;
      expect(element).toBeTruthy();
      expect(element.dataset.initialized).toBeTruthy();
      return element;
    },
    {
      timeout: 500, // по умолчанию 1000
      interval: 20, // по умолчанию 50
    }
  );
  expect(element).toBeInstanceOf(HTMLElement);
});

Если используется vi.useFakeTimers, vi.waitFor автоматически вызывает vi.advanceTimersByTime(interval) в каждом колбэке проверки.

vi.waitUntil ​

  • Тип: <T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>

Это похоже на vi.waitFor, но если колбэк выбрасывает какие-либо ошибки, выполнение немедленно прерывается и выдается сообщение об ошибке. Если колбэк возвращает ложное значение, следующая проверка будет продолжаться до тех пор, пока не будет возвращено истинное значение. Это полезно, когда вам нужно дождаться существования чего-либо, прежде чем предпринимать следующий шаг.

Посмотрите на пример ниже. Мы можем использовать vi.waitUntil, чтобы дождаться появления элемента на странице, а затем мы можем что-то сделать с этим элементом.

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

test('Элемент отображается корректно', async () => {
  const element = await vi.waitUntil(() => document.querySelector('.element'), {
    timeout: 500, // по умолчанию 1000
    interval: 20, // по умолчанию 50
  });

  // сделать что-то с элементом
  expect(element.querySelector('.element-child')).toBeTruthy();
});

vi.hoisted ​

  • Тип: <T>(factory: () => T) => T

Все статические операторы import в модулях ES поднимаются в начало файла, поэтому любой код, определенный до импортов, фактически будет выполнен после оценки импортов.

Однако может быть полезно вызвать некоторые побочные эффекты, такие как мокирование дат, перед импортом модуля.

Чтобы обойти это ограничение, вы можете переписать статические импорты в динамические следующим образом:

diff
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')

При запуске vitest вы можете сделать это автоматически, используя метод vi.hoisted. На низком уровне Vitest преобразует статические импорты в динамические с сохранением живых привязок.

diff
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())

ИМПОРТЫ НЕДОСТУПНЫ

Выполнение кода до импортов означает, что вы не можете получить доступ к импортированным переменным, поскольку они еще не определены:

ts
import { value } from './some/module.js';

vi.hoisted(() => { value }); // выбрасывает ошибку

Этот код выдаст ошибку:

Cannot access '__vi_import_0__' before initialization

Если вам нужно получить доступ к переменной из другого модуля внутри vi.hoisted, используйте динамический импорт:

ts
await vi.hoisted(async () => {
  const { value } = await import('./some/module.js');
});

Однако не рекомендуется импортировать что-либо внутри vi.hoisted, поскольку импорты уже подняты — если вам нужно выполнить что-то до запуска тестов, просто выполните это в самом импортированном модуле.

Этот метод возвращает значение, которое было возвращено фабрикой. Вы можете использовать это значение в своих фабриках vi.mock, если вам нужен легкий доступ к локально определенным переменным:

ts
import { expect, vi } from 'vitest';
import { originalMethod } from './path/to/module.js';

const { mockedMethod } = vi.hoisted(() => {
  return { mockedMethod: vi.fn() };
});

vi.mock('./path/to/module.js', () => {
  return { originalMethod: mockedMethod };
});

mockedMethod.mockReturnValue(100);
expect(originalMethod()).toBe(100);

Обратите внимание, что этот метод также может быть вызван асинхронно, даже если ваша среда не поддерживает top-level await:

ts
const json = await vi.hoisted(async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  return response.json();
});

vi.setConfig ​

  • Тип: RuntimeConfig

Обновляет конфигурацию для текущего тестового файла. Этот метод поддерживает только те параметры конфигурации, которые повлияют на текущий тестовый файл:

ts
vi.setConfig({
  allowOnly: true,
  testTimeout: 10_000,
  hookTimeout: 10_000,
  clearMocks: true,
  restoreMocks: true,
  fakeTimers: {
    now: new Date(2021, 11, 19),
    // поддерживает весь объект
  },
  maxConcurrency: 10,
  sequence: {
    hooks: 'stack',
    // поддерживает только "sequence.hooks"
  },
});

vi.resetConfig ​

  • Тип: RuntimeConfig

Если vi.setConfig был вызван ранее, это сбросит конфигурацию до исходного состояния.

Pager
Предыдущая страницаМок-функции
Следующая страницаexpect

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

Авторские права (c) 2021-Present Vitest Team

https://vitest.dev/api/vi

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

Авторские права (c) 2021-Present Vitest Team