Контекст теста
Контекст теста Vitest, вдохновленный Playwright Fixtures, позволяет определять утилиты, состояния и фикстуры, используемые в тестах.
Использование
Контекст теста передается первым аргументом в каждый обработчик теста.
import { it } from 'vitest';
it('should work', ctx => {
// выводит имя теста
console.log(ctx.task.name);
});
Встроенный контекст теста
context.task
Объект только для чтения, содержащий метаданные текущего теста.
context.expect
API expect
, привязанный к текущему тесту:
import { it } from 'vitest';
it('math is easy', ({ expect }) => {
expect(2 + 2).toBe(4);
});
Этот API полезен при параллельном запуске snapshot-тестов, поскольку глобальный expect
не может корректно отслеживать их:
import { it } from 'vitest';
it.concurrent('math is easy', ({ expect }) => {
expect(2 + 2).toMatchInlineSnapshot();
});
it.concurrent('math is hard', ({ expect }) => {
expect(2 * 2).toMatchInlineSnapshot();
});
context.skip
Пропускает выполнение текущего теста и помечает его как пропущенный (skipped):
import { expect, it } from 'vitest';
it('math is hard', ({ skip }) => {
skip();
expect(2 + 2).toBe(5);
});
Расширение контекста теста
Vitest предоставляет два способа расширения контекста теста.
test.extend
WARNING
Этот API доступен начиная с Vitest 0.32.3.
Как и в Playwright, вы можете использовать этот метод для определения собственного API test
с пользовательскими фикстурами и повторно использовать его в любом месте.
Например, создадим myTest
с двумя фикстурами: todos
и archive
.
// my-test.ts
import { test } from 'vitest';
const todos = [];
const archive = [];
export const myTest = test.extend({
todos: async ({ task }, use) => {
// настройка фикстуры перед каждым тестом
todos.push(1, 2, 3);
// использование значения фикстуры
await use(todos);
// очистка фикстуры после каждого теста
todos.length = 0;
},
archive,
});
Затем мы можем импортировать и использовать его.
import { expect } from 'vitest';
import { myTest } from './my-test.ts';
myTest('add items to todos', ({ todos }) => {
expect(todos.length).toBe(3);
todos.add(4);
expect(todos.length).toBe(4);
});
myTest('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);
});
Мы также можем добавить больше фикстур или переопределить существующие, расширив myTest
.
export const myTest2 = myTest.extend({
settings: {
// ...
},
});
Инициализация фикстур
Vitest автоматически инициализирует фикстуры и внедряет их в контекст теста, основываясь на их использовании.
import { test } from 'vitest';
async function todosFn({ task }, use) {
await use([1, 2, 3]);
}
const myTest = test.extend({
todos: todosFn,
archive: [],
});
// todosFn не будет запущена
myTest('', () => {});
myTest('', ({ archive }) => {});
// todosFn будет запущена
myTest('', ({ todos }) => {});
WARNING
При использовании test.extend()
с фикстурами рекомендуется использовать деструктуризацию { todos }
для доступа к контексту как в функции фикстуры, так и в функции теста.
TypeScript
Чтобы предоставить типы для ваших пользовательских фикстур, вы можете передать generic-тип в качестве аргумента.
interface MyFixtures {
todos: number[];
archive: number[];
}
const myTest = test.extend<MyFixtures>({
todos: [],
archive: [],
});
myTest('', context => {
expectTypeOf(context.todos).toEqualTypeOf<number[]>();
expectTypeOf(context.archive).toEqualTypeOf<number[]>();
});
beforeEach
и afterEach
Контексты различны для каждого теста. Вы можете получить доступ к ним и расширить их в хуках beforeEach
и afterEach
.
import { beforeEach, it } from 'vitest';
beforeEach(async context => {
// расширение контекста
context.foo = 'bar';
});
it('should work', ({ foo }) => {
console.log(foo); // 'bar'
});
TypeScript
Чтобы определить типы свойств для всех ваших пользовательских контекстов, вы можете расширить тип TestContext
, добавив следующее объявление:
declare module 'vitest' {
export interface TestContext {
foo?: string;
}
}
Если вы хотите предоставить типы свойств только для определенных хуков beforeEach
, afterEach
, it
и test
, вы можете передать тип в качестве generic-аргумента.
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'
});