Contesto del Test
Ispirandosi alle Playwright Fixtures, il contesto di test di Vitest permette di definire utilità, stati e fixture utilizzabili all'interno dei test.
Utilizzo
Il primo argomento di ogni callback della funzione di test è un contesto di test.
import { it } from 'vitest';
it('should work', ctx => {
// stampa il nome del test
console.log(ctx.task.name);
});
Contesto del Test Integrato
context.task
Un oggetto di sola lettura contenente metadati relativi al test.
context.expect
L'API expect
associata al test corrente:
import { it } from 'vitest';
it('math is easy', ({ expect }) => {
expect(2 + 2).toBe(4);
});
Questa API è utile per eseguire test snapshot in parallelo, poiché l'aspettativa globale non è in grado di tracciarli correttamente:
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
Salta l'esecuzione dei test successivi e contrassegna il test come saltato:
import { expect, it } from 'vitest';
it('math is hard', ({ skip }) => {
skip();
expect(2 + 2).toBe(5);
});
Estendere il Contesto del Test
Vitest offre due modi distinti per estendere il contesto di test.
test.extend
Come Playwright, puoi usare questo metodo per definire la tua API test
con fixture personalizzate e riutilizzarle ovunque.
Per esempio, creiamo prima myTest
con due fixture, todos
e archive
.
// my-test.ts
import { test } from 'vitest';
const todos = [];
const archive = [];
export const myTest = test.extend({
todos: async ({}, use) => {
// imposta la fixture prima di ogni funzione di test
todos.push(1, 2, 3);
// usa il valore della fixture
await use(todos);
// pulisci la fixture dopo ogni funzione di test
todos.length = 0;
},
archive,
});
Quindi possiamo importarlo e utilizzarlo.
import { expect } from 'vitest';
import { myTest } from './my-test.js';
myTest('add items to todos', ({ todos }) => {
expect(todos.length).toBe(3);
todos.push(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);
});
Possiamo anche aggiungere ulteriori fixture o sovrascrivere fixture esistenti estendendo myTest
.
export const myTest2 = myTest.extend({
settings: {
// ...
},
});
Inizializzazione delle Fixture
Il runner di Vitest inizializzerà le fixture in modo intelligente e le inserirà nel contesto di test in base all'utilizzo.
import { test } from 'vitest';
async function todosFn({ task }, use) {
await use([1, 2, 3]);
}
const myTest = test.extend({
todos: todosFn,
archive: [],
});
// todosFn non verrà eseguito
myTest('', () => {});
myTest('', ({ archive }) => {});
// todosFn verrà eseguito
myTest('', ({ todos }) => {});
WARNING
Quando si utilizza test.extend()
con le fixture, è consigliabile utilizzare sempre il pattern di destrutturazione degli oggetti { todos }
per accedere al contesto sia nella funzione fixture sia nella funzione test.
Fixture automatica
Vitest supporta anche la sintassi a tupla per le fixture, consentendoti di passare opzioni per ogni fixture. Ad esempio, puoi usarla per inizializzare esplicitamente una fixture, anche se non viene utilizzata nei test.
import { test as base } from 'vitest';
const test = base.extend({
fixture: [
async ({}, use) => {
// questa funzione verrà eseguita
setup();
await use();
teardown();
},
{ auto: true }, // Contrassegna come una fixture automatica
],
});
test('', () => {});
TypeScript
Per specificare i tipi per le fixture per tutti i contesti personalizzati, è possibile passare il tipo di fixture come parametro generico.
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
e afterEach
I contesti sono diversi per ogni test e possono essere acceduti ed estesi all'interno degli hook beforeEach
e afterEach
.
import { beforeEach, it } from 'vitest';
beforeEach(async context => {
// estendi il contesto
context.foo = 'bar';
});
it('should work', ({ foo }) => {
console.log(foo); // 'bar'
});
TypeScript
Per specificare i tipi delle proprietà per tutti i contesti personalizzati, è possibile estendere il tipo TestContext
aggiungendo
declare module 'vitest' {
export interface TestContext {
foo?: string;
}
}
Se si desidera specificare i tipi di proprietà solo per hook specifici beforeEach
, afterEach
, it
e test
, è possibile passare il tipo come parametro generico.
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'
});