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

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

Mock-функции

Vitest

expect

expectTypeOf

assert

assertType

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

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 всплывает (hoisted), поэтому не имеет значения, где вы его вызываете. Он всегда будет выполнен перед всеми импортами. Если вам нужно ссылаться на переменные вне его области видимости, вы можете определить их внутри 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 или вспомогательную функцию, которой передается фабрика в качестве первого аргумента, и получить оригинальный модуль внутри.

Начиная с Vitest 2.1, вы также можете предоставить объект со свойством 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 в тестовом файле без предоставления factory или опций, он найдет файл в папке __mocks__ для использования в качестве модуля:

ts
// increment.test.js
import { vi } from 'vitest';

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

// increment - это именованный экспорт (named export) из `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__ отсутствует или factory не предоставлен, 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
// ./increment.js
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
// example.ts
export function add(x: number, y: number): number {
  return x + y;
}

export function fetchSomething(): Promise<Response> {
  return fetch('https://vitest.dev/');
}
ts
// example.test.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 axios = await vi.importActual('./example.js');

  return { ...axios, 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
// ./increment.js
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

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

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.isMockFunction ​

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

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

vi.clearAllMocks ​

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

vi.resetAllMocks ​

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

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

Вы можете вызвать 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

Возвращает поддельную текущую дату, которая была установлена с помощью setSystemTime. Если дата не подделана, метод вернет 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 автоматически. Но вы можете включить его, указав опцию в аргументе toFake: vi.useFakeTimers({ toFake: ['nextTick'] }).

vi.isFakeTimers ​

  • Тип: () => boolean

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

vi.useRealTimers ​

  • Тип: () => Vitest

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

Разное ​

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

vi.waitFor ​

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

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

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

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.

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

Этот метод возвращает значение, которое было возвращено из функции-фабрики. Вы можете использовать это значение в функциях-фабриках для 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 promised = 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
Предыдущая страницаMock-функции
Следующая страницаexpect

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

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

https://v2.vitest.dev/api/vi

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

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