Vi
A Vitest a vi
segédprogramján keresztül biztosít segédfunkciókat. Globálisan is elérheted (ha a globals konfiguráció engedélyezve van), vagy közvetlenül importálhatod a vitest
-ből:
import { vi } from 'vitest';
Modulok Mockolása
Ez a szakasz az API-t írja le, amelyet a modulok mockolásához használhatsz. Fontos megjegyezni, hogy a Vitest nem támogatja a require()
használatával 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
-ról egy másik modullal helyettesíti. Használhatod a konfigurált Vite aliasokat az útvonalon belül. A vi.mock
hívás felemelésre kerül (hoisted), így nem számít, hogy hol hívod meg. Mindig az összes import előtt fog végrehajtódni. Ha hivatkoznod kell néhány változóra a hatókörén kívül, definiálhatod őket a vi.hoisted
belsejében, és hivatkozhatsz rájuk a vi.mock
belsejében.
WARNING
A vi.mock
csak az import
kulcsszóval importált moduloknál működik. Nem működik a require
-rel.
A vi.mock
hoistingolásához a Vitest statikusan elemzi a fájljaidat. Ez azt jelenti, hogy a vi
, amelyet nem közvetlenül a vitest
csomagból importáltál (például egy segédprogram fájlból), nem használható. Használd a vi.mock
-ot a vitest
-ből importált vi
-vel, vagy engedélyezd a globals
konfigurációs opciót.
A Vitest nem fogja mockolni azokat a modulokat, amelyeket egy setup fájlban importáltak, mert azok a tesztfájl futásakor már gyorsítótárazva vannak. Hívhatod a vi.resetModules()
metódust a vi.hoisted
belsejében, hogy törölje az összes modul gyorsítótárat 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 későbbi importáláshoz, amíg a vi.unmock
vagy a vi.doUnmock
hívás meg nem történik.
A jest
-tel ellentétben a factory lehet aszinkron. Használhatod a vi.importActual
metódust vagy egy segédprogramot, amelynek a factory-t adják át első argumentumként, és így hozzáférhetsz az eredeti modulhoz.
A Vitest 2.1 óta a factory függvény helyett egy objektumot is megadhatsz spy
tulajdonsággal. Ha a spy
értéke true
, akkor a Vitest a szokásos módon automockolja a modult, de nem írja felül az exportok implementációját. Ez akkor hasznos, ha csak azt szeretnéd 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 kikényszeríti, 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 következtetett
// ^?
return {
...mod,
// néhány export felülírása
total: vi.fn(),
};
});
A háttérben a Vitest továbbra is stringgel dolgozik, nem modul objektummal.
Ha TypeScript-et használsz a tsconfig.json
-ban 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 meg róla, hogy az összes aliased importot lecseréled a megfelelő relatív útvonalakra. Pl. használd az import('./path/to/module.js')
helyett az import('@/module')
-t.
WARNING
A vi.mock
hoistingolásra kerül (más szóval, áthelyezésre) a fájl tetejére. Ez azt jelenti, hogy bárhol is írod (legyen az beforeEach
vagy test
belsejében), valójában azelőtt fog meghívódni.
Ez azt is jelenti, hogy nem használhatsz semmilyen változót a factory belsejében, amelyek a factory-n kívül vannak definiálva.
Ha változókat kell használnod a factory belsejében, próbáld meg a vi.doMock
metódust használni. Ugyanúgy működik, de nincs felemelve. Vigyázz, csak a későbbi importokat mockolja.
Hivatkozhatsz 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 mockolsz alapértelmezett exporttal, akkor a visszaadott factory függvény objektumon belül meg kell adnod egy default
kulcsot. Ez egy ES modul-specifikus sajátosság; ezért a jest
dokumentáció 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ál egy azonos nevű fájlt találni a __mocks__
almappában, és azt használja tényleges modulként. Ha egy függőséget mockolsz, a Vitest megpróbál egy __mocks__
mappát találni a projekt gyökerében (alapértelmezett a process.cwd()
). Megadhatod a Vitestnek, 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
metódust hívod egy tesztfájlban factory vagy opciók nélkül, akkor a __mocks__
mappában talál egy fájlt, amelyet modulként használhat:
// increment.test.js
import { vi } from 'vitest';
// az axios egy alapértelmezett export a `__mocks__/axios.js`-ből
import axios from 'axios';
// az increment egy elnevezett export a `src/__mocks__/increment.js`-ből
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
Vigyázz, ha nem hívod a vi.mock
metódust, a modulok nem lesznek automatikusan mockolva. A Jest automocking viselkedésének replikálásához hívhatod a vi.mock
metódust minden szükséges modulhoz a setupFiles
belsejében.
Ha nincs __mocks__
mappa vagy megadott factory, a Vitest importálja az eredeti modult, és automockolja az összes exportját. Az alkalmazott szabályokért lásd az algoritmust.
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 nincs felemelve a fájl tetejére, így hivatkozhatsz változókra a globális fájl hatókörében. A modul következő dinamikus importálása mockolva lesz.
WARNING
Ez nem fogja mockolni azokat a modulokat, amelyeket ez előtt hívtak meg. Ne felejtsd el, hogy az összes statikus import az ESM-ben mindig hoistingolásra kerül, így ennek a statikus import elé helyezése nem fogja kikényszeríteni, hogy az import előtt hívják meg:
vi.doMock('./increment.js'); // ez az import utasítás _után_ lesz meghívva
import { increment } from './increment.js';
// ./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érhetsz 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 a mockolt modult adja 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ípus segéd TypeScript-hez. Csak visszaadja az átadott objektumot.
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 fogja elhitetni a TypeScript-tel, hogy az első szintű értékek mockolva vannak. Átadhatod a { deep: true }
-t második argumentumként, hogy elmondd a TypeScript-nek, hogy az egész objektum mockolva van, ha tényleg az.
// example.ts
export function add(x: number, y: number): number {
return x + y;
}
export function fetchSomething(): Promise<Response> {
return fetch('https://vitest.dev/');
}
// example.test.ts
import * as example from './example';
vi.mock('./example');
test('1 + 1 egyenlő 10', 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 tipizálá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>
Importálja a modult, megkerülve az összes ellenőrzést, hogy mockolni kell-e. Hasznos lehet, ha részben szeretnéd mockolni a modult.
vi.mock('./example.js', async () => {
const axios = await vi.importActual('./example.js');
return { ...axios, get: vi.fn() };
});
vi.importMock
- Típus:
<T>(path: string) => Promise<MaybeMockedDeep<T>>
Importál egy modult 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ályokért lásd az algoritmust.
vi.unmock
- Típus:
(path: string | Promise<Module>) => void
Eltávolítja a modult a mockolt regiszterből. Minden importálási hívás az eredeti modult adja vissza, még akkor is, ha korábban mockolva volt. Ez a hívás felemelésre kerül a fájl tetejére, így csak azokat a modulokat fogja unmockolni, amelyek például a setupFiles
-ban voltak definiálva.
vi.doUnmock
- Típus:
(path: string | Promise<Module>) => void
Ugyanaz, mint a vi.unmock
, de nincs felemelve a fájl tetejére. A modul következő importálása az eredeti modult fogja importálni a mock helyett. Ez nem fogja unmockolni a korábban importált modulokat.
// ./increment.js
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// az increment már mockolva van, mert a vi.mock felemelésre került
increment(1) === 100;
// ez felemelésre került, és a factory az 1. sorban lévő import előtt hívódik meg
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// minden hívás mockolva van, és az `increment` mindig 100-at ad vissza
increment(1) === 100;
increment(30) === 100;
// ez nincs felemelve, í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 count + 1-et ad vissza
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- Típus:
() => Vitest
Visszaállítja a modul regisztert 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 felső szintű importok nem értékelhetők újra. Hasznos lehet a modulok izolálására, ahol a helyi állapot ütközik a tesztek között.
import { vi } from 'vitest';
import { data } from './data.js'; // Nem lesz újraértékelve minden teszt előtt
beforeEach(() => {
vi.resetModules();
});
test('állapot megváltoztatása', async () => {
const mod = await import('./some/path.js'); // Újraértékelve lesz
mod.changeLocalState('új érték');
expect(mod.getLocalState()).toBe('új érték');
});
test('a modulnak régi állapota van', async () => {
const mod = await import('./some/path.js'); // Újraértékelve lesz
expect(mod.getLocalState()).toBe('régi érték');
});
WARNING
Nem állítja vissza a mock regisztert. A mock regiszter törléséhez használd a vi.unmock
vagy a vi.doUnmock
metódust.
vi.dynamicImportSettled
Várja meg az összes import betöltését. Hasznos, ha van egy szinkron hívásod, amely elindít egy modul importálását, amelyet egyébként nem tudsz megvárni.
import { expect, test, vi } from 'vitest';
// nem tudja 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 indul el, ez a metódus megvárja, amíg mindegyik feloldódik.
Ez a metódus megvárja a következő setTimeout
tick-et is az import feloldása után, í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 dolgozhatsz a metódus mockokkal és hogyan cserélheted le a környezeti és globális változókat.
vi.fn
- Típus:
(fn?: Function) => Mock
Spy-t hoz létre egy függvényen, 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 példányait. Ezenkívül manipulálhatod a viselkedését a metódusokkal. Ha nincs megadva függvény, a mock undefined
-t ad vissza, amikor 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.isMockFunction
- Típus:
(fn: Function) => boolean
Ellenőrzi, hogy egy adott paraméter mock függvény-e. Ha TypeScript-et használsz, akkor a típusát is finomítja.
vi.clearAllMocks
Meghívja a .mockClear()
metódust az összes spy-on. Ez törli a mock előzményeket, de nem állítja vissza az implementációját az alapértelmezettre.
vi.resetAllMocks
Meghívja a .mockReset()
metódust az összes spy-on. Ez törli a mock előzményeket, és visszaállítja az implementációját egy üres függvényre (amely undefined
-t ad vissza).
vi.restoreAllMocks
Meghívja a .mockRestore()
metódust az összes spy-on. Ez törli a mock előzményeket, és visszaállítja az implementációját az eredetire.
vi.spyOn
- Típus:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
Spy-t hoz létre egy objektum metódusán vagy getter/setterén, hasonlóan a vi.fn()
metódushoz. 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
Hívhatod a vi.restoreAllMocks
metódust az afterEach
belsejében (vagy engedélyezheted a test.restoreMocks
opciót), hogy visszaállítsd az összes metódust az eredeti implementációjukra. Ez visszaállítja az objektum eredeti leíróját, így nem tudod 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 spy-t létrehozni az exportált metódusokon böngésző módban. Ehelyett kémkedhetsz minden exportált metóduson a vi.mock("./file-path.js", { spy: true })
hívásával. Ez minden exportot mockol, de az implementációját érintetlenül hagyja, lehetővé téve, hogy ellenőrizd, 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 megvá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
esetében. Az értékét visszaállíthatod a vi.unstubAllEnvs
hívásával.
import { vi } from 'vitest';
// `process.env.NODE_ENV` és `import.meta.env.NODE_ENV`
// "development" a "vi.stubEnv" hí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 env-t
import.meta.env.MODE === 'development';
TIP
Az értéket egyszerűen hozzárendeléssel is megváltoztathatod, de nem fogod tudni használni a vi.unstubAllEnvs
metódust az előző érték visszaállításához:
import.meta.env.MODE = 'test';
vi.unstubAllEnvs
- Típus:
() => Vitest
Visszaállítja az összes import.meta.env
és process.env
értéket, amelyeket a vi.stubEnv
metódus 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ívódik.
import { vi } from 'vitest';
// `process.env.NODE_ENV` és `import.meta.env.NODE_ENV`
// "development" a stubEnv hí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 értéket, amely az első "stubEnv" hívás előtt volt tárolva
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
- Típus:
(name: string | number | symbol, value: unknown) => Vitest
Globális változó értékét változtatja meg. Az eredeti értékét visszaállíthatod a vi.unstubAllGlobals
hívásával.
import { vi } from 'vitest';
// az `innerWidth` "0" a stubGlobal hívása előtt
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// ha jsdom-ot vagy happy-dom-ot használsz
window.innerWidth === 100;
TIP
Az értéket egyszerűen hozzárendeléssel is megváltoztathatod a globalThis
vagy window
objektumhoz (ha jsdom
vagy happy-dom
környezetet használsz), de nem fogod tudni használni a vi.unstubAllGlobals
metódust az eredeti érték visszaállításához:
globalThis.innerWidth = 100;
// ha jsdom-ot vagy happy-dom-ot használsz
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álsz) esetében, amelyeket a vi.stubGlobal
metódus 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ívódik.
import { vi } from 'vitest';
const Mock = vi.fn();
// az IntersectionObserver "undefined" a "stubGlobal" hívása előtt
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// ha jsdom-ot vagy happy-dom-ot használsz
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 dolgozhatsz a hamis időzítőkkel.
vi.advanceTimersByTime
- Típus:
(ms: number) => Vitest
Ez a metódus minden elindított időzítőt meghív, amíg a megadott milliszekundum el nem telik, vagy a sor kiürül - attól függően, hogy melyik következik be 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 elindított időzítőt meghív, amíg a megadott milliszekundum el nem telik, vagy a sor kiürül - 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
Meghívja a következő elérhető időzítőt. Hasznos az ellenőrzések elvégzéséhez minden időzítő hívás között. Láncolhatod a hívásokat, hogy saját magad kezeld 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>
Meghívja 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 az ellenőrzések elvégzéséhez minden időzítő hívás között.
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
metódushoz, de annyi milliszekundummal lépteti előre az időzítőket, 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
Lekéri 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 soha nem fognak futni a jövőben.
vi.getMockedSystemTime
- Típus:
() => Date | null
Visszaadja a mockolt aktuális dátumot, amelyet a setSystemTime
metódussal állítottak be. Ha a dátum nincs mockolva, a metódus null
-t ad vissza.
vi.getRealSystemTime
- Típus:
() => number
Amikor a vi.useFakeTimers
metódust használod, a Date.now
hívások mockolva vannak. Ha valós időt szeretnél milliszekundumban lekérni, meghívhatod ezt a függvényt.
vi.runAllTicks
- Típus:
() => Vitest
Meghív minden mikrofeladatot, amelyet a process.nextTick
sorba állított. Ez futtatja az összes önmaguk által ütemezett mikrofeladatot is.
vi.runAllTimers
- Típus:
() => Vitest
Ez a metódus minden elindított időzítőt meghív, amíg az időzítő sor kiürül. Ez azt jelenti, hogy minden időzítő, amelyet a runAllTimers
hívás során hívtak meg, elindul. Ha végtelen intervallumod van, 10 000 próbálkozás után hibát dob (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 meghív minden elindított időzítőt, amíg az időzítő sor kiürül. Ez azt jelenti, hogy minden időzítő, amelyet a runAllTimersAsync
hívás során hívtak meg, elindul, még az aszinkron időzítők is. Ha végtelen intervallumod van, 10 000 próbálkozás után hibát dob (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 időzítőt meghív, amelyet a vi.useFakeTimers
hívás után indítottak el. Nem fogja elindítani azokat az időzítőket, amelyeket a hívása során indítottak el.
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 meghív minden időzítőt, amelyet a vi.useFakeTimers
hívás után indítottak el, még az aszinkronokat is. Nem fogja elindítani azokat az időzítőket, amelyeket a hívása során indítottak el.
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 a hrtime
, performance.now
vagy new Date()
) - azonban nem fog elindítani semmilyen időzítőt. Ha a hamis időzítők nincsenek engedélyezve, ez a metódus csak a Date.*
hívásokat mockolja.
Hasznos, ha olyan dolgokat kell tesztelned, amelyek az aktuális dátumtól függenek - például a Luxon hívásokat a kódodban.
Ugyanazokat a string és number 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ívnod ezt a metódust. Ez felülírja az összes további hívást az időzítőkhöz (például setTimeout
, setInterval
, clearTimeout
, clearInterval
, setImmediate
, clearImmediate
, és Date
), amíg a vi.useRealTimers()
hívás meg nem történik.
A nextTick
mockolása nem támogatott, ha a Vitest-et node:child_process
belsejében futtatod a --pool=forks
használatával. A NodeJS belsőleg használja a process.nextTick
-et a node:child_process
belsejében, és lefagy, ha mockolva van. A nextTick
mockolása támogatott, ha a Vitest-et --pool=threads
opcióval futtatod.
Az implementáció belsőleg a @sinonjs/fake-timers
alapul.
TIP
A vi.useFakeTimers()
nem mockolja automatikusan a process.nextTick
-et. De engedélyezheted ezt az opciót a toFake
argumentumban: vi.useFakeTimers({ toFake: ['nextTick'] })
.
vi.isFakeTimers
- Típus:
() => boolean
true
-t ad vissza, ha a hamis időzítők engedélyezve vannak.
vi.useRealTimers
- Típus:
() => Vitest
Amikor az időzítők lefutottak, meghívhatod ezt a metódust, hogy visszaállítsd a mockolt időzítőket az eredeti implementációjukra. Minden korábban ütemezett időzítő eldobásra kerül.
Egyéb
Egy sor hasznos segédprogram, amelyet a Vitest biztosít.
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 sikerül, vagy időtúllépés következik be.
Ez nagyon hasznos, ha meg kell várnod valamilyen aszinkron művelet befejezését, például amikor elindítasz egy szervert, és meg kell várnod, 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ásoknál 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
metódust használod, a vi.waitFor
automatikusan meghívja a vi.advanceTimersByTime(interval)
metódust minden ellenőrző visszahívásban.
vi.waitUntil
- Típus:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
Ez hasonló a vi.waitFor
metódushoz, de ha a visszahívás bármilyen hibát dob, a végrehajtás azonnal megszakad, és hibaüzenet érkezik. Ha a visszahívás hamis értéket ad vissza, a következő ellenőrzés folytatódik, amíg igaz érték nem kerül visszaadásra. Ez akkor hasznos, ha meg kell várnod, hogy valami létezzen, mielőtt megteszed a következő lépést.
Nézd meg az alábbi példát. Használhatjuk a vi.waitUntil
metódust, hogy megvárjuk, amíg az elem megjelenik az oldalon, majd tehetünk valamit 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
});
// tegyél valamit az elemmel
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted
- Típus:
<T>(factory: () => T) => T
Az összes statikus import
utasítás az ES modulokban hoistingolásra kerül a fájl tetejére, így minden kód, amely az importok előtt van definiálva, valójában az importok kiértékelése után fog végrehajtódni.
Azonban hasznos lehet néhány mellékhatás meghívása, például a dátumok mockolása egy modul importálása előtt.
Ennek a korlátozásnak a megkerüléséhez átírhatod a statikus importokat dinamikus importokra így:
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
A vitest
futtatásakor ezt automatikusan megteheted a vi.hoisted
metódus használatával.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
Ez a metódus visszaadja a factory által szolgáltatott értéket. Ezt az értéket használhatod a vi.mock
factory-jaidban, ha könnyen hozzáférsz a lokálisan definiált változókhoz:
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);
Megjegyzendő, hogy ez a metódus aszinkron módon is hívható, még akkor is, ha a környezeted nem támogatja a top-level await-et:
const promised = 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ájlhoz. Ez a metódus csak azokat a konfigurációs opciókat támogatja, amelyek hatással lesznek az aktuális tesztfájlra:
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"-ot támogatja
},
});
vi.resetConfig
- Típus:
RuntimeConfig
Ha a vi.setConfig
metódust korábban hívták, ez visszaállítja a konfigurációt az eredeti állapotba.