Vi
A Vitest a vi
segédfüggvényen keresztül biztosít segédprogramokat. Ezt globálisan is elérheti (ha a globals konfiguráció engedélyezve van), vagy közvetlenül importálhatja a vitest
csomagból:
import { vi } from 'vitest';
Modulok Mockolása
Ez a szakasz az API-t írja le, amelyet modulok mockolásakor használhat. Fontos megjegyezni, hogy a Vitest nem támogatja a require()
-ral importált modulok mockolását.
vi.mock
- Típus:
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Típus:
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
Az összes importált modult a megadott path
útvonalról egy másik modullal helyettesíti. A konfigurált Vite aliasokat használhatja az útvonalon belül. A vi.mock
hívás emelt (hoisted), így nem számít, hogy hol hívja meg. Mindig az összes importálás előtt hajtódik végre. Ha a hatókörén kívüli változókra szeretne hivatkozni, azokat a vi.hoisted
belsejében definiálhatja, és hivatkozhat rájuk a vi.mock
belsejében.
WARNING
A vi.mock
csak az import
kulcsszóval importált modulok esetén működik. A require
esetén nem működik.
A vi.mock
emeléséhez a Vitest statikusan elemzi a fájlokat. Ezért a vi
nem használható, ha nem közvetlenül a vitest
csomagból (például valamilyen segédprogram fájlból) importálták. Használja a vi.mock
függvényt a vitest
csomagból importált vi
segítségével, vagy engedélyezze a globals
konfigurációs opciót.
A Vitest nem fogja mockolni azokat a modulokat, amelyeket egy setup fájlban importáltak, mert azok már gyorsítótárazva vannak a tesztfájl futásakor. Hívhatja a vi.resetModules()
függvényt a vi.hoisted
belsejében, hogy törölje az összes modul gyorsítótárát a tesztfájl futtatása előtt.
Ha a factory
függvény definiálva van, az összes importálás annak eredményét adja vissza. A Vitest csak egyszer hívja meg a factory-t, és gyorsítótárazza az eredményeket az összes további importáláshoz, amíg a vi.unmock
vagy a vi.doUnmock
meg nem hívódik.
A jest
-től eltérően a factory aszinkron is lehet. Használhatja a vi.importActual
függvényt, vagy egy segédprogramot, amelynek első argumentumaként a factory-t adja át, és így hozzáférhet az eredeti modulhoz.
A factory függvény helyett megadhat egy objektumot is, amelynek van egy spy
tulajdonsága. Ha a spy
értéke true
, akkor a Vitest a szokásos módon automatikusan mockolja a modult, de nem írja felül az exportok implementációját. Ez akkor hasznos, ha csak azt szeretné ellenőrizni, hogy az exportált metódust egy másik metódus helyesen hívta-e meg.
import { calculator } from './src/calculator.ts';
vi.mock('./src/calculator.ts', { spy: true });
// meghívja az eredeti implementációt,
// de lehetővé teszi a viselkedés későbbi ellenőrzését
const result = calculator(1, 2);
expect(result).toBe(3);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);
A Vitest támogatja a modul promise-t is a vi.mock
és vi.doMock
metódusokban string helyett a jobb IDE támogatás érdekében. Amikor a fájl áthelyezésre kerül, az útvonal frissül, és az importOriginal
automatikusan örökli a típust. Ennek a szignatúrának a használata azt is biztosítja, hogy a factory visszatérési típusa kompatibilis legyen az eredeti modullal (az exportok opcionálisak maradnak).
// @filename: ./path/to/module.js
export declare function total(...numbers: number[]): number;
// @filename: test.js
import { vi } from 'vitest';
// ---cut---
vi.mock(import('./path/to/module.js'), async importOriginal => {
const mod = await importOriginal(); // a típus kikövetkeztetett
// ^?
return {
...mod,
// néhány export felülírása
total: vi.fn(),
};
});
A háttérben a Vitest továbbra is stringgel, nem pedig modulobjektummal dolgozik.
Ha azonban TypeScriptet használ a tsconfig.json
fájlban konfigurált paths
aliasokkal, a fordító nem fogja tudni helyesen feloldani az import típusokat. Ahhoz, hogy ez működjön, győződjön meg róla, hogy az összes aliased importot lecseréli a megfelelő relatív útvonalakra. Pl. használja az import('./path/to/module.js')
helyett az import('@/module')
kifejezést.
WARNING
A vi.mock
emelt (más szóval, áthelyezett) a fájl tetejére. Ez azt jelenti, hogy bárhol is írja (legyen az beforeEach
vagy test
belsejében), az valójában előbb hajtódik végre.
Ez azt is jelenti, hogy a factory belsejében nem használhat olyan változókat, amelyek a factoryn kívül vannak definiálva.
Ha változókat szeretne használni a factory belsejében, próbálja meg a vi.doMock
függvényt. Ugyanúgy működik, de nem emelt. Fontos megjegyezni, hogy csak a későbbi importokat mockolja.
Hivatkozhat a vi.hoisted
metódussal definiált változókra is, ha az a vi.mock
előtt lett deklarálva:
import { namedExport } from './path/to/module.js';
const mocks = vi.hoisted(() => {
return {
namedExport: vi.fn(),
};
});
vi.mock('./path/to/module.js', () => {
return {
namedExport: mocks.namedExport,
};
});
vi.mocked(namedExport).mockReturnValue(100);
expect(namedExport()).toBe(100);
expect(namedExport).toBe(mocks.namedExport);
WARNING
Ha egy modult alapértelmezett exporttal mockol, akkor a visszaadott factory függvény objektumon belül meg kell adnia egy default
kulcsot. Ez egy ES modul-specifikus sajátosság; ezért a jest
dokumentációja eltérhet, mivel a jest
CommonJS modulokat használ. Például:
vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
// stb...
};
});
Ha van egy __mocks__
mappa a mockolt fájl mellett, és a factory nincs megadva, a Vitest megpróbálja megtalálni a __mocks__
almappában az azonos nevű fájlt, és azt használja tényleges modulként. Ha egy függőséget mockol, a Vitest megpróbálja megtalálni a __mocks__
mappát a projekt gyökerében (alapértelmezés szerint process.cwd()
). A Vitestnek megadhatja, hol találhatók a függőségek a deps.moduleDirectories
konfigurációs opcióval.
Például, van ez a fájlstruktúra:
- __mocks__
- axios.js
- src
__mocks__
- increment.js
- increment.js
- tests
- increment.test.js
Ha a vi.mock
függvényt egy tesztfájlban factory vagy opciók nélkül hívja meg, akkor a __mocks__
mappában keres egy fájlt, amelyet modulként használhat:
import { vi } from 'vitest';
// az axios egy alapértelmezett export a `__mocks__/axios.js` fájlból
import axios from 'axios';
// az increment egy elnevezett export a `src/__mocks__/increment.js` fájlból
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
Ne feledje, hogy ha nem hívja meg a vi.mock
függvényt, a modulok nem lesznek automatikusan mockolva. A Jest automocking viselkedésének utánzásához meghívhatja a vi.mock
függvényt minden szükséges modulhoz a setupFiles
belsejében.
Ha nincs __mocks__
mappa vagy megadott factory, a Vitest importálja az eredeti modult, és automatikusan mockolja az összes exportját. Az alkalmazott szabályokat lásd az algoritmus részben.
vi.doMock
- Típus:
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Típus:
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
Ugyanaz, mint a vi.mock
, de nem emelkedik fel a fájl tetejére, így hivatkozhat a globális fájlhatókörben lévő változókra. A modul következő dinamikus importálása mockolt lesz.
WARNING
Ez nem fogja mockolni azokat a modulokat, amelyeket ezen hívás előtt importáltak. Fontos megjegyezni, hogy az ESM-ben az összes statikus import mindig emelt, így ennek a statikus import elé helyezése nem fogja biztosítani, hogy az import előtt hívják meg:
vi.doMock('./increment.js'); // ez az import utasítás _után_ fog meghívódni
import { increment } from './increment.js';
export function increment(number) {
return number + 1;
}
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';
// a modul nincs mockolva, mert a vi.doMock még nincs meghívva
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// hozzáférhet a változókhoz a factory belsejében
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('a következő modul importálása a mockoltat importálja', async () => {
// az eredeti import NEM VOLT MOCKOLVA, mert a vi.doMock az importok UTÁN értékelődik ki
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// az új dinamikus import mockolt modult ad vissza
expect(mockedIncrement(1)).toBe(101);
expect(mockedIncrement(1)).toBe(102);
expect(mockedIncrement(1)).toBe(103);
});
vi.mocked
- Típus:
<T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>
- Típus:
<T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>
Típussegéd a TypeScript számára. Az átadott objektumot adja vissza.
Ha a partial
értéke true
, akkor Partial<T>
-t vár visszatérési értékként. Alapértelmezés szerint ez csak azt jelzi a TypeScriptnek, hogy az első szintű értékek mockolva vannak. Átadhatja a { deep: true }
értéket második argumentumként, hogy elmondja a TypeScriptnek, hogy az egész objektum mockolva van, ha az valóban az.
export function add(x: number, y: number): number {
return x + y;
}
export function fetchSomething(): Promise<Response> {
return fetch('https://vitest.dev/');
}
import * as example from './example';
vi.mock('./example');
test('1 + 1 egyenlő 10-zel', async () => {
vi.mocked(example.add).mockReturnValue(10);
expect(example.add(1, 1)).toBe(10);
});
test('mock visszatérési érték csak részben helyes típusozással', async () => {
vi.mocked(example.fetchSomething).mockResolvedValue(new Response('hello'));
vi.mocked(example.fetchSomething, { partial: true }).mockResolvedValue({
ok: false,
});
// vi.mocked(example.someFn).mockResolvedValue({ ok: false }) // ez típus hiba
});
vi.importActual
- Típus:
<T>(path: string) => Promise<T>
Modult importál, megkerülve az összes ellenőrzést, hogy mockolni szükséges-e. Hasznos lehet, ha részlegesen szeretné mockolni a modult.
vi.mock('./example.js', async () => {
const originalModule = await vi.importActual('./example.js');
return { ...originalModule, get: vi.fn() };
});
vi.importMock
- Típus:
<T>(path: string) => Promise<MaybeMockedDeep<T>>
Egy modult importál az összes tulajdonságával (beleértve a beágyazott tulajdonságokat is) mockolva. Ugyanazokat a szabályokat követi, mint a vi.mock
. Az alkalmazott szabályokat lásd az algoritmus részben.
vi.unmock
- Típus:
(path: string | Promise<Module>) => void
Eltávolítja a modult a mockolt regiszterből. Az összes importálás az eredeti modult adja vissza, még akkor is, ha korábban mockolták. Ez a hívás a fájl tetejére emelkedik, így csak azokat a modulokat fogja unmockolni, amelyek például a setupFiles
fájlokban lettek definiálva.
vi.doUnmock
- Típus:
(path: string | Promise<Module>) => void
Ugyanaz, mint a vi.unmock
, de nem emelkedik fel a fájl tetejére. A modul következő importálása az eredeti modult fogja importálni a mock helyett. Ez nem fogja visszaállítani a korábban importált modulokat.
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// az increment már mockolva van, mert a vi.mock felemelt
increment(1) === 100;
// ez emelt, és a factory az 1. sorban lévő import előtt hívódik meg
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// az összes hívás mockolva van, és az `increment` mindig 100-at ad vissza
increment(1) === 100;
increment(30) === 100;
// ez nincs emelve, így a másik import unmockolt modult ad vissza
vi.doUnmock('./increment.js');
// ez MÉG MINDIG 100-at ad vissza, mert a `vi.doUnmock` nem értékeli újra a modult
increment(1) === 100;
increment(30) === 100;
// a következő import unmockolt, most az `increment` az eredeti függvény, amely a count + 1-et adja vissza
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- Típus:
() => Vitest
Visszaállítja a modulok nyilvántartását az összes modul gyorsítótárának törlésével. Ez lehetővé teszi a modulok újraértékelését az újraimportáláskor. A legfelső szintű importok nem értékelhetők újra. Hasznos lehet a modulok izolálására, ahol a helyi állapot ütközéseket okoz a tesztek között.
import { vi } from 'vitest';
import { data } from './data.js'; // Nem fog újraértékelődni minden teszt előtt
beforeEach(() => {
vi.resetModules();
});
test('állapot megváltoztatása', async () => {
const mod = await import('./some/path.js'); // Újraértékelődik
mod.changeLocalState('new value');
expect(mod.getLocalState()).toBe('new value');
});
test('a modul régi állapotban van', async () => {
const mod = await import('./some/path.js'); // Újraértékelődik
expect(mod.getLocalState()).toBe('old value');
});
WARNING
Nem állítja vissza a mock nyilvántartást. A mock nyilvántartás törléséhez használja a vi.unmock
vagy a vi.doUnmock
függvényt.
vi.dynamicImportSettled
Megvárja az összes import betöltését. Hasznos, ha van egy szinkron hívása, amely egy modult kezd importálni, és azt egyébként nem tudná megvárni.
import { expect, test } from 'vitest';
// nem tudja nyomon követni az importot, mert a Promise nem kerül visszaadásra
function renderComponent() {
import('./component.js').then(({ render }) => {
render();
});
}
test('a műveletek feloldódtak', async () => {
renderComponent();
await vi.dynamicImportSettled();
expect(document.querySelector('.component')).not.toBeNull();
});
TIP
Ha egy dinamikus import során egy másik dinamikus import is elindul, ez a metódus megvárja, amíg mindegyik feloldódik.
Ez a metódus megvárja a következő setTimeout
ütemet is, miután az import feloldódott, így az összes szinkron műveletnek be kell fejeződnie, mire feloldódik.
Függvények és objektumok mockolása
Ez a szakasz leírja, hogyan kell dolgozni a metódus mockokkal, és hogyan kell felülírni a környezeti és globális változókat.
vi.fn
- Típus:
(fn?: Function) => Mock
Kémfüggvényt hoz létre egy függvényhez, bár anélkül is inicializálható. Minden alkalommal, amikor egy függvényt meghívnak, tárolja a hívási argumentumait, visszatérési értékeit és a példányokat. Emellett manipulálhatja a viselkedését metódusokkal. Ha nincs megadva függvény, a mock undefined
értéket ad vissza, ha meghívják.
const getApples = vi.fn(() => 0);
getApples();
expect(getApples).toHaveBeenCalled();
expect(getApples).toHaveReturnedWith(0);
getApples.mockReturnValueOnce(5);
const res = getApples();
expect(res).toBe(5);
expect(getApples).toHaveNthReturnedWith(2, 5);
vi.mockObject 3.2.0+
- Típus:
<T>(value: T) => MaybeMockedDeep<T>
Mélyen mockolja egy adott objektum tulajdonságait és metódusait ugyanúgy, ahogy a vi.mock()
a modul exportokat mockolja. Részletekért lásd az automockingot.
const original = {
simple: () => 'value',
nested: {
method: () => 'real',
},
prop: 'foo',
};
const mocked = vi.mockObject(original);
expect(mocked.simple()).toBe(undefined);
expect(mocked.nested.method()).toBe(undefined);
expect(mocked.prop).toBe('foo');
mocked.simple.mockReturnValue('mocked');
mocked.nested.method.mockReturnValue('mocked nested');
expect(mocked.simple()).toBe('mocked');
expect(mocked.nested.method()).toBe('mocked nested');
vi.isMockFunction
- Típus:
(fn: Function) => boolean
Ellenőrzi, hogy egy adott paraméter mock függvény. Ha TypeScriptet használ, akkor a típusát is pontosítja.
vi.clearAllMocks
Meghívja a .mockClear()
függvényt az összes kémobjektumon. Ez törli a mock előzményeket anélkül, hogy érintené a mock implementációkat.
vi.resetAllMocks
Meghívja a .mockReset()
függvényt az összes kémobjektumon. Ez törli a mock előzményeket, és visszaállítja az egyes mockok implementációját az eredeti állapotába.
vi.restoreAllMocks
Meghívja a .mockRestore()
függvényt az összes kémobjektumon. Ez törli a mock előzményeket, visszaállítja az összes eredeti mock implementációt, és visszaállítja a megfigyelt objektumok eredeti leíróit.
vi.spyOn
- Típus:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
Kémfüggvényt hoz létre egy objektum metódusához vagy getter/setteréhez, hasonlóan a vi.fn()
függvényhez. Egy mock függvényt ad vissza.
let apples = 0;
const cart = {
getApples: () => 42,
};
const spy = vi.spyOn(cart, 'getApples').mockImplementation(() => apples);
apples = 1;
expect(cart.getApples()).toBe(1);
expect(spy).toHaveBeenCalled();
expect(spy).toHaveReturnedWith(1);
TIP
Azokban a környezetekben, amelyek támogatják az Explicit Resource Management mechanizmust, használhatja a using
kulcsszót a const
helyett, hogy automatikusan meghívja a mockRestore
függvényt bármely mockolt függvényen, amikor a tartalmazó blokk kilép. Ez különösen hasznos a megfigyelt metódusok esetében:
it('calls console.log', () => {
using spy = vi.spyOn(console, 'log').mockImplementation(() => {})
debug('message')
expect(spy).toHaveBeenCalled()
})
// console.log is restored here
TIP
Meghívhatja a vi.restoreAllMocks
függvényt az afterEach
belsejében (vagy engedélyezheti a test.restoreMocks
opciót), hogy az összes metódust visszaállítsa az eredeti implementációjára. Ez visszaállítja az eredeti objektum leírót, így nem fogja tudni megváltoztatni a metódus implementációját:
const cart = {
getApples: () => 42,
};
const spy = vi.spyOn(cart, 'getApples').mockReturnValue(10);
console.log(cart.getApples()); // 10
vi.restoreAllMocks();
console.log(cart.getApples()); // 42
spy.mockReturnValue(10);
console.log(cart.getApples()); // még mindig 42!
TIP
Nem lehetséges megfigyelni az exportált metódusokat Böngésző módban. Ehelyett kémkedhet minden exportált metóduson a vi.mock("./file-path.js", { spy: true })
meghívásával. Ez minden exportot mockol, de az implementációját változatlanul hagyja, lehetővé téve, hogy ellenőrizze, hogy a metódust helyesen hívták-e meg.
import { calculator } from './src/calculator.ts';
vi.mock('./src/calculator.ts', { spy: true });
calculator(1, 2);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);
És bár lehetséges kémkedni az exportokon jsdom
vagy más Node.js környezetekben, ez a jövőben változhat.
vi.stubEnv
- Típus:
<T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => Vitest
Megváltoztatja a környezeti változó értékét a process.env
és import.meta.env
objektumokon. Az értékét visszaállíthatja a vi.unstubAllEnvs
meghívásával.
import { vi } from 'vitest';
// `process.env.NODE_ENV` és `import.meta.env.NODE_ENV`
// "development" a "vi.stubEnv" meghívása előtt
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
vi.stubEnv('NODE_ENV', undefined);
process.env.NODE_ENV === undefined;
import.meta.env.NODE_ENV === undefined;
// nem változtatja meg a többi környezeti változót
import.meta.env.MODE === 'development';
TIP
Az értéket egyszerűen hozzárendeléssel is megváltoztathatja, de ekkor nem fogja tudni használni a vi.unstubAllEnvs
függvényt az előző érték visszaállítására:
import.meta.env.MODE = 'test';
vi.unstubAllEnvs
- Típus:
() => Vitest
Visszaállítja az összes import.meta.env
és process.env
értéket, amelyet a vi.stubEnv
megváltoztatott. Amikor először hívják meg, a Vitest megjegyzi az eredeti értéket, és tárolja azt, amíg az unstubAllEnvs
újra meg nem hívják.
import { vi } from 'vitest';
// `process.env.NODE_ENV` és `import.meta.env.NODE_ENV`
// "development" a stubEnv meghívása előtt
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
vi.stubEnv('NODE_ENV', 'staging');
process.env.NODE_ENV === 'staging';
import.meta.env.NODE_ENV === 'staging';
vi.unstubAllEnvs();
// visszaállítja az első "stubEnv" hívás előtt tárolt értékre
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
- Típus:
(name: string | number | symbol, value: unknown) => Vitest
Megváltoztatja egy globális változó értékét. Az eredeti értékét visszaállíthatja a vi.unstubAllGlobals
meghívásával.
import { vi } from 'vitest';
// az `innerWidth` "0" a stubGlobal meghívása előtt
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// ha jsdom-ot vagy happy-dom-ot használ
window.innerWidth === 100;
TIP
Az értéket egyszerűen hozzárendeléssel is megváltoztathatja a globalThis
vagy window
(ha jsdom
vagy happy-dom
környezetet használ) objektumhoz, de ekkor nem fogja tudni használni a vi.unstubAllGlobals
függvényt az eredeti érték visszaállítására:
globalThis.innerWidth = 100;
// ha jsdom-ot vagy happy-dom-ot használ
window.innerWidth = 100;
vi.unstubAllGlobals
- Típus:
() => Vitest
Visszaállítja az összes globális értéket a globalThis
/global
(és window
/top
/self
/parent
, ha jsdom
vagy happy-dom
környezetet használ) objektumon, amelyet a vi.stubGlobal
megváltoztatott. Amikor először hívják meg, a Vitest megjegyzi az eredeti értéket, és tárolja azt, amíg az unstubAllGlobals
újra meg nem hívják.
import { vi } from 'vitest';
const Mock = vi.fn();
// az IntersectionObserver "undefined" a "stubGlobal" meghívása előtt
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// ha jsdom-ot vagy happy-dom-ot használ
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// ReferenceError-t dob, mert nincs definiálva
IntersectionObserver === undefined;
Hamis időzítők
Ez a szakasz leírja, hogyan kell dolgozni a hamis időzítőkkel.
vi.advanceTimersByTime
- Típus:
(ms: number) => Vitest
Ez a metódus minden inicializált időzítőt végrehajt, amíg a megadott milliszekundum el nem telik, vagy a sor üres nem lesz – attól függően, hogy melyik következik előbb.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersByTime(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersByTimeAsync
- Típus:
(ms: number) => Promise<Vitest>
Ez a metódus minden inicializált időzítőt végrehajt, amíg a megadott milliszekundum el nem telik, vagy a sor üres nem lesz – attól függően, hogy melyik következik be előbb. Ez magában foglalja az aszinkron módon beállított időzítőket is.
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersByTimeAsync(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersToNextTimer
- Típus:
() => Vitest
Végrehajtja a következő elérhető időzítőt. Hasznos, ha minden időzítőhívás között ellenőrzéseket szeretne végezni. Láncoltan is hívhatja, hogy maga kezelje az időzítőket.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer(); // log: 3
vi.advanceTimersToNextTimerAsync
- Típus:
() => Promise<Vitest>
Végrehajtja a következő elérhető időzítőt, és megvárja, amíg feloldódik, ha aszinkron módon lett beállítva. Hasznos, ha minden időzítőhívás között ellenőrzéseket szeretne végezni.
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersToNextTimerAsync(); // log: 1
expect(console.log).toHaveBeenCalledWith(1);
await vi.advanceTimersToNextTimerAsync(); // log: 2
await vi.advanceTimersToNextTimerAsync(); // log: 3
vi.advanceTimersToNextFrame 2.1.0+
- Típus:
() => Vitest
Hasonló a vi.advanceTimersByTime
függvényhez, de az időzítőket annyi milliszekundummal lépteti előre, amennyi a requestAnimationFrame
segítségével jelenleg ütemezett visszahívások végrehajtásához szükséges.
let frameRendered = false;
requestAnimationFrame(() => {
frameRendered = true;
});
vi.advanceTimersToNextFrame();
expect(frameRendered).toBe(true);
vi.getTimerCount
- Típus:
() => number
Visszaadja a várakozó időzítők számát.
vi.clearAllTimers
Eltávolítja az összes futásra ütemezett időzítőt. Ezek az időzítők a jövőben soha nem fognak futni.
vi.getMockedSystemTime
- Típus:
() => Date | null
Visszaadja a mockolt aktuális dátumot. Ha a dátum nincs mockolva, a metódus null
értéket ad vissza.
vi.getRealSystemTime
- Típus:
() => number
A vi.useFakeTimers
használatakor a Date.now
hívások mockoltak. Ha valós időt szeretne milliszekundumban lekérni, meghívhatja ezt a függvényt.
vi.runAllTicks
- Típus:
() => Vitest
Végrehajtja az összes mikrofeladatot, amelyet a process.nextTick
sorba állított. Ez az összes önmaguk által ütemezett mikrofeladatot is futtatja.
vi.runAllTimers
- Típus:
() => Vitest
Ez a metódus minden inicializált időzítőt végrehajt, amíg az időzítősor üres nem lesz. Ez azt jelenti, hogy a runAllTimers
során meghívott minden időzítő végrehajtódik. Ha végtelen intervalluma van, 10 000 próbálkozás után hibát jelez (konfigurálható a fakeTimers.loopLimit
opcióval).
let i = 0;
setTimeout(() => console.log(++i));
const interval = setInterval(() => {
console.log(++i);
if (i === 3) {
clearInterval(interval);
}
}, 50);
vi.runAllTimers();
// log: 1
// log: 2
// log: 3
vi.runAllTimersAsync
- Típus:
() => Promise<Vitest>
Ez a metódus aszinkron módon végrehajtja az összes inicializált időzítőt, amíg az időzítősor ki nem ürül. Ez azt jelenti, hogy a runAllTimersAsync
során meghívott minden időzítő végrehajtódik, még az aszinkron időzítők is. Ha végtelen intervalluma van, 10 000 próbálkozás után hibát jelez (konfigurálható a fakeTimers.loopLimit
opcióval).
setTimeout(async () => {
console.log(await Promise.resolve('eredmény'));
}, 100);
await vi.runAllTimersAsync();
// log: eredmény
vi.runOnlyPendingTimers
- Típus:
() => Vitest
Ez a metódus minden olyan időzítőt végrehajt, amelyet a vi.useFakeTimers
hívás után inicializáltak. Nem fogja végrehajtani azokat az időzítőket, amelyeket a hívása során inicializáltak.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- Típus:
() => Promise<Vitest>
Ez a metódus aszinkron módon végrehajtja az összes olyan időzítőt, amelyet a vi.useFakeTimers
hívás után inicializáltak, még az aszinkronokat is. Nem fogja végrehajtani azokat az időzítőket, amelyeket a hívása során inicializáltak.
setTimeout(() => {
console.log(1);
}, 100);
setTimeout(() => {
Promise.resolve().then(() => {
console.log(2);
setInterval(() => {
console.log(3);
}, 40);
});
}, 10);
await vi.runOnlyPendingTimersAsync();
// log: 2
// log: 3
// log: 3
// log: 1
vi.setSystemTime
- Típus:
(date: string | number | Date) => void
Ha a hamis időzítők engedélyezve vannak, ez a metódus szimulálja, hogy a felhasználó megváltoztatja a rendszerórát (ez hatással lesz a dátummal kapcsolatos API-kra, mint például a hrtime
, performance.now
vagy new Date()
) – azonban nem fog időzítőket végrehajtani. Ha a hamis időzítők nincsenek engedélyezve, ez a metódus csak a Date.*
hívásokat mockolja.
Hasznos, ha bármit tesztelnie kell, ami az aktuális dátumtól függ – például a Luxon hívásokat a kódjában.
Ugyanazokat a string és szám argumentumokat fogadja el, mint a Date
.
const date = new Date(1998, 11, 19);
vi.useFakeTimers();
vi.setSystemTime(date);
expect(Date.now()).toBe(date.valueOf());
vi.useRealTimers();
vi.useFakeTimers
- Típus:
(config?: FakeTimerInstallOpts) => Vitest
Az időzítők mockolásának engedélyezéséhez meg kell hívnia ezt a metódust. Ez az összes további időzítőhívást (például setTimeout
, setInterval
, clearTimeout
, clearInterval
, setImmediate
, clearImmediate
és Date
) felülírja, amíg a vi.useRealTimers()
meg nem hívódik.
A nextTick
mockolása nem támogatott, ha a Vitestet node:child_process
belsejében futtatja a --pool=forks
használatával. A NodeJS belsőleg használja a process.nextTick
függvényt a node:child_process
környezetben, és lefagy, ha mockolva van. A nextTick
mockolása támogatott, ha a Vitestet --pool=threads
opcióval futtatja.
Az implementáció belsőleg a @sinonjs/fake-timers
könyvtáron alapul.
TIP
A vi.useFakeTimers()
nem mockolja automatikusan a process.nextTick
és queueMicrotask
függvényeket. De engedélyezheti ezt az opciót a toFake
argumentumban: vi.useFakeTimers({ toFake: ['nextTick', 'queueMicrotask'] })
.
vi.isFakeTimers
- Típus:
() => boolean
true
értéket ad vissza, ha a hamis időzítők engedélyezettek.
vi.useRealTimers
- Típus:
() => Vitest
Amikor az időzítők lejárnak, meghívhatja ezt a metódust, hogy a mockolt időzítőket visszaállítsa eredeti implementációjukra. Az összes korábban ütemezett időzítő elvetésre kerül.
Egyéb
A Vitest által biztosított hasznos segédfüggvények.
vi.waitFor
- Típus:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
Megvárja, amíg a visszahívás sikeresen végrehajtódik. Ha a visszahívás hibát dob, vagy elutasított promise-t ad vissza, tovább vár, amíg sikeres nem lesz, vagy időtúllépés nem következik be.
Ha az options
számra van állítva, a hatás egyenértékű a { timeout: options }
beállításával.
Ez nagyon hasznos, ha valamilyen aszinkron művelet befejezésére kell várnia, például amikor elindít egy szervert, és meg kell várnia, amíg elindul.
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';
test('A szerver sikeresen elindult', async () => {
const server = createServer();
await vi.waitFor(
() => {
if (!server.isReady) {
throw new Error('A szerver nem indult el');
}
console.log('A szerver elindult');
},
{
timeout: 500, // alapértelmezett: 1000
interval: 20, // alapértelmezett: 50
}
);
expect(server.isReady).toBe(true);
});
Aszinkron visszahívások esetén is működik
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';
test('Az elem létezik a DOM-ban', async () => {
// DOM feltöltésének indítása
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// próbálja meg lekérni az elemet, amíg létezik
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // alapértelmezett: 1000
interval: 20, // alapértelmezett: 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
Ha a vi.useFakeTimers
használatban van, a vi.waitFor
automatikusan meghívja a vi.advanceTimersByTime(interval)
függvényt minden ellenőrző visszahívásban.
vi.waitUntil
- Típus:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
Ez hasonló a vi.waitFor
függvényhez, de ha a visszahívás bármilyen hibát dob, a végrehajtás azonnal megszakad, és hibaüzenet jelenik meg. Ha a visszahívás hamis értéket ad vissza, a következő ellenőrzés folytatódik, amíg igaz érték nem tér vissza. Ez akkor hasznos, ha meg kell várnia, hogy valami létezzen, mielőtt megtenné a következő lépést.
Tekintse meg az alábbi példát. A vi.waitUntil
segítségével megvárhatjuk, amíg az elem megjelenik az oldalon, majd elvégezhetünk valamilyen műveletet az elemmel.
import { expect, test, vi } from 'vitest';
test('Az elem helyesen renderelődik', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // alapértelmezett: 1000
interval: 20, // alapértelmezett: 50
});
// tegyen valamit az elemmel
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted
- Típus:
<T>(factory: () => T) => T
Az ES modulokban az összes statikus import
utasítás a fájl tetejére emelkedik, így minden olyan kód, amely az importok előtt van definiálva, valójában az importok kiértékelése után hajtódik végre.
Azonban hasznos lehet bizonyos mellékhatások kiváltása, például dátumok mockolása egy modul importálása előtt.
Ennek a korlátozásnak a megkerüléséhez átírhatja a statikus importokat dinamikus importokra az alábbiak szerint:
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
A vitest
futtatásakor ezt automatikusan megteheti a vi.hoisted
metódus használatával. A háttérben a Vitest a statikus importokat dinamikus importokká alakítja át, megőrizve az élő kötéseket.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
AZ IMPORTOK NEM ELÉRHETŐK
A kód futtatása az importok előtt azt jelenti, hogy nem férhet hozzá az importált változókhoz, mert azok még nincsenek definiálva:
import { value } from './some/module.js';
vi.hoisted(() => { value }); // hibát dob
Ez a kód hibát fog eredményezni:
Cannot access '__vi_0__' before initialization
Ha egy másik modulból származó változóhoz kell hozzáférnie a vi.hoisted
belsejében, használjon dinamikus importot:
await vi.hoisted(async () => {
const { value } = await import('./some/module.js');
});
Azonban nem javasolt semmit importálni a vi.hoisted
belsejében, mert az importok már emeltek – ha valamit a tesztek futtatása előtt kell végrehajtania, egyszerűen hajtsa végre magában az importált modulban.
Ez a metódus visszaadja a factory által visszaadott értéket. Ezt az értéket felhasználhatja a vi.mock
factory-jaiban, ha könnyen hozzáférhetővé szeretné tenni a lokálisan definiált változókat:
import { expect, vi } from 'vitest';
import { originalMethod } from './path/to/module.js';
const { mockedMethod } = vi.hoisted(() => {
return { mockedMethod: vi.fn() };
});
vi.mock('./path/to/module.js', () => {
return { originalMethod: mockedMethod };
});
mockedMethod.mockReturnValue(100);
expect(originalMethod()).toBe(100);
Fontos megjegyezni, hogy ez a metódus aszinkron módon is meghívható, még akkor is, ha a környezete nem támogatja a legfelső szintű await-et:
const json = await vi.hoisted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
});
vi.setConfig
- Típus:
RuntimeConfig
Frissíti a konfigurációt az aktuális tesztfájl számára. Ez a metódus csak azokat a konfigurációs opciókat támogatja, amelyek az aktuális tesztfájlt érintik:
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// támogatja az egész objektumot
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// csak a "sequence.hooks" támogatott
},
});
vi.resetConfig
- Típus:
RuntimeConfig
Ha a vi.setConfig
korábban meghívásra került, ez visszaállítja a konfigurációt az eredeti állapotba.