Справочник по API тестирования
Следующие типы используются в приведенных ниже сигнатурах типов:
type Awaitable<T> = T | PromiseLike<T>;
type TestFunction = () => Awaitable<void>;
interface TestOptions {
/**
* Тест завершится с ошибкой, если его выполнение превысит установленный таймаут.
*/
timeout?: number;
/**
* Будет повторять тест указанное количество раз при неудачном выполнении.
*
* @default 0
*/
retry?: number;
/**
* Повторит тот же тест несколько раз, даже если он каждый раз завершается ошибкой.
* Если включена опция "retry" и тест завершается ошибкой, каждая попытка будет задействована в каждом цикле.
* Полезно для отладки нерегулярных сбоев.
*
* @default 0
*/
repeats?: number;
}Когда тестовая функция возвращает промис, раннер ожидает его разрешения для сбора асинхронных ожиданий. Если промис отклонен, тест завершится ошибкой.
TIP
В Jest TestFunction также может быть типа (done: DoneCallback) => void. Если используется эта форма, тест не будет завершен, пока не будет вызван done. Того же можно достичь, используя async функцию; см. раздел «Обратный вызов done» в руководстве по миграции.
Вы можете задать опции, используя цепочечный вызов свойств функции:
import { test } from 'vitest';
test.skip('пропущенный тест', () => {
// некоторая логика, которая сейчас приводит к сбою
});
test.concurrent.skip('пропущенный параллельный тест', () => {
// некоторая логика, которая сейчас приводит к сбою
});Но вы также можете предоставить объект в качестве второго аргумента:
import { test } from 'vitest';
test('пропущенный тест', { skip: true }, () => {
// некоторая логика, которая сейчас приводит к сбою
});
test('пропущенный параллельный тест', { skip: true, concurrent: true }, () => {
// некоторая логика, которая сейчас приводит к сбою
});Оба варианта работают абсолютно одинаково. Выбор одного из них — чисто стилистический.
Обратите внимание: если таймаут указан в качестве последнего аргумента, вы больше не сможете использовать опции:
import { test } from 'vitest';
// ✅ это работает
test.skip('тяжелый тест', () => {
// ...
}, 10_000);
// ❌ это не работает
test(
'тяжелый тест',
{ skip: true },
() => {
// ...
},
10_000
);Однако вы можете указать таймаут внутри объекта:
import { test } from 'vitest';
// ✅ это работает
test('тяжелый тест', { skip: true, timeout: 10_000 }, () => {
// ...
});test
- Псевдоним:
it
test определяет группу связанных ожиданий. Он принимает имя теста и функцию, содержащую проверяемые ожидания.
Опционально вы можете указать таймаут (в миллисекундах), по истечении которого тест будет завершен. По умолчанию установлено 5 секунд; это значение можно настроить глобально с помощью testTimeout.
import { expect, test } from 'vitest';
test('должен работать как ожидалось', () => {
expect(Math.sqrt(4)).toBe(2);
});test.extend
- Псевдоним:
it.extend
Используйте test.extend для расширения контекста теста пользовательскими фикстурами. Это вернет новый test, который также является расширяемым, позволяя вам добавлять новые фикстуры или переопределять существующие по мере необходимости. См. Расширение контекста теста для получения дополнительной информации.
import { expect, test } from 'vitest';
const todos = [];
const archive = [];
const myTest = test.extend({
todos: async ({ task }, use) => {
todos.push(1, 2, 3);
await use(todos);
todos.length = 0;
},
archive,
});
myTest('добавить элемент', ({ todos }) => {
expect(todos.length).toBe(3);
todos.push(4);
expect(todos.length).toBe(4);
});test.skip
- Псевдоним:
it.skip
Если вы хотите пропустить выполнение определенных тестов, но не желаете удалять их код, вы можете использовать test.skip.
import { assert, test } from 'vitest';
test.skip('пропущенный тест', () => {
// Тест пропущен, и это не вызывает ошибок
assert.equal(Math.sqrt(4), 3);
});Вы также можете пропустить тест, динамически вызвав skip в его контексте:
import { assert, test } from 'vitest';
test('пропущенный тест', context => {
context.skip();
// Тест пропущен, и это не вызывает ошибок
assert.equal(Math.sqrt(4), 3);
});Начиная с Vitest 3.1, если условие не определено, вы можете передать его методу skip в качестве первого аргумента:
import { assert, test } from 'vitest';
test('пропущенный тест', context => {
context.skip(Math.random() < 0.5, 'необязательное сообщение');
// Тест пропущен, и это не вызывает ошибок
assert.equal(Math.sqrt(4), 3);
});test.skipIf
- Псевдоним:
it.skipIf
В некоторых случаях тесты могут запускаться несколько раз в разных средах, при этом некоторые из них могут быть специфичными для конкретной среды. Вместо того чтобы оборачивать код теста в if, вы можете использовать test.skipIf для пропуска теста, если условие выполняется.
import { assert, test } from 'vitest';
const isDev = process.env.NODE_ENV === 'development';
test.skipIf(isDev)('тест, запускаемый только в продакшене', () => {
// этот тест запускается только в продакшене
});WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
test.runIf
- Псевдоним:
it.runIf
Противоположность test.skipIf.
import { assert, test } from 'vitest';
const isDev = process.env.NODE_ENV === 'development';
test.runIf(isDev)('тест, запускаемый только в разработке', () => {
// этот тест запускается только в разработке
});WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
test.only
- Псевдоним:
it.only
Используйте test.only для выполнения только определенных тестов в данном наборе. Это полезно при отладке.
Опционально вы можете указать таймаут (в миллисекундах), по истечении которого тест будет завершен. По умолчанию установлено 5 секунд; это значение можно настроить глобально с помощью testTimeout.
import { assert, test } from 'vitest';
test.only('тест', () => {
// Запускается только этот тест (и другие, помеченные `only`)
assert.equal(Math.sqrt(4), 2);
});Иногда очень полезно запускать тесты, помеченные only, в определенном файле, игнорируя все остальные тесты из всего набора, чтобы не засорять вывод.
Для этого запустите vitest с указанием конкретного файла, содержащего интересующие тесты.
# vitest interesting.test.tstest.concurrent
- Псевдоним:
it.concurrent
test.concurrent указывает на то, что последующие тесты должны выполняться параллельно. Он принимает имя теста, асинхронную функцию, содержащую тесты для выполнения, и необязательный таймаут (в миллисекундах).
import { describe, test } from 'vitest';
// Два теста, помеченные как concurrent, будут выполняться параллельно
describe('набор', () => {
test('последовательный тест', async () => {
/* ... */
});
test.concurrent('параллельный тест 1', async () => {
/* ... */
});
test.concurrent('параллельный тест 2', async () => {
/* ... */
});
});test.skip, test.only и test.todo работают с параллельными тестами. Все следующие комбинации допустимы:
test.concurrent(/* ... */);
test.skip.concurrent(/* ... */); // или test.concurrent.skip(/* ... */)
test.only.concurrent(/* ... */); // или test.concurrent.only(/* ... */)
test.todo.concurrent(/* ... */); // или test.concurrent.todo(/* ... */)При запуске параллельных тестов, снимки и утверждения должны использовать expect из локального контекста теста для корректного определения теста.
test.concurrent('тест 1', async ({ expect }) => {
expect(foo).toMatchSnapshot();
});
test.concurrent('тест 2', async ({ expect }) => {
expect(foo).toMatchSnapshot();
});WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
test.sequential
- Псевдоним:
it.sequential
test.sequential помечает тест как последовательный. Это полезно, если вы хотите запускать тесты последовательно внутри describe.concurrent или с опцией командной строки --sequence.concurrent.
import { describe, test } from 'vitest';
// с опцией конфигурации { sequence: { concurrent: true } }
test('параллельный тест 1', async () => {
/* ... */
});
test('параллельный тест 2', async () => {
/* ... */
});
test.sequential('последовательный тест 1', async () => {
/* ... */
});
test.sequential('последовательный тест 2', async () => {
/* ... */
});
// внутри параллельного набора
describe.concurrent('набор', () => {
test('параллельный тест 1', async () => {
/* ... */
});
test('параллельный тест 2', async () => {
/* ... */
});
test.sequential('последовательный тест 1', async () => {
/* ... */
});
test.sequential('последовательный тест 2', async () => {
/* ... */
});
});test.todo
- Псевдоним:
it.todo
Используйте test.todo для обозначения тестов, которые нужно реализовать позже. Запись будет отображена в отчете, чтобы вы знали, сколько тестов вам еще нужно реализовать.
// Запись будет отображена в отчете для этого теста
test.todo('нереализованный тест');test.fails
- Псевдоним:
it.fails
Используйте test.fails, чтобы явно указать, что ожидается сбой утверждения.
import { expect, test } from 'vitest';
function myAsyncFunc() {
return new Promise(resolve => resolve(1));
}
test.fails('тест с ошибкой', async () => {
await expect(myAsyncFunc()).rejects.toBe(1);
});WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
test.each
- Псевдоним:
it.each
TIP
Хотя test.each предусмотрен для совместимости с Jest, Vitest также имеет test.for с дополнительной функцией для интеграции TestContext.
Используйте test.each, когда вам нужно запустить один и тот же тест с разными переменными. Вы можете внедрять параметры с форматированием printf в имя теста, следуя порядку параметров тестовой функции.
%s: строка%d: число%i: целое число%f: число с плавающей запятой%j: json%o: объект%#: 0-индексированный номер тестового случая%$: 1-индексированный номер тестового случая%%: одиночный знак процента ('%')
import { expect, test } from 'vitest';
test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
expect(a + b).toBe(expected);
});
// это вернет
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3Вы также можете получить доступ к свойствам объекта и элементам массива, используя префикс $:
test.each([
{ a: 1, b: 1, expected: 2 },
{ a: 1, b: 2, expected: 3 },
{ a: 2, b: 1, expected: 3 },
])('add($a, $b) -> $expected', ({ a, b, expected }) => {
expect(a + b).toBe(expected);
});
// это вернет
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3
test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add($0, $1) -> $2', (a, b, expected) => {
expect(a + b).toBe(expected);
});
// это вернет
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3Вы также можете получить доступ к атрибутам объекта с помощью ., если объекты используются в качестве аргументов:
test.each`
a | b | expected
${{ val: 1 }} | ${'b'} | ${'1b'}
${{ val: 2 }} | ${'b'} | ${'2b'}
${{ val: 3 }} | ${'b'} | ${'3b'}
`('add($a.val, $b) -> $expected', ({ a, b, expected }) => {
expect(a.val + b).toBe(expected);
});
// это вернет
// ✓ add(1, b) -> 1b
// ✓ add(2, b) -> 2b
// ✓ add(3, b) -> 3bНачиная с Vitest 0.25.3, вы также можете использовать табличные шаблонные строки.
- Первая строка должна содержать имена столбцов, разделенные символом
|; - Одна или несколько последующих строк данных предоставляются в виде выражений шаблонных литералов с использованием синтаксиса
${value}.
import { expect, test } from 'vitest';
test.each`
a | b | expected
${1} | ${1} | ${2}
${'a'} | ${'b'} | ${'ab'}
${[]} | ${'b'} | ${'b'}
${{}} | ${'b'} | ${'[object Object]b'}
${{ asd: 1 }} | ${'b'} | ${'[object Object]b'}
`('возвращает $expected, когда $a добавляется $b', ({ a, b, expected }) => {
expect(a + b).toBe(expected);
});TIP
Vitest обрабатывает $values методом Chai format. Если значение слишком сильно сокращено, вы можете увеличить chaiConfig.truncateThreshold в вашем файле конфигурации.
WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
test.for
- Псевдоним:
it.for
Альтернатива test.each для предоставления TestContext.
Различие с test.each заключается в способе предоставления массивов в аргументах. Аргументы, не являющиеся массивами, для test.for (включая использование шаблонных строк) работают точно так же, как для test.each.
// `each` разворачивает массивы
test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
expect(a + b).toBe(expected);
});
// `for` не разворачивает массивы (обратите внимание на квадратные скобки вокруг аргументов)
test.for([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', ([a, b, expected]) => {
expect(a + b).toBe(expected);
});Второй аргумент — это TestContext и может использоваться для параллельных снимков, например:
test.concurrent.for([
[1, 1],
[1, 2],
[2, 1],
])('add(%i, %i)', ([a, b], { expect }) => {
expect(a + b).matchSnapshot();
});bench
- Тип:
(name: string | Function, fn: BenchFunction, options?: BenchOptions) => void
bench определяет бенчмарк. В контексте Vitest, бенчмарк — это функция, которая определяет серию операций. Vitest запускает эту функцию несколько раз для отображения различных результатов производительности.
Vitest использует библиотеку tinybench в своей основе, наследуя все ее опции, которые могут быть использованы в качестве третьего аргумента.
import { bench } from 'vitest';
bench(
'обычная сортировка',
() => {
const x = [1, 5, 4, 2, 3];
x.sort((a, b) => {
return a - b;
});
},
{ time: 1000 }
);export interface Options {
/**
* время выполнения задачи бенчмарка (миллисекунды)
* @default 500
*/
time?: number;
/**
* количество раз, которое задача должна быть выполнена, независимо от истечения опции time
* @default 10
*/
iterations?: number;
/**
* функция для получения текущей временной метки в миллисекундах
*/
now?: () => number;
/**
* AbortSignal для прерывания бенчмарка
*/
signal?: AbortSignal;
/**
* Выбрасывать исключение, если задача завершается ошибкой (события не будут работать, если это значение true)
*/
throws?: boolean;
/**
* время прогрева (миллисекунды)
* @default 100ms
*/
warmupTime?: number;
/**
* итерации прогрева
* @default 5
*/
warmupIterations?: number;
/**
* функция настройки, запускаемая перед каждой задачей бенчмарка (циклом)
*/
setup?: Hook;
/**
* функция очистки, запускаемая после каждой задачи бенчмарка (цикла)
*/
teardown?: Hook;
}После выполнения бенчмарка информация о структуре вывода выглядит следующим образом:
name hz min max mean p75 p99 p995 p999 rme samples
· обычная сортировка 6,526,368.12 0.0001 0.3638 0.0002 0.0002 0.0002 0.0002 0.0004 ±1.41% 652638export interface TaskResult {
/*
* последняя ошибка, возникшая во время выполнения задачи
*/
error?: unknown;
/**
* Время выполнения задачи бенчмарка (цикла) в миллисекундах.
*/
totalTime: number;
/**
* минимальное значение в выборках
*/
min: number;
/**
* максимальное значение в выборках
*/
max: number;
/**
* количество операций в секунду
*/
hz: number;
/**
* сколько времени занимает каждая операция (мс)
*/
period: number;
/**
* выборки времени каждой итерации задачи (мс)
*/
samples: number[];
/**
* среднее значение выборок (оценка среднего значения генеральной совокупности)
*/
mean: number;
/**
* дисперсия выборок (оценка дисперсии генеральной совокупности)
*/
variance: number;
/**
* стандартное отклонение выборок (оценка стандартного отклонения генеральной совокупности)
*/
sd: number;
/**
* стандартная ошибка среднего (также известная как стандартное отклонение выборочного распределения среднего значения выборки)
*/
sem: number;
/**
* степени свободы
*/
df: number;
/**
* критическое значение выборки
*/
critical: number;
/**
* погрешность
*/
moe: number;
/**
* относительная погрешность
*/
rme: number;
/**
* медианное абсолютное отклонение
*/
mad: number;
/**
* 50-й/медианный перцентиль
*/
p50: number;
/**
* 75-й перцентиль
*/
p75: number;
/**
* 99-й перцентиль
*/
p99: number;
/**
* 995-й перцентиль
*/
p995: number;
/**
* 999-й перцентиль
*/
p999: number;
}bench.skip
- Тип:
(name: string | Function, fn: BenchFunction, options?: BenchOptions) => void
Вы можете использовать синтаксис bench.skip для пропуска выполнения определенных бенчмарков.
import { bench } from 'vitest';
bench.skip('обычная сортировка', () => {
const x = [1, 5, 4, 2, 3];
x.sort((a, b) => {
return a - b;
});
});bench.only
- Тип:
(name: string | Function, fn: BenchFunction, options?: BenchOptions) => void
Используйте bench.only для запуска только определенных бенчмарков в данном наборе. Это полезно при отладке.
import { bench } from 'vitest';
bench.only('обычная сортировка', () => {
const x = [1, 5, 4, 2, 3];
x.sort((a, b) => {
return a - b;
});
});bench.todo
- Тип:
(name: string | Function) => void
Используйте bench.todo для заглушки бенчмарков, которые будут реализованы позже.
import { bench } from 'vitest';
bench.todo('нереализованный тест');describe
Когда вы используете test или bench на верхнем уровне файла, они автоматически включаются в неявный набор. Используя describe, вы можете определить новый набор в текущем контексте, который будет содержать связанные тесты, бенчмарки и другие вложенные наборы. Набор позволяет организовать тесты и бенчмарки для получения более понятных отчетов.
// basic.spec.ts
// организация тестов
import { describe, expect, test } from 'vitest';
const person = {
isActive: true,
age: 32,
};
describe('человек', () => {
test('человек определён', () => {
expect(person).toBeDefined();
});
test('активен', () => {
expect(person.isActive).toBeTruthy();
});
test('ограничение по возрасту', () => {
expect(person.age).toBeLessThanOrEqual(32);
});
});// basic.bench.ts
// организация бенчмарков
import { bench, describe } from 'vitest';
describe('сортировка', () => {
bench('обычная', () => {
const x = [1, 5, 4, 2, 3];
x.sort((a, b) => {
return a - b;
});
});
bench('обратная сортировка', () => {
const x = [1, 5, 4, 2, 3];
x.reverse().sort((a, b) => {
return a - b;
});
});
});Вы также можете вкладывать блоки describe, если у вас есть иерархия тестов или бенчмарков:
import { describe, expect, test } from 'vitest';
function numberToCurrency(value: number | string) {
if (typeof value !== 'number') {
throw new TypeError('Значение должно быть числом');
}
return value
.toFixed(2)
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
describe('numberToCurrency', () => {
describe('при недопустимом значении числа', () => {
test('состоящем из нечисловых символов, должно вызывать ошибку', () => {
expect(() => numberToCurrency('abc')).toThrowError();
});
});
describe('при допустимом значении числа', () => {
test('возвращает правильный формат валюты', () => {
expect(numberToCurrency(10000)).toBe('10,000.00');
});
});
});describe.skip
- Псевдоним:
suite.skip
Используйте describe.skip для пропуска выполнения определенного блока describe.
import { assert, describe, test } from 'vitest';
describe.skip('пропущенный набор', () => {
test('sqrt', () => {
// Набор пропущен, ошибок нет
assert.equal(Math.sqrt(4), 3);
});
});describe.skipIf
- Псевдоним:
suite.skipIf
В некоторых случаях вы можете запускать наборы несколько раз с разными средами, и некоторые из наборов могут быть специфичными для среды. Вместо того чтобы оборачивать набор в if, вы можете использовать describe.skipIf, чтобы пропустить набор, если условие истинно.
import { describe, test } from 'vitest';
const isDev = process.env.NODE_ENV === 'development';
describe.skipIf(isDev)('набор тестов, запускаемый только в продакшене', () => {
// этот набор тестов запускается только в продакшене
});WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
describe.runIf
- Псевдоним:
suite.runIf
Противоположность describe.skipIf.
import { assert, describe, test } from 'vitest';
const isDev = process.env.NODE_ENV === 'development';
describe.runIf(isDev)('набор тестов, запускаемый только в разработке', () => {
// этот набор тестов запускается только в разработке
});WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
describe.only
- Тип:
(name: string | Function, fn: TestFunction, options?: number | TestOptions) => void
Используйте describe.only для запуска только определенных наборов.
import { assert, describe, test } from 'vitest';
// Запускается только этот набор (и другие, помеченные `only`)
describe.only('набор', () => {
test('sqrt', () => {
assert.equal(Math.sqrt(4), 3);
});
});
describe('другой набор', () => {
// ... будет пропущен
});Иногда очень полезно запускать тесты, помеченные only, в определенном файле, игнорируя все остальные тесты из всего набора, чтобы не засорять вывод.
Для этого запустите vitest с указанием конкретного файла, содержащего интересующие тесты.
# vitest interesting.test.tsdescribe.concurrent
- Псевдоним:
suite.concurrent
describe.concurrent запускает все вложенные наборы и тесты параллельно.
import { describe, test } from 'vitest';
// Все наборы и тесты в этом наборе будут выполняться параллельно
describe.concurrent('набор', () => {
test('параллельный тест 1', async () => {
/* ... */
});
describe('параллельный набор 2', async () => {
test('параллельный внутренний тест 1', async () => {
/* ... */
});
test('параллельный внутренний тест 2', async () => {
/* ... */
});
});
test.concurrent('параллельный тест 3', async () => {
/* ... */
});
});.skip, .only и .todo работают с параллельными наборами. Все следующие комбинации допустимы:
describe.concurrent(/* ... */);
describe.skip.concurrent(/* ... */); // или describe.concurrent.skip(/* ... */)
describe.only.concurrent(/* ... */); // или describe.concurrent.only(/* ... */)
describe.todo.concurrent(/* ... */); // или describe.concurrent.todo(/* ... */)При запуске параллельных тестов, снимки и утверждения должны использовать expect из локального контекста теста, чтобы убедиться, что обнаружен правильный тест.
describe.concurrent('набор', () => {
test('параллельный тест 1', async ({ expect }) => {
expect(foo).toMatchSnapshot();
});
test('параллельный тест 2', async ({ expect }) => {
expect(foo).toMatchSnapshot();
});
});WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
describe.sequential
- Псевдоним:
suite.sequential
describe.sequential помечает каждый тест в наборе как последовательный. Это полезно, если вы хотите запускать тесты последовательно внутри describe.concurrent или с опцией командной строки --sequence.concurrent.
import { describe, test } from 'vitest';
describe.concurrent('suite', () => {
test('параллельный тест 1', async () => {
/* ... */
});
test('параллельный тест 2', async () => {
/* ... */
});
describe.sequential('', () => {
test('последовательный тест 1', async () => {
/* ... */
});
test('последовательный тест 2', async () => {
/* ... */
});
});
});describe.shuffle
- Псевдоним:
suite.shuffle
Vitest позволяет запускать все тесты в случайном порядке с помощью флага CLI --sequence.shuffle или опции конфигурации sequence.shuffle. Однако, если вы хотите, чтобы только часть вашего тестового набора запускала тесты в случайном порядке, вы можете пометить ее этим флагом.
import { describe, test } from 'vitest';
// или describe('набор', { shuffle: true }, ...)
describe.shuffle('набор', () => {
test('случайный тест 1', async () => {
/* ... */
});
test('случайный тест 2', async () => {
/* ... */
});
test('случайный тест 3', async () => {
/* ... */
});
// `shuffle` является наследуемым
describe('все еще случайный', () => {
test('случайный 4.1', async () => {
/* ... */
});
test('случайный 4.2', async () => {
/* ... */
});
});
// отключить перемешивание для вложенных тестов
describe('не случайный', { shuffle: false }, () => {
test('по порядку 5.1', async () => {
/* ... */
});
test('по порядку 5.2', async () => {
/* ... */
});
});
});
// порядок зависит от опции sequence.seed в конфигурации (по умолчанию используется Date.now()).skip, .only и .todo работают со случайными наборами.
WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
describe.todo
- Псевдоним:
suite.todo
Используйте describe.todo для заглушки наборов, которые будут реализованы позже. Запись будет отображена в отчете, чтобы вы знали, сколько тестов вам еще нужно реализовать.
// Запись будет отображена в отчете для этого набора
describe.todo('нереализованный набор');describe.each
- Псевдоним:
suite.each
TIP
Хотя describe.each предусмотрен для совместимости с Jest, Vitest также имеет describe.for, который упрощает типы аргументов и соответствует test.for.
Используйте describe.each, если у вас есть более одного теста, зависящего от одних и тех же данных.
import { describe, expect, test } from 'vitest';
describe.each([
{ a: 1, b: 1, expected: 2 },
{ a: 1, b: 2, expected: 3 },
{ a: 2, b: 1, expected: 3 },
])('описание объекта: add($a, $b)', ({ a, b, expected }) => {
test(`возвращает ${expected}`, () => {
expect(a + b).toBe(expected);
});
test(`возвращенное значение не должно превышать ${expected}`, () => {
expect(a + b).not.toBeGreaterThan(expected);
});
test(`возвращенное значение не должно быть меньше ${expected}`, () => {
expect(a + b).not.toBeLessThan(expected);
});
});Начиная с Vitest 0.25.3, вы также можете использовать табличные шаблонные строки.
- Первая строка должна содержать имена столбцов, разделенные символом
|; - Одна или несколько последующих строк данных предоставляются в виде выражений шаблонных литералов с использованием синтаксиса
${value}.
import { describe, expect, test } from 'vitest';
describe.each`
a | b | expected
${1} | ${1} | ${2}
${'a'} | ${'b'} | ${'ab'}
${[]} | ${'b'} | ${'b'}
${{}} | ${'b'} | ${'[object Object]b'}
${{ asd: 1 }} | ${'b'} | ${'[object Object]b'}
`('описание шаблонной строки: add($a, $b)', ({ a, b, expected }) => {
test(`возвращает ${expected}`, () => {
expect(a + b).toBe(expected);
});
});WARNING
Вы не можете использовать этот синтаксис при использовании Vitest в качестве проверки типов.
describe.for
- Псевдоним:
suite.for
Различие с describe.each заключается в способе предоставления массива в аргументах. Другие аргументы, не являющиеся массивами (включая использование шаблонных строк), работают точно так же.
// `each` разворачивает массив
describe.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
test('тест', () => {
expect(a + b).toBe(expected);
});
});
// `for` не разворачивает массив
describe.for([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', ([a, b, expected]) => {
test('тест', () => {
expect(a + b).toBe(expected);
});
});Настройка и очистка
Эти функции позволяют вам взаимодействовать с жизненным циклом тестов, чтобы избежать повторения кода настройки и очистки. Они применяются к текущему контексту: к файлу, если используются на верхнем уровне, или к текущему набору, если находятся внутри блока describe. Эти хуки не вызываются, когда Vitest используется в качестве средства проверки типов.
beforeEach
- Тип:
beforeEach(fn: () => Awaitable<void>, timeout?: number)
Регистрирует колбэк, вызываемый перед каждым тестом в текущем контексте. Если функция возвращает промис, Vitest ожидает его разрешения, прежде чем запускать тест.
Опционально вы можете передать таймаут (в миллисекундах), определяющий, сколько времени ждать до завершения. По умолчанию 5 секунд.
import { beforeEach } from 'vitest';
beforeEach(async () => {
// Очистить моки и добавить тестовые данные перед каждым запуском теста
await stopMocking();
await addUser({ name: 'John' });
});Здесь beforeEach гарантирует добавление пользователя для каждого теста.
beforeEach также принимает необязательную функцию очистки (эквивалентную afterEach).
import { beforeEach } from 'vitest';
beforeEach(async () => {
// вызывается перед каждым запуском теста
await prepareSomething();
// функция очистки, вызываемая после каждого запуска теста
return async () => {
await resetSomething();
};
});afterEach
- Тип:
afterEach(fn: () => Awaitable<void>, timeout?: number)
Регистрирует колбэк, вызываемый после завершения каждого теста в текущем контексте. Если функция возвращает промис, Vitest ожидает его разрешения, прежде чем продолжить.
Опционально вы можете указать таймаут (в миллисекундах), определяющий, сколько времени ждать до завершения. По умолчанию 5 секунд.
import { afterEach } from 'vitest';
afterEach(async () => {
await clearTestingData(); // очистить тестовые данные после каждого теста
});Здесь afterEach гарантирует очистку тестовых данных после каждого запуска теста.
TIP
Vitest 1.3.0 добавил хук onTestFinished. Вы можете вызвать его во время выполнения теста для очистки состояния после завершения теста.
beforeAll
- Тип:
beforeAll(fn: () => Awaitable<void>, timeout?: number)
Регистрирует колбэк, вызываемый один раз перед началом выполнения всех тестов в текущем контексте. Если функция возвращает промис, Vitest ожидает его разрешения, прежде чем запускать тесты.
Опционально вы можете указать таймаут (в миллисекундах), определяющий, сколько времени ждать до завершения. По умолчанию 5 секунд.
import { beforeAll } from 'vitest';
beforeAll(async () => {
await startMocking(); // вызывается перед всеми тестами
});Здесь beforeAll гарантирует настройку мок-данных перед запуском тестов.
beforeAll также принимает необязательную функцию очистки (эквивалентную afterAll).
import { beforeAll } from 'vitest';
beforeAll(async () => {
// вызывается перед всеми тестами
await startMocking();
// функция очистки, вызываемая после всех тестов
return async () => {
await stopMocking();
};
});afterAll
- Тип:
afterAll(fn: () => Awaitable<void>, timeout?: number)
Регистрирует колбэк, вызываемый один раз после выполнения всех тестов в текущем контексте. Если функция возвращает промис, Vitest ожидает его разрешения, прежде чем продолжить.
Опционально вы можете указать таймаут (в миллисекундах), определяющий, сколько времени ждать до завершения. По умолчанию 5 секунд.
import { afterAll } from 'vitest';
afterAll(async () => {
await stopMocking(); // этот метод вызывается после всех тестов
});Здесь afterAll гарантирует вызов метода stopMocking после выполнения всех тестов.
Хуки тестирования
Vitest предоставляет несколько хуков, которые вы можете вызвать во время выполнения теста для очистки состояния после его завершения.
WARNING
Эти хуки вызовут ошибку, если они будут вызваны вне тела теста.
onTestFinished
Этот хук всегда вызывается после завершения теста. Он вызывается после хуков afterEach, поскольку они могут влиять на результат теста. Он получает объект ExtendedContext, аналогично beforeEach и afterEach.
import { onTestFinished, test } from 'vitest';
test('выполняет запрос', () => {
const db = connectDb();
onTestFinished(() => db.close());
db.query('SELECT * FROM users');
});WARNING
Если вы запускаете тесты параллельно, всегда используйте хук onTestFinished из контекста теста, поскольку Vitest не отслеживает параллельные тесты в глобальных хуках:
import { test } from 'vitest';
test.concurrent('выполняет запрос', ({ onTestFinished }) => {
const db = connectDb();
onTestFinished(() => db.close());
db.query('SELECT * FROM users');
});Этот хук особенно полезен при создании переиспользуемой логики:
// это может быть в отдельном файле
function getTestDb() {
const db = connectMockedDb();
onTestFinished(() => db.close());
return db;
}
test('выполняет запрос пользователя', async () => {
const db = getTestDb();
expect(await db.query('SELECT * from users').perform()).toEqual([]);
});
test('выполняет запрос организации', async () => {
const db = getTestDb();
expect(await db.query('SELECT * from organizations').perform()).toEqual([]);
});TIP
Этот хук всегда вызывается в обратном порядке и не зависит от опции sequence.hooks.
onTestFailed
Этот хук вызывается только после сбоя теста. Он вызывается после хуков afterEach, поскольку они могут влиять на результат теста. Он получает объект ExtendedContext, аналогично beforeEach и afterEach. Этот хук полезен при отладке.
import { onTestFailed, test } from 'vitest';
test('выполняет запрос', () => {
const db = connectDb();
onTestFailed(({ task }) => {
console.log(task.result.errors);
});
db.query('SELECT * FROM users');
});WARNING
Если вы запускаете тесты параллельно, всегда используйте хук onTestFailed из контекста теста, поскольку Vitest не отслеживает параллельные тесты в глобальных хуках:
import { test } from 'vitest';
test.concurrent('performs a query', ({ onTestFailed }) => {
const db = connectDb();
onTestFailed(({ task }) => {
console.log(task.result.errors);
});
db.query('SELECT * FROM users');
});