Tesztkörnyezet
A Playwright Fixtures által inspirált Vitest tesztkörnyezet lehetővé teszi segédprogramok, állapotok és fixture-ök definiálását, amelyek a tesztekben felhasználhatók.
Használat
Minden teszt callback első argumentuma egy tesztkörnyezet.
import { it } from 'vitest';
it('should work', ({ task }) => {
// a teszt nevét jeleníti meg
console.log(task.name);
});
Beépített tesztkörnyezet
task
Egy csak olvasható objektum, amely a teszt metaadatait tartalmazza.
expect
Az expect
API az aktuális teszthez rendelve:
import { it } from 'vitest';
it('math is easy', ({ expect }) => {
expect(2 + 2).toBe(4);
});
Ez az API hasznos a snapshot tesztek párhuzamos futtatásához, mivel a globális expect
nem képes nyomon követni őket:
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
function skip(note?: string): never;
function skip(condition: boolean, note?: string): void;
Kihagyja a további tesztvégrehajtást, és kihagyottként jelöli meg a tesztet:
import { expect, it } from 'vitest';
it('math is hard', ({ skip }) => {
skip();
expect(2 + 2).toBe(5);
});
A Vitest 3.1 óta egy logikai paramétert is elfogad a teszt feltételes kihagyásához:
it('math is hard', ({ skip, mind }) => {
skip(mind === 'foggy');
expect(2 + 2).toBe(5);
});
annotate
3.2.0+
function annotate(
message: string,
attachment?: TestAttachment
): Promise<TestAnnotation>;
function annotate(
message: string,
type?: string,
attachment?: TestAttachment
): Promise<TestAnnotation>;
Hozzáad egy teszt annotációt, amelyet a riporter jelenít meg.
test('annotations API', async ({ annotate }) => {
await annotate('https://github.com/vitest-dev/vitest/pull/7953', 'issues');
});
signal
3.2.0+
Egy AbortSignal
, amelyet a Vitest megszakíthat. A jel a következő esetekben szakad meg:
- A teszt időtúllépésbe ütközik.
- A felhasználó manuálisan megszakította a teszt futtatását Ctrl+C-vel.
- A
vitest.cancelCurrentRun
programozottan meghívásra került. - Egy másik teszt párhuzamosan meghiúsult, és a
bail
jelző be van állítva.
it('stop request when test times out', async ({ signal }) => {
await fetch('/resource', { signal });
}, 2000);
onTestFailed
Az onTestFailed
hook az aktuális teszthez kötve. Ez az API hasznos, ha párhuzamosan futtat teszteket, és speciális kezelést igényel csak ehhez a konkrét teszthez.
onTestFinished
Az onTestFinished
hook az aktuális teszthez kötve. Ez az API hasznos, ha párhuzamosan futtat teszteket, és speciális kezelést igényel csak ehhez a konkrét teszthez.
Tesztkörnyezet kiterjesztése
A Vitest két különböző módot biztosít a tesztkörnyezet kiterjesztésére.
test.extend
A Playwright mintájára használhatja ezt a módszert saját test
API definiálására egyedi fixture-ökkel, és bárhol újra felhasználhatja.
Például először létrehozzuk a test
API-t két fixture-rel: todos
és archive
.
import { test as baseTest } from 'vitest';
const todos = [];
const archive = [];
export const test = baseTest.extend({
todos: async ({}, use) => {
// beállítja a fixture-t minden tesztfüggvény előtt
todos.push(1, 2, 3);
// használja a fixture értékét
await use(todos);
// megtisztítja a fixture-t minden tesztfüggvény után
todos.length = 0;
},
archive,
});
Ezután importálhatjuk és használhatjuk.
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);
});
További fixture-öket is hozzáadhatunk, vagy felülírhatjuk a meglévő fixture-öket a test
kiterjesztésével.
import { test as todosTest } from './my-test.js';
export const test = todosTest.extend({
settings: {
// ...
},
});
Fixture inicializálás
A Vitest futtató intelligensen inicializálja a fixture-öket, és befecskendezi őket a tesztkörnyezetbe a használat alapján.
import { test as baseTest } from 'vitest';
const test = baseTest.extend<{
todos: number[];
archive: number[];
}>({
todos: async ({ task }, use) => {
await use([1, 2, 3]);
},
archive: [],
});
// a todos fixture nem fog futni, mert nincs használva
test('skip', () => {});
test('skip', ({ archive }) => {});
// a todos fixture futni fog, mert használva van
test('run', ({ todos }) => {});
WARNING
Amikor test.extend()
-et használ fixture-ökkel, mindig az objektum destructuring mintát { todos }
kell használnia a kontextus eléréséhez, mind a fixture függvényben, mind a tesztfüggvényben.
test('context must be destructured', (context) => {
expect(context.todos.length).toBe(2)
})
test('context must be destructured', ({ todos }) => {
expect(todos.length).toBe(2)
})
Automatikus fixture
A Vitest támogatja a tuple szintaxist is a fixture-ök esetében, lehetővé téve, hogy opciókat adjon át minden fixture-nek. Például használhatja egy fixture explicit inicializálására, még akkor is, ha az nincs használatban a tesztekben.
import { test as base } from 'vitest';
const test = base.extend({
fixture: [
async ({}, use) => {
// ez a függvény futni fog
setup();
await use();
teardown();
},
{ auto: true }, // Automatikus fixture-ként jelöli meg
],
});
test('works correctly');
Alapértelmezett fixture
A Vitest 3 óta különböző értékeket adhat meg különböző projektekben. Ennek a funkciónak az engedélyezéséhez adja át a { injected: true }
értéket az opcióknak. Ha a kulcs nincs megadva a projekt konfigurációjában, akkor az alapértelmezett érték kerül felhasználásra.
import { test as base } from 'vitest';
const test = base.extend({
url: [
// alapértelmezett érték, ha az "url" nincs definiálva a konfigurációban
'/default',
// "injected"-ként jelöli meg a fixture-t az felülírás engedélyezéséhez
{ injected: true },
],
});
test('works correctly', ({ url }) => {
// az url "/default" a "project-new" projektben
// az url "/full" a "project-full" projektben
// az url "/empty" a "project-empty" projektben
});
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',
},
},
},
],
},
});
Értékek hatókörbe helyezése a Suite-ra 3.1.0+
A Vitest 3.1 óta felülírhatja a kontextus értékeket suite-onként és annak gyermekeinél a test.scoped
API használatával:
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 }) => {
// a `dependant` az új felülírt értéket használja, amely a suite összes tesztjére érvényes
expect(dependant).toEqual({ dependency: 'new' });
});
describe('keeps using scoped value', () => {
test('uses scoped value', ({ dependant }) => {
// a beágyazott suite örökölte az értéket
expect(dependant).toEqual({ dependency: 'new' });
});
});
});
test('keep using the default values', ({ dependant }) => {
// a `dependency` az alapértelmezett értéket használja
// a suite-on kívül, ahol a .scoped nem érvényes
expect(dependant).toEqual({ dependency: 'default' });
});
Ez az API különösen hasznos, ha egy kontextus érték egy dinamikus változótól függ, például egy adatbázis-kapcsolattól:
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' });
// ... tesztek
});
describe('another type of schema', () => {
test.scoped({ schema: 'schema-2' });
// ... tesztek
});
Hatókörönkénti kontextus 3.2.0+
Definiálhat olyan kontextust, amely fájlonként vagy workerenként egyszer inicializálódik. Ugyanúgy inicializálódik, mint egy normál fixture, objektum paraméterrel:
import { test as baseTest } from 'vitest';
export const test = baseTest.extend({
perFile: [({}, { use }) => use([]), { scope: 'file' }],
perWorker: [({}, { use }) => use([]), { scope: 'worker' }],
});
Az érték akkor inicializálódik először, amikor bármely teszt hozzáfér, kivéve, ha a fixture opciók auto: true
értéket tartalmaznak. Ebben az esetben az érték bármely teszt futtatása előtt inicializálódik.
const test = baseTest.extend({
perFile: [
({}, { use }) => use([]),
{
scope: 'file',
// mindig futtatja ezt a hookot bármely teszt előtt
auto: true,
},
],
});
A worker
hatókör workerenként egyszer futtatja a fixture-t. A futó workerek száma különböző tényezőktől függ. Alapértelmezés szerint minden fájl külön workerben fut, így a file
és worker
hatókörök ugyanúgy működnek.
Azonban, ha letiltja az izolációt, akkor a workerek száma korlátozott a maxWorkers
vagy poolOptions
konfigurációval.
Vegye figyelembe, hogy a scope: 'worker'
megadása a tesztek vmThreads
vagy vmForks
módban történő futtatásakor ugyanúgy működik, mint a scope: 'file'
. Ez a korlátozás azért létezik, mert minden tesztfájlnak saját VM kontextusa van, így ha a Vitest egyszer inicializálná, az egyik kontextus átszivároghatna a másikba, és számos referencia-inkonzisztenciát okozhatna (például ugyanazon osztály példányai különböző konstruktorokra hivatkoznának).
TypeScript
Ahhoz, hogy fixture típusokat biztosítson az összes egyéni kontextusához, átadhatja a fixture típusát generikus paraméterként.
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[]>();
});
Típus következtetés
Vegye figyelembe, hogy a Vitest nem támogatja a típusok következtetését, amikor a use
függvény meghívásra kerül. Mindig előnyösebb az egész kontextus típusát generikus típusként átadni, amikor a test.extend
meghívásra kerül:
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
és afterEach
Elavult
Ez egy elavult módszer a kontextus kiterjesztésére, és nem fog működni, ha a test
a test.extend
-del van kiterjesztve.
A kontextusok minden teszthez eltérőek. Hozzáférhet és kiterjesztheti őket a beforeEach
és afterEach
hookokon belül.
import { beforeEach, it } from 'vitest';
beforeEach(async context => {
// kontextus kiterjesztése
context.foo = 'bar';
});
it('should work', ({ foo }) => {
console.log(foo); // 'bar'
});
TypeScript
Ahhoz, hogy tulajdonságtípusokat biztosítson az összes egyéni kontextusához, kiterjesztheti a TestContext
típust a következő hozzáadásával:
declare module 'vitest' {
export interface TestContext {
foo?: string;
}
}
Ha csak bizonyos beforeEach
, afterEach
, it
és test
hookokhoz szeretne tulajdonságtípusokat biztosítani, átadhatja a típust generikus paraméterként.
interface LocalTestContext {
foo: string;
}
beforeEach<LocalTestContext>(async context => {
// a context típusa 'TestContext & LocalTestContext'
context.foo = 'bar';
});
it<LocalTestContext>('should work', ({ foo }) => {
// a foo típusa 'string'
console.log(foo); // 'bar'
});