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

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

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

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

Вдохновленный Playwright Fixtures, контекст теста Vitest позволяет определять утилиты, состояния и фикстуры, используемые в ваших тестах.

Использование ​

Первый аргумент каждого коллбэка теста — это контекст теста.

ts
import { it } from 'vitest';

it('should work', ({ task }) => {
  // выводит название теста
  console.log(task.name);
});

Встроенный контекст теста ​

task ​

Объект, доступный только для чтения, содержащий метаданные о тесте.

expect ​

API expect, связанный с текущим тестом:

ts
import { it } from 'vitest';

it('math is easy', ({ expect }) => {
  expect(2 + 2).toBe(4);
});

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

ts
import { it } from 'vitest';

it.concurrent('math is easy', ({ expect }) => {
  expect(2 + 2).toMatchInlineSnapshot();
});

it.concurrent('math is hard', ({ expect }) => {
  expect(2 * 2).toMatchInlineSnapshot();
});

skip ​

ts
function skip(note?: string): never;
function skip(condition: boolean, note?: string): void;

Пропускает дальнейшее выполнение теста и помечает тест как пропущенный:

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

it('math is hard', ({ skip }) => {
  skip();
  expect(2 + 2).toBe(5);
});

Начиная с Vitest 3.1, он принимает логический параметр для условного пропуска теста:

ts
it('math is hard', ({ skip, mind }) => {
  skip(mind === 'foggy');
  expect(2 + 2).toBe(5);
});

annotate 3.2.0+ ​

ts
function annotate(
  message: string,
  attachment?: TestAttachment
): Promise<TestAnnotation>;

function annotate(
  message: string,
  type?: string,
  attachment?: TestAttachment
): Promise<TestAnnotation>;

Добавляет аннотацию для теста, которая будет отображаться в вашем репортере.

ts
test('annotations API', async ({ annotate }) => {
  await annotate('https://github.com/vitest-dev/vitest/pull/7953', 'issues');
});

signal 3.2.0+ ​

AbortSignal, который может быть прерван Vitest. Сигнал будет прерван в следующих случаях:

  • Время выполнения теста истекло.
  • Пользователь вручную отменил запуск теста с помощью Ctrl+C.
  • vitest.cancelCurrentRun был вызван программно.
  • Другой тест параллельно завершился с ошибкой, и установлен флаг bail.
ts
it('stop request when test times out', async ({ signal }) => {
  await fetch('/resource', { signal });
}, 2000);

onTestFailed ​

Хук onTestFailed, связанный с текущим тестом. Этот API полезен, если вы запускаете тесты параллельно и требуется специальная обработка только для этого конкретного теста.

onTestFinished ​

Хук onTestFinished, связанный с текущим тестом. Этот API полезен, если вы запускаете тесты параллельно и требуется специальная обработка только для этого конкретного теста.

Расширение контекста теста ​

Vitest предоставляет два способа расширения контекста теста.

test.extend ​

Как и Playwright, вы можете использовать этот метод для создания собственного API test с пользовательскими фикстурами и их повторного использования в любом месте.

Например, сначала мы создаем объект test с двумя фикстурами: todos и archive.

ts
import { test as baseTest } from 'vitest';

const todos = [];
const archive = [];

export const test = baseTest.extend({
  todos: async ({}, use) => {
    // настройка фикстуры перед каждым тестом
    todos.push(1, 2, 3);

    // использование значения фикстуры
    await use(todos);

    // очистка фикстуры после каждого теста
    todos.length = 0;
  },
  archive,
});

Затем мы можем импортировать и использовать его.

ts
import { expect } from 'vitest';
import { test } from './my-test.js';

test('add items to todos', ({ todos }) => {
  expect(todos.length).toBe(3);

  todos.push(4);
  expect(todos.length).toBe(4);
});

test('move items from todos to archive', ({ todos, archive }) => {
  expect(todos.length).toBe(3);
  expect(archive.length).toBe(0);

  archive.push(todos.pop());
  expect(todos.length).toBe(2);
  expect(archive.length).toBe(1);
});

Мы также можем добавить больше фикстур или переопределить существующие фикстуры, расширив наш test.

ts
import { test as todosTest } from './my-test.js';

export const test = todosTest.extend({
  settings: {
    // ...
  },
});

Инициализация фикстуры ​

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

ts
import { test as baseTest } from 'vitest';

const test = baseTest.extend<{
  todos: number[];
  archive: number[];
}>({
  todos: async ({ task }, use) => {
    await use([1, 2, 3]);
  },
  archive: [],
});

// todos не будет инициализирован
test('skip', () => {});
test('skip', ({ archive }) => {});

// todos будет инициализирован
test('run', ({ todos }) => {});

WARNING

При использовании test.extend() с фикстурами, вы всегда должны использовать деструктуризацию объекта { todos } для доступа к контексту как в функции фикстуры, так и в функции теста.

ts
test('context must be destructured', (context) => { 
  expect(context.todos.length).toBe(2)
})

test('context must be destructured', ({ todos }) => { 
  expect(todos.length).toBe(2)
})

Автоматическая фикстура ​

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

ts
import { test as base } from 'vitest';

const test = base.extend({
  fixture: [
    async ({}, use) => {
      // эта функция будет запущена
      setup();
      await use();
      teardown();
    },
    { auto: true }, // Указать, что фикстура автоматическая
  ],
});

test('works correctly');

Фикстура по умолчанию ​

Начиная с Vitest 3, вы можете задавать разные значения для различных проектов. Чтобы включить эту функцию, передайте { injected: true } в опции. Если ключ не задан в конфигурации проекта, используется значение по умолчанию.

ts
import { test as base } from 'vitest';

const test = base.extend({
  url: [
    // значение по умолчанию, если "url" не определен в конфигурации
    '/default',
    // пометить фикстуру как "injected", чтобы разрешить переопределение
    { injected: true },
  ],
});

test('works correctly', ({ url }) => {
  // url равен "/default" в "project-new"
  // url равен "/full" в "project-full"
  // url равен "/empty" в "project-empty"
});
ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    projects: [
      {
        test: {
          name: 'project-new',
        },
      },
      {
        test: {
          name: 'project-full',
          provide: {
            url: '/full',
          },
        },
      },
      {
        test: {
          name: 'project-empty',
          provide: {
            url: '/empty',
          },
        },
      },
    ],
  },
});

Область видимости значений в наборе тестов 3.1.0+ ​

Начиная с Vitest 3.1, вы можете переопределять значения контекста для каждого набора тестов и его дочерних элементов, используя API test.scoped:

ts
import { test as baseTest, describe, expect } from 'vitest';

const test = baseTest.extend({
  dependency: 'default',
  dependant: ({ dependency }, use) => use({ dependency }),
});

describe('use scoped values', () => {
  test.scoped({ dependency: 'new' });

  test('uses scoped value', ({ dependant }) => {
    // `dependant` использует новое переопределенное значение, которое действует
    // для всех тестов в этом наборе
    expect(dependant).toEqual({ dependency: 'new' });
  });

  describe('keeps using scoped value', () => {
    test('uses scoped value', ({ dependant }) => {
      // вложенный набор тестов унаследовал значение
      expect(dependant).toEqual({ dependency: 'new' });
    });
  });
});

test('keep using the default values', ({ dependant }) => {
  // `dependency` использует значение по умолчанию
  // вне набора с .scoped
  expect(dependant).toEqual({ dependency: 'default' });
});

Этот API особенно полезен, если у вас есть значение контекста, которое зависит от динамической переменной, такой как подключение к базе данных:

ts
const test = baseTest.extend<{
  db: Database;
  schema: string;
}>({
  db: async ({ schema }, use) => {
    const db = await createDb({ schema });
    await use(db);
    await cleanup(db);
  },
  schema: '',
});

describe('one type of schema', () => {
  test.scoped({ schema: 'schema-1' });

  // ... тесты
});

describe('another type of schema', () => {
  test.scoped({ schema: 'schema-2' });

  // ... тесты
});

Контекст с заданной областью видимости 3.2.0+ ​

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

ts
import { test as baseTest } from 'vitest';

export const test = baseTest.extend({
  perFile: [({}, { use }) => use([]), { scope: 'file' }],
  perWorker: [({}, { use }) => use([]), { scope: 'worker' }],
});

Значение инициализируется при первом доступе к нему любым тестом, если только опции фикстуры не содержат auto: true. В этом случае значение инициализируется до запуска любого теста.

ts
const test = baseTest.extend({
  perFile: [
    ({}, { use }) => use([]),
    {
      scope: 'file',
      // всегда запускать этот хук перед любым тестом
      auto: true,
    },
  ],
});

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

Однако, если вы отключите изоляцию, количество воркеров будет ограничено конфигурацией maxWorkers или poolOptions.

Обратите внимание, что указание scope: 'worker' при запуске тестов в vmThreads или vmForks будет работать так же, как scope: 'file'. Это ограничение связано с тем, что каждый тестовый файл имеет свой собственный контекст VM. Если Vitest инициализирует его один раз, один контекст может повлиять на другой, что приведет к многочисленным несоответствиям ссылок (например, экземпляры одного и того же класса будут ссылаться на разные конструкторы).

TypeScript ​

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

ts
interface MyFixtures {
  todos: number[];
  archive: number[];
}

const test = baseTest.extend<MyFixtures>({
  todos: [],
  archive: [],
});

test('types are defined correctly', ({ todos, archive }) => {
  expectTypeOf(todos).toEqualTypeOf<number[]>();
  expectTypeOf(archive).toEqualTypeOf<number[]>();
});

Выведение типов

Обратите внимание, что Vitest не поддерживает выведение типов при вызове функции use. Рекомендуется всегда передавать полный тип контекста как дженерик-тип при вызове test.extend:

ts
import { test as baseTest } from 'vitest';

const test = baseTest.extend<{
  todos: number[];
  schema: string;
}>({
  todos: ({ schema }, use) => use([]),
  schema: 'test',
});

test('types are correct', ({
  todos, // number[]
  schema, // string
}) => {
  // ...
});

beforeEach и afterEach ​

Устарело

Это устаревший метод расширения контекста, и он не будет работать, если test был расширен с помощью test.extend.

Контексты отличаются для каждого теста. Вы можете получить к ним доступ и расширить их в хуках beforeEach и afterEach.

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

beforeEach(async context => {
  // расширить контекст
  context.foo = 'bar';
});

it('should work', ({ foo }) => {
  console.log(foo); // 'bar'
});

TypeScript ​

Чтобы предоставить типы свойств для всех ваших пользовательских контекстов, вы можете расширить тип TestContext, добавив следующее:

ts
declare module 'vitest' {
  export interface TestContext {
    foo?: string;
  }
}

Если вы хотите предоставить типы свойств только для определенных хуков beforeEach, afterEach, it и test, вы можете передать тип как дженерик.

ts
interface LocalTestContext {
  foo: string;
}

beforeEach<LocalTestContext>(async context => {
  // typeof context is 'TestContext & LocalTestContext'
  context.foo = 'bar';
});

it<LocalTestContext>('should work', ({ foo }) => {
  // typeof foo is 'string'
  console.log(foo); // 'bar'
});
Pager
Предыдущая страницаТестирование в исходном коде
Следующая страницаАннотации тестов

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

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

https://vitest.dev/guide/test-context

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

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