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

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

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

Мокирование ​

При написании тестов часто возникает необходимость создать имитированную версию внутренней или внешней службы. Этот процесс обычно называется мокированием. Vitest предоставляет вспомогательные функции для этого через объект vi. Вы можете импортировать его из vitest или получить к нему доступ глобально, если включена конфигурация global.

WARNING

Всегда помните очищать или восстанавливать моки до или после каждого запуска теста, чтобы сбросить их состояние между запусками! Дополнительную информацию см. в документации mockReset.

Если вы не знакомы с методами vi.fn, vi.mock или vi.spyOn, сначала ознакомьтесь с разделом API.

Даты ​

Иногда необходимо контролировать дату для обеспечения согласованности при тестировании. Vitest использует пакет @sinonjs/fake-timers для манипулирования таймерами и системной датой. Более подробную информацию о конкретном API можно найти здесь.

Пример ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const businessHours = [9, 17];

function purchase() {
  const currentHour = new Date().getHours();
  const [open, close] = businessHours;

  if (currentHour > open && currentHour < close) {
    return { message: 'Success' };
  }

  return { message: 'Error' };
}

describe('purchasing flow', () => {
  beforeEach(() => {
    // информируем vitest о том, что мы используем мокированное время
    vi.useFakeTimers();
  });

  afterEach(() => {
    // восстанавливаем реальное время после каждого теста
    vi.useRealTimers();
  });

  it('allows purchases within business hours', () => {
    // устанавливаем час в пределах рабочего времени
    const date = new Date(2000, 1, 1, 13);
    vi.setSystemTime(date);

    // вызов Date.now() вернет дату, установленную выше
    expect(purchase()).toEqual({ message: 'Success' });
  });

  it('disallows purchases outside of business hours', () => {
    // устанавливаем час за пределами рабочего времени
    const date = new Date(2000, 1, 1, 19);
    vi.setSystemTime(date);

    // вызов Date.now() вернет дату, установленную выше
    expect(purchase()).toEqual({ message: 'Error' });
  });
});

Функции ​

Мокирование функций можно разделить на две категории: отслеживание и мокирование.

Иногда все, что вам нужно, это проверить, была ли вызвана конкретная функция (и, возможно, какие аргументы были переданы). В таких случаях достаточно отслеживания, которое можно использовать напрямую с vi.spyOn() (подробнее здесь).

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

Мы используем Tinyspy в качестве основы для мокирования функций, но у нас есть собственная обертка, чтобы сделать его совместимым с jest. Методы vi.fn() и vi.spyOn() обладают одинаковыми методами, однако только возвращаемый результат vi.fn() является вызываемым.

Пример ​

js
import { afterEach, describe, expect, it, vi } from 'vitest';

const messages = {
  items: [
    { message: 'Simple test message', from: 'Testman' },
    // ...
  ],
  getLatest, // также может быть `getter` или `setter`, если поддерживается
};

function getLatest(index = messages.items.length - 1) {
  return messages.items[index];
}

describe('reading messages', () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('should get the latest message with a spy', () => {
    const spy = vi.spyOn(messages, 'getLatest');
    expect(spy.getMockName()).toEqual('getLatest');

    expect(messages.getLatest()).toEqual(
      messages.items[messages.items.length - 1]
    );

    expect(spy).toHaveBeenCalledTimes(1);

    spy.mockImplementationOnce(() => 'access-restricted');
    expect(messages.getLatest()).toEqual('access-restricted');

    expect(spy).toHaveBeenCalledTimes(2);
  });

  it('should get with a mock', () => {
    const mock = vi.fn().mockImplementation(getLatest);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(1);

    mock.mockImplementationOnce(() => 'access-restricted');
    expect(mock()).toEqual('access-restricted');

    expect(mock).toHaveBeenCalledTimes(2);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(3);
  });
});

Подробнее ​

  • Мок-функции Jest

Глобальные переменные ​

Вы можете мокировать глобальные переменные, которые не определены в jsdom или node, используя вспомогательную функцию vi.stubGlobal. Она установит значение глобальной переменной в объекте globalThis.

ts
import { vi } from 'vitest';

const IntersectionObserverMock = vi.fn(() => ({
  disconnect: vi.fn(),
  observe: vi.fn(),
  takeRecords: vi.fn(),
  unobserve: vi.fn(),
}));

vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);

// теперь вы можете получить к нему доступ как `IntersectionObserver` или `window.IntersectionObserver`

Модули ​

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

Подробное описание API см. в разделе vi.mock() API.

Алгоритм автомокирования ​

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

Применяются следующие принципы:

  • Все массивы будут опустошены.
  • Все примитивы и коллекции останутся без изменений.
  • Все объекты будут глубоко клонированы.
  • Все экземпляры классов и их прототипы будут клонированы с глубоким копированием.

Виртуальные модули ​

Vitest поддерживает мокирование виртуальных модулей Vite. Это работает иначе, чем обработка виртуальных модулей в Jest. Вместо передачи virtual: true в функцию vi.mock, вам нужно сообщить Vite, что модуль существует, иначе это приведет к ошибке во время парсинга. Вы можете сделать это несколькими способами:

  1. Предоставить псевдоним
ts
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
  test: {
    alias: {
      '$app/forms': resolve('./mocks/forms.js'),
    },
  },
});
  1. Предоставить плагин, который разрешает виртуальный модуль
ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  plugins: [
    {
      name: 'virtual-modules',
      resolveId(id) {
        if (id === '$app/forms') {
          return 'virtual:$app/forms';
        }
      },
    },
  ],
});

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

Особенности мокирования ​

Имейте в виду, что невозможно мокировать вызовы методов, которые вызываются внутри других методов того же файла. Например, в этом коде:

ts
export function foo() {
  return 'foo';
}

export function foobar() {
  return `${foo()}bar`;
}

Невозможно мокировать метод foo извне, потому что он вызывается напрямую. Таким образом, этот код не повлияет на вызов foo в функции foobar (но повлияет на вызов foo в других модулях):

ts
import { vi } from 'vitest';
import * as mod from './foobar.js';

// это повлияет только на "foo" вне исходного модуля
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
  return {
    ...(await importOriginal<typeof import('./foobar.js')>()),
    // это повлияет только на "foo" вне исходного модуля
    foo: () => 'mocked',
  };
});

Вы можете подтвердить это поведение, предоставив реализацию методу foobar напрямую:

ts
import * as mod from './foobar.js';

vi.spyOn(mod, 'foo');

// экспортированный foo ссылается на мокированный метод
mod.foobar(mod.foo);
ts
export function foo() {
  return 'foo';
}

export function foobar(injectedFoo) {
  return injectedFoo === foo; // false
}

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

Пример ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';

// получить задачи
export async function getTodos(event, context) {
  const client = new Client({
    // ...clientOptions
  });

  await client.connect();

  try {
    const result = await client.query('SELECT * FROM todos;');

    client.end();

    return success({
      message: `${result.rowCount} item(s) returned`,
      data: result.rows,
      status: true,
    });
  } catch (e) {
    console.error(e.stack);

    client.end();

    return failure({ message: e, status: false });
  }
}

vi.mock('pg', () => {
  const Client = vi.fn();
  Client.prototype.connect = vi.fn();
  Client.prototype.query = vi.fn();
  Client.prototype.end = vi.fn();

  return { Client };
});

vi.mock('./handlers.js', () => {
  return {
    success: vi.fn(),
    failure: vi.fn(),
  };
});

describe('get a list of todo items', () => {
  let client;

  beforeEach(() => {
    client = new Client();
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  it('should return items successfully', async () => {
    client.query.mockResolvedValueOnce({ rows: [], rowCount: 0 });

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);

    expect(success).toBeCalledWith({
      message: '0 item(s) returned',
      data: [],
      status: true,
    });
  });

  it('should throw an error', async () => {
    const mError = new Error('Unable to retrieve rows');
    client.query.mockRejectedValueOnce(mError);

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);
    expect(failure).toBeCalledWith({ message: mError, status: false });
  });
});

Файловая система ​

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

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

Пример ​

Чтобы автоматически перенаправлять все вызовы fs в memfs, вы можете создать файлы __mocks__/fs.cjs и __mocks__/fs/promises.cjs в корне вашего проекта:

ts
// мы также можем использовать `import`, но тогда
// каждый экспорт должен быть явно определен

const { fs } = require('memfs');
module.exports = fs;
ts
// мы также можем использовать `import`, но тогда
// каждый экспорт должен быть явно определен

const { fs } = require('memfs');
module.exports = fs.promises;
ts
import { readFileSync } from 'node:fs';

export function readHelloWorld(path) {
  return readFileSync(path, 'utf-8');
}
ts
import { beforeEach, expect, it, vi } from 'vitest';
import { fs, vol } from 'memfs';
import { readHelloWorld } from './read-hello-world.js';

// сообщаем vitest использовать мок fs из папки __mocks__
// это можно сделать в файле настройки, если fs всегда должен быть мокирован
vi.mock('node:fs');
vi.mock('node:fs/promises');

beforeEach(() => {
  // сбрасываем состояние файловой системы в памяти
  vol.reset();
});

it('should return correct text', () => {
  const path = '/hello-world.txt';
  fs.writeFileSync(path, 'hello world');

  const text = readHelloWorld(path);
  expect(text).toBe('hello world');
});

it('can return a value multiple times', () => {
  // вы можете использовать vol.fromJSON для определения нескольких файлов
  vol.fromJSON(
    {
      './dir1/hw.txt': 'hello dir1',
      './dir2/hw.txt': 'hello dir2',
    },
    // cwd по умолчанию
    '/tmp'
  );

  expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1');
  expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2');
});

Запросы ​

Поскольку Vitest работает в Node, мокирование сетевых запросов является непростой задачей; веб-API не поддерживаются, поэтому нам нужно что-то, что будет имитировать сетевое поведение. Мы рекомендуем Mock Service Worker для достижения этой цели. Он позволяет мокировать сетевые запросы http, WebSocket и GraphQL и не привязан к фреймворку.

Mock Service Worker (MSW) работает путем перехвата запросов, выполняемых вашими тестами, что позволяет использовать его без изменения кода вашего приложения. В браузере для этого используется Service Worker API. В Node.js и для Vitest он использует библиотеку @mswjs/interceptors. Чтобы узнать больше о MSW, прочитайте их введение

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

Вы можете использовать его, как показано ниже, в вашем файле настройки

js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

export const restHandlers = [
  http.get('https://rest-endpoint.example/path/to/posts', () => {
    return HttpResponse.json(posts);
  }),
];

const server = setupServer(...restHandlers);

// Запустить сервер перед всеми тестами
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// Закрыть сервер после всех тестов
afterAll(() => server.close());

// Сбросить обработчики после каждого теста для изоляции тестов
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { graphql, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

const graphqlHandlers = [
  graphql.query('ListPosts', () => {
    return HttpResponse.json({
      data: { posts },
    });
  }),
];

const server = setupServer(...graphqlHandlers);

// Запустить сервер перед всеми тестами
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// Закрыть сервер после всех тестов
afterAll(() => server.close());

// Сбросить обработчики после каждого теста для изоляции тестов
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { ws } from 'msw';

const chat = ws.link('wss://chat.example.com');

const wsHandlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.addEventListener('message', event => {
      console.log('Received message from client:', event.data);
      // Отправляем полученное сообщение обратно клиенту
      client.send(`Server received: ${event.data}`);
    });
  }),
];

const server = setupServer(...wsHandlers);

// Запустить сервер перед всеми тестами
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// Закрыть сервер после всех тестов
afterAll(() => server.close());

// Сбросить обработчики после каждого теста для изоляции тестов
afterEach(() => server.resetHandlers());

Настройка сервера с onUnhandledRequest: 'error' гарантирует, что будет выброшена ошибка при каждом запросе, для которого не найден соответствующий обработчик.

Подробнее ​

MSW предоставляет гораздо больше возможностей. Вы можете получать доступ к файлам cookie и параметрам запроса, определять имитированные ответы об ошибках и многое другое! Чтобы узнать все, что вы можете сделать с MSW, прочитайте их документацию.

Таймеры ​

Когда мы тестируем код, который использует тайм-ауты или интервалы, вместо того чтобы наши тесты ждали или завершались по тайм-ауту, мы можем ускорить наши тесты, используя "фальшивые" таймеры, которые имитируют вызовы setTimeout и setInterval.

Подробное описание API см. в разделе vi.useFakeTimers API.

Пример ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

function executeAfterTwoHours(func) {
  setTimeout(func, 1000 * 60 * 60 * 2); // 2 часа
}

function executeEveryMinute(func) {
  setInterval(func, 1000 * 60); // 1 минута
}

const mock = vi.fn(() => console.log('executed'));

describe('delayed execution', () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });
  afterEach(() => {
    vi.restoreAllMocks();
  });
  it('should execute the function', () => {
    executeAfterTwoHours(mock);
    vi.runAllTimers();
    expect(mock).toHaveBeenCalledTimes(1);
  });
  it('should not execute the function', () => {
    executeAfterTwoHours(mock);
    // перемещение времени на 2 мс не вызовет функцию
    vi.advanceTimersByTime(2);
    expect(mock).not.toHaveBeenCalled();
  });
  it('should execute every minute', () => {
    executeEveryMinute(mock);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(1);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(2);
  });
});

Классы ​

Вы можете мокировать весь класс одним вызовом vi.fn — поскольку все классы также являются функциями, это поддерживается по умолчанию. Имейте в виду, что в настоящее время Vitest не обрабатывает ключевое слово new, поэтому new.target всегда будет undefined в теле функции.

ts
class Dog {
  name: string;

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

  static getType(): string {
    return 'animal';
  }

  greet = (): string => {
    return `Hi! My name is ${this.name}!`;
  };

  speak(): string {
    return 'bark!';
  }

  isHungry() {}
  feed() {}
}

Мы можем воссоздать этот класс с помощью функций ES5:

ts
const Dog = vi.fn(function (name) {
  this.name = name;
  // имитируем методы экземпляра в конструкторе, каждый экземпляр будет иметь свой собственный отслеживаемый метод
  this.greet = vi.fn(() => `Hi! My name is ${this.name}!`);
});

// обратите внимание, что статические методы имитируются непосредственно на функции,
// а не на экземпляре класса
Dog.getType = vi.fn(() => 'mocked animal');

// имитируем методы "speak" и "feed" на каждом экземпляре класса
// все экземпляры `new Dog()` будут наследовать и совместно использовать эти отслеживаемые методы
Dog.prototype.speak = vi.fn(() => 'loud bark!');
Dog.prototype.feed = vi.fn();

WARNING

Если из функции-конструктора возвращается не примитивное значение, это значение станет результатом нового выражения. В этом случае [[Prototype]] может быть некорректно установлен:

ts
const CorrectDogClass = vi.fn(function (name) {
  this.name = name;
});

const IncorrectDogClass = vi.fn(name => ({
  name,
}));

const Marti = new CorrectDogClass('Marti');
const Newt = new IncorrectDogClass('Newt');

Marti instanceof CorrectDogClass; // ✅ true
Newt instanceof IncorrectDogClass; // ❌ false!

КОГДА ИСПОЛЬЗОВАТЬ?

Как правило, класс воссоздается таким образом внутри фабрики модуля, если он реэкспортируется из другого модуля:

ts
import { Dog } from './dog.js';

vi.mock(import('./dog.js'), () => {
  const Dog = vi.fn();
  Dog.prototype.feed = vi.fn();
  // ... другие моки
  return { Dog };
});

Этот метод также можно использовать для передачи экземпляра класса функции, которая принимает тот же интерфейс:

ts
function feed(dog: Dog) {
  // ...
}
ts
import { expect, test, vi } from 'vitest';
import { feed } from '../src/feed.js';

const Dog = vi.fn();
Dog.prototype.feed = vi.fn();

test('can feed dogs', () => {
  const dogMax = new Dog('Max');

  feed(dogMax);

  expect(dogMax.feed).toHaveBeenCalled();
  expect(dogMax.isHungry()).toBe(false);
});

Теперь, когда мы создаем новый экземпляр класса Dog, его метод speak (наряду с feed и greet) уже мокирован:

ts
const Cooper = new Dog('Cooper');
Cooper.speak(); // loud bark!
Cooper.greet(); // Hi! My name is Cooper!

// вы можете использовать встроенные утверждения для проверки корректности вызова
expect(Cooper.speak).toHaveBeenCalled();
expect(Cooper.greet).toHaveBeenCalled();

const Max = new Dog('Max');

// методы, назначенные прототипу, являются общими между экземплярами
expect(Max.speak).toHaveBeenCalled();
expect(Max.greet).not.toHaveBeenCalled();

Мы можем переназначить возвращаемое значение для конкретного экземпляра:

ts
const dog = new Dog('Cooper');

// "vi.mocked" - это вспомогательный тип, поскольку
// TypeScript не знает, что Dog - это мокированный класс,
// он оборачивает любую функцию в тип MockInstance<T>
// без проверки, является ли функция моком
vi.mocked(dog.speak).mockReturnValue('woof woof');

dog.speak(); // woof woof

Чтобы мокировать свойство, мы можем использовать метод vi.spyOn(dog, 'name', 'get'). Это позволяет использовать утверждения отслеживания для мокированного свойства:

ts
const dog = new Dog('Cooper');

const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max');

expect(dog.name).toBe('Max');
expect(nameSpy).toHaveBeenCalledTimes(1);

TIP

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

Шпаргалка ​

INFO

vi в примерах ниже импортируется непосредственно из vitest. Вы также можете использовать его глобально, если установите globals в true в вашей конфигурации.

Возможные сценарии:

Мокировать экспортированные переменные ​

js
export const getter = 'variable';
ts
import * as exports from './example.js';

vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');

Мокировать экспортированную функцию ​

  1. Пример с vi.mock:

WARNING

Не забывайте, что вызов vi.mock перемещается в начало файла. Он всегда будет выполняться перед всеми импортами.

ts
export function method() {}
ts
import { method } from './example.js';

vi.mock('./example.js', () => ({
  method: vi.fn(),
}));
  1. Пример с vi.spyOn:
ts
import * as exports from './example.js';

vi.spyOn(exports, 'method').mockImplementation(() => {});

Мокировать реализацию экспортированного класса ​

  1. Пример с vi.mock и .prototype:
ts
export class SomeClass {}
ts
import { SomeClass } from './example.js';

vi.mock(import('./example.js'), () => {
  const SomeClass = vi.fn();
  SomeClass.prototype.someMethod = vi.fn();
  return { SomeClass };
});
// SomeClass.mock.instances будет иметь SomeClass
  1. Пример с vi.spyOn:
ts
import * as mod from './example.js';

const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();

vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);

Отслеживать объект, возвращаемый из функции ​

  1. Пример использования кеша:
ts
export function useObject() {
  return { method: () => true };
}
ts
import { useObject } from './example.js';

const obj = useObject();
obj.method();
ts
import { useObject } from './example.js';

vi.mock(import('./example.js'), () => {
  let _cache;
  const useObject = () => {
    if (!_cache) {
      _cache = {
        method: vi.fn(),
      };
    }
    // теперь каждый раз, когда вызывается useObject(), он будет
    // возвращать ту же ссылку на объект
    return _cache;
  };
  return { useObject };
});

const obj = useObject();
// obj.method был вызван внутри some-path
expect(obj.method).toHaveBeenCalled();

Мокировать часть модуля ​

ts
import { mocked, original } from './some-path.js';

vi.mock(import('./some-path.js'), async importOriginal => {
  const mod = await importOriginal();
  return {
    ...mod,
    mocked: vi.fn(),
  };
});
original(); // сохраняет оригинальное поведение
mocked(); // является отслеживаемой функцией

WARNING

Не забывайте, что это мокирует только внешний доступ. В этом примере, если original вызывает mocked внутренне, он всегда будет вызывать функцию, определенную в модуле, а не в фабрике моков.

Мокировать текущую дату ​

Чтобы мокировать время Date, вы можете использовать вспомогательную функцию vi.setSystemTime. Это значение не будет автоматически сбрасываться между различными тестами.

Имейте в виду, что использование vi.useFakeTimers также изменяет время Date.

ts
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// сброс мокированного времени
vi.useRealTimers();

Мокировать глобальную переменную ​

Вы можете установить глобальную переменную, присвоив значение свойству globalThis или используя вспомогательную функцию vi.stubGlobal. При использовании vi.stubGlobal она не будет автоматически сбрасываться между различными тестами, если вы не включите опцию конфигурации unstubGlobals или не вызовете vi.unstubAllGlobals.

ts
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');

Мокировать import.meta.env ​

  1. Чтобы изменить переменную окружения, вы можете просто присвоить ей новое значение.

WARNING

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

ts
import { beforeEach, expect, it } from 'vitest';

// перед запуском тестов "VITE_ENV" имеет значение "test"
const originalViteEnv = import.meta.env.VITE_ENV;

beforeEach(() => {
  import.meta.env.VITE_ENV = originalViteEnv;
});

it('changes value', () => {
  import.meta.env.VITE_ENV = 'staging';
  expect(import.meta.env.VITE_ENV).toBe('staging');
});
  1. Если вы хотите автоматически сбрасывать значение(я), вы можете использовать вспомогательную функцию vi.stubEnv с включенной опцией конфигурации unstubEnvs (или вручную вызвать vi.unstubAllEnvs в хуке beforeEach):
ts
import { expect, it, vi } from 'vitest';

// перед запуском тестов "VITE_ENV" имеет значение "test"
import.meta.env.VITE_ENV === 'test';

it('changes value', () => {
  vi.stubEnv('VITE_ENV', 'staging');
  expect(import.meta.env.VITE_ENV).toBe('staging');
});

it('the value is restored before running an other test', () => {
  expect(import.meta.env.VITE_ENV).toBe('test');
});
ts
export default defineConfig({
  test: {
    unstubEnvs: true,
  },
});
Pager
Предыдущая страницаСнапшот-тестирование
Следующая страницаПараллелизм

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

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

https://vitest.dev/guide/mocking

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

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