Vi
Vitest poskytuje užitečné funkce, které vám pomohou prostřednictvím svého pomocníka vi
. Můžete k němu přistupovat globálně (pokud je povolena konfigurace globals), nebo jej importovat přímo z vitest
:
import { vi } from 'vitest';
Mockování modulů
Tato sekce popisuje API, které můžete použít při mockování modulů. Upozorňujeme, že Vitest nepodporuje mockování modulů, které byly importovány pomocí require()
.
vi.mock
- Typ:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
Nahradí všechny importy z modulu na cestě path
jiným modulem. Uvnitř cesty můžete použít nakonfigurované aliasy Vite. Volání vi.mock
je přesunuto nahoru, takže nezáleží na tom, kde jej voláte. Vždy bude provedeno před všemi importy. Pokud potřebujete odkazovat na proměnné mimo jeho rozsah, můžete je definovat uvnitř vi.hoisted
a odkazovat se na ně uvnitř vi.mock
.
WARNING
vi.mock
funguje pouze pro moduly, které byly importovány pomocí klíčového slova import
. Nefunguje s require
.
Aby bylo možné vi.mock
přesunout nahoru, Vitest staticky analyzuje vaše soubory. To znamená, že nemůžete použít vi
, které není přímo importováno z balíčku vitest
(například z nějakého pomocného souboru). Použijte vi.mock
s vi
importovaným z vitest
, nebo povolte konfigurační možnost globals
.
Vitest nebude mockovat moduly, které byly importovány uvnitř setup souboru, protože jsou uloženy v mezipaměti v době, kdy je spuštěn testovací soubor. Můžete zavolat vi.resetModules()
uvnitř vi.hoisted
a vymazat všechny mezipaměti modulů před spuštěním testovacího souboru.
WARNING
Režim prohlížeče v současné době nepodporuje mockování modulů. Tuto funkci můžete sledovat v GitHub issue.
Pokud je factory
definována, všechny importy vrátí její výsledek. Vitest volá factory pouze jednou a ukládá výsledky do mezipaměti pro všechny následující importy, dokud není volána vi.unmock
nebo vi.doUnmock
.
Na rozdíl od jest
může být factory asynchronní. Můžete použít vi.importActual
nebo pomocníka s factory předanou jako první argument a získat původní modul uvnitř.
import { vi } from 'vitest';
// ---cut---
// při použití JavaScriptu
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal();
return {
...mod,
// nahradí některé exporty
namedExport: vi.fn(),
};
});
// při použití TypeScriptu
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal<typeof import('./path/to/module.js')>();
return {
...mod,
// nahradí některé exporty
namedExport: vi.fn(),
};
});
WARNING
vi.mock
je přesunuto (jinými slovy, přesunuto) na začátek souboru. To znamená, že bez ohledu na to, kam jej umístíte (do beforeEach
nebo test
), bude vždy vyvoláno dříve.
To také znamená, že nemůžete použít žádné proměnné uvnitř factory, které jsou definovány mimo factory.
Pokud potřebujete použít proměnné uvnitř factory, zkuste vi.doMock
. Funguje to stejně, ale není to přesunuto nahoru. Upozorňujeme, že mockuje pouze následující importy.
Můžete také odkazovat na proměnné definované metodou vi.hoisted
, pokud byla deklarována před vi.mock
:
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
Pokud mockujete modul s výchozím exportem, budete muset zadat klíč default
v rámci vráceného objektu factory funkce. Toto je specifický rys ES modulů; proto se dokumentace jest
může lišit, protože jest
používá moduly CommonJS. Například,
vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
// atd...
};
});
Pokud vedle souboru, který mockujete, existuje složka __mocks__
a není zadána žádná factory, Vitest se pokusí najít soubor se stejným názvem v podsložce __mocks__
a použít jej jako skutečný modul. Pokud mockujete závislost, Vitest se pokusí najít složku __mocks__
v kořeni projektu (výchozí je process.cwd()
). Můžete říct Vitestu, kde se nacházejí závislosti, prostřednictvím konfigurační možnosti deps.moduleDirectories.
Například máte tuto strukturu souborů:
- __mocks__
- axios.js
- src
__mocks__
- increment.js
- increment.js
- tests
- increment.test.js
Pokud v testovacím souboru zavoláte vi.mock
bez poskytnuté factory, najde soubor ve složce __mocks__
, který se použije jako modul:
// increment.test.js
import { vi } from 'vitest';
// axios je výchozí export z `__mocks__/axios.js`
import axios from 'axios';
// increment je pojmenovaný export z `src/__mocks__/increment.js`
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
Pozor, pokud nezavoláte vi.mock
, moduly nebudou automaticky mockovány. Chcete-li replikovat chování automatického mockování Jestu, můžete zavolat vi.mock
pro každý požadovaný modul uvnitř setupFiles
.
Pokud neexistuje složka __mocks__
nebo poskytnutá factory, Vitest importuje původní modul a automaticky mockuje všechny jeho exporty. Pro použitá pravidla viz algoritmus.
vi.doMock
- Typ:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
Stejné jako vi.mock
, ale není přesunuto na začátek souboru, takže můžete odkazovat na proměnné v globálním oboru. Další dynamický import modulu bude mockován.
WARNING
Toto nebude mockovat moduly, které byly importovány před tímto voláním. Nezapomeňte, že všechny statické importy v ESM jsou vždy přesunuty nahoru, takže umístění tohoto před statický import jej nenutí, aby byl volán před importem:
vi.doMock('./increment.js'); // toto bude voláno _po_ příkazu import
import { increment } from './increment.js';
// ./increment.js
export function increment(number) {
return number + 1;
}
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';
// modul není mockován, protože vi.doMock ještě nebyl volán
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// můžete přistupovat k proměnným uvnitř factory
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('import dalšího modulu importuje mockovaný modul', async () => {
// původní import NEBYL MOCKOVÁN, protože vi.doMock je vyhodnocen PO importech
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// nový dynamický import vrací mockovaný modul
expect(mockedIncrement(1)).toBe(101);
expect(mockedIncrement(1)).toBe(102);
expect(mockedIncrement(1)).toBe(103);
});
vi.mocked
- Typ:
<T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>
- Typ:
<T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>
Pomocník pro typy pro TypeScript. Vrací objekt, který byl předán.
Když je partial
true
, očekává Partial<T>
jako návratovou hodnotu. Ve výchozím nastavení to způsobí, že TypeScript bude věřit, že jsou mockovány pouze hodnoty první úrovně. Můžete předat { deep: true }
jako druhý argument a říct TypeScriptu, že je mockován celý objekt, pokud tomu tak skutečně je.
import example from './example.js';
vi.mock('./example.js');
test('1 + 1 se rovná 10', async () => {
vi.mocked(example.calc).mockReturnValue(10);
expect(example.calc(1, '+', 1)).toBe(10);
});
vi.importActual
- Typ:
<T>(path: string) => Promise<T>
Importuje modul, obchází všechny kontroly, zda by měl být mockován. Může být užitečné, pokud chcete modul mockovat částečně.
vi.mock('./example.js', async () => {
const axios = await vi.importActual('./example.js');
return { ...axios, get: vi.fn() };
});
vi.importMock
- Typ:
<T>(path: string) => Promise<MaybeMockedDeep<T>>
Importuje modul se všemi jeho vlastnostmi (včetně vnořených vlastností) mockovanými. Dodržuje stejná pravidla jako vi.mock
. Pro použitá pravidla viz algoritmus.
vi.unmock
- Typ:
(path: string) => void
Odebere modul z mockovaného registru. Všechna volání importu vrátí původní modul, i když byl dříve mockován. Protože je toto volání přesunuto na začátek souboru, odmockuje pouze moduly, které byly definovány například v setupFiles
.
vi.doUnmock
- Typ:
(path: string) => void
Stejné jako vi.unmock
, ale není přesunuto na začátek souboru. Další import modulu importuje původní modul místo mocku. Toto nemá vliv na dříve importované moduly.
// ./increment.js
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// increment je již mockován, protože vi.mock je přesunuto nahoru
increment(1) === 100;
// toto je přesunuto nahoru a factory je volána před importem na řádku 1
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// všechna volání jsou mockována a `increment` vždy vrací 100
increment(1) === 100;
increment(30) === 100;
// toto není přesunuto nahoru, takže jiný import vrátí odmockovaný modul
vi.doUnmock('./increment.js');
// toto STÁLE vrací 100, protože `vi.doUnmock` nepřehodnocuje modul
increment(1) === 100;
increment(30) === 100;
// další import je odmockován, nyní je `increment` původní funkce, která vrací count + 1
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- Typ:
() => Vitest
Resetuje registr modulů tím, že vymaže jejich cache. To umožňuje přehodnocení modulů při opětovném importu. Importy nejvyšší úrovně nelze přehodnotit. Může být užitečné izolovat moduly, kde lokální stav způsobuje konflikty mezi testy.
import { vi } from 'vitest';
import { data } from './data.js'; // Nebude přehodnoceno beforeEach test
beforeEach(() => {
vi.resetModules();
});
test('změna stavu', async () => {
const mod = await import('./some/path.js'); // Bude přehodnoceno
mod.changeLocalState('new value');
expect(mod.getLocalState()).toBe('new value');
});
test('modul má starý stav', async () => {
const mod = await import('./some/path.js'); // Bude přehodnoceno
expect(mod.getLocalState()).toBe('old value');
});
WARNING
Neresetuje registr mocků. Chcete-li vymazat registr mocků, použijte vi.unmock
nebo vi.doUnmock
.
vi.dynamicImportSettled
Počkejte, až se načtou všechny dynamické importy. Užitečné, pokud máte synchronní volání, které začne importovat modul, na který jinak nemůžete čekat.
import { expect, test } from 'vitest';
// nelze sledovat import, protože Promise není vrácena
function renderComponent() {
import('./component.js').then(({ render }) => {
render();
});
}
test('operace jsou vyřešeny', async () => {
renderComponent();
await vi.dynamicImportSettled();
expect(document.querySelector('.component')).not.toBeNull();
});
TIP
Pokud je během dynamického importu zahájen jiný dynamický import, tato metoda počká, dokud nebudou všechny vyřešeny.
Tato metoda také počká na další setTimeout
tick po vyřešení importu, takže všechny synchronní operace by měly být dokončeny do doby, než bude vyřešen.
Mockování funkcí a objektů
Tato sekce popisuje, jak pracovat s mocky metod a nahradit proměnné prostředí a globální proměnné.
vi.fn
- Typ:
(fn?: Function) => Mock
Vytvoří spy pro funkci, nebo může být inicializován i bez ní. Pokaždé, když je funkce vyvolána, uloží své argumenty volání, návratové hodnoty a instance. Také můžete manipulovat s jejím chováním pomocí metod. Pokud není zadána žádná funkce, mock vrátí undefined
, když je vyvolán.
import { expect, vi } from 'vitest';
// ---cut---
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
- Typ:
(fn: Function) => boolean
Zkontroluje, zda je daný parametr mockovací funkce. Pokud používáte TypeScript, také zúží jeho typ.
vi.clearAllMocks
Zavolá .mockClear()
na všechny špehy. Tím se vymaže historie volání mocků, ale implementace zůstane beze změny.
vi.resetAllMocks
Zavolá .mockReset()
na všechny špehy. Tím se vymaže historie mocků a resetuje se její implementace na prázdnou funkci (vrátí undefined
).
vi.restoreAllMocks
Zavolá .mockRestore()
na všechny špehy. Tím se vymaže historie mocků a resetuje se její implementace na původní.
vi.spyOn
- Typ:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
Vytvoří spy na metodu nebo getter/setter objektu podobně jako vi.fn()
. Vrací mockovací funkci.
import { expect, vi } from 'vitest';
// ---cut---
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
Můžete zavolat vi.restoreAllMocks
uvnitř afterEach
(nebo povolit test.restoreMocks
), abyste obnovili všechny metody na jejich původní implementace. Tím se obnoví původní deskriptor objektu, takže nebudete moci změnit implementaci metody.
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()); // stále 42!
vi.stubEnv 0.26.0+
- Typ:
(name: string, value: string) => Vitest
Nastaví hodnotu proměnné prostředí v process.env
a import.meta.env
. Můžete obnovit její hodnotu voláním vi.unstubAllEnvs
.
import { vi } from 'vitest';
// `process.env.NODE_ENV` a `import.meta.env.NODE_ENV`
// jsou "development" před voláním "vi.stubEnv"
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
// nemění ostatní envs
import.meta.env.MODE === 'development';
TIP
Hodnotu lze také změnit přímým přiřazením, ale nebudete moci použít vi.unstubAllEnvs
k obnovení předchozí hodnoty:
import.meta.env.MODE = 'test';
vi.unstubAllEnvs 0.26.0+
- Typ:
() => Vitest
Obnoví původní hodnoty v import.meta.env
a process.env
, které byly změněny pomocí vi.stubEnv
. Při prvním volání si Vitest zapamatuje původní hodnotu a uloží ji, dokud není unstubAllEnvs
zavolána znovu.
import { vi } from 'vitest';
// `process.env.NODE_ENV` a `import.meta.env.NODE_ENV`
// jsou "development" před voláním stubEnv
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();
// obnoví hodnotu, která byla uložena před prvním voláním "stubEnv"
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
- Typ:
(name: string | number | symbol, value: unknown) => Vitest
Nastaví hodnotu globální proměnné. Můžete obnovit její původní hodnotu voláním vi.unstubAllGlobals
.
import { vi } from 'vitest';
// `innerWidth` je "0" před voláním stubGlobal
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// pokud používáte jsdom nebo happy-dom
window.innerWidth === 100;
TIP
Hodnotu lze také změnit jednoduše přiřazením k globalThis
nebo window
(pokud používáte prostředí jsdom
nebo happy-dom
), ale nebudete moci použít vi.unstubAllGlobals
k obnovení původní hodnoty:
globalThis.innerWidth = 100;
// pokud používáte jsdom nebo happy-dom
window.innerWidth = 100;
vi.unstubAllGlobals 0.26.0+
- Typ:
() => Vitest
Obnoví všechny globální hodnoty na globalThis
/global
(a window
/top
/self
/parent
, pokud používáte prostředí jsdom
nebo happy-dom
), které byly změněny pomocí vi.stubGlobal
. Při prvním volání si Vitest zapamatuje původní hodnotu a uloží ji, dokud není unstubAllGlobals
zavolána znovu.
import { vi } from 'vitest';
const Mock = vi.fn();
// IntersectionObserver je "undefined" před voláním "stubGlobal"
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// pokud používáte jsdom nebo happy-dom
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// vyvolá ReferenceError, protože není definován
IntersectionObserver === undefined;
Fake Timers
Tato sekce popisuje, jak používat falešné časovače.
vi.advanceTimersByTime
- Typ:
(ms: number) => Vitest
Tato metoda posune čas ve všech spuštěných časovačích o zadaný počet milisekund, nebo dokud není fronta časovačů prázdná, podle toho, co nastane dříve.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersByTime(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersByTimeAsync
- Typ:
(ms: number) => Promise<Vitest>
Tato metoda asynchronně posune čas ve všech spuštěných časovačích o zadaný počet milisekund, nebo dokud není fronta časovačů prázdná, podle toho, co nastane dříve. Zahrnuje i asynchronně nastavené časovače.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersByTimeAsync(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersToNextTimer
- Typ:
() => Vitest
Spustí nejbližší naplánovaný časovač. To je užitečné pro provádění kontrol mezi jednotlivými spuštěními časovačů. Můžete jej řetězit a spravovat časovače ručně.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer(); // log: 3
vi.advanceTimersToNextTimerAsync
- Typ:
() => Promise<Vitest>
Spustí nejbližší naplánovaný časovač a počká na jeho dokončení, pokud byl nastaven asynchronně. Užitečné pro provádění kontrol mezi jednotlivými spuštěními časovače.
import { expect, vi } from 'vitest';
// ---cut---
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.getTimerCount
- Typ:
() => number
Vrací počet aktuálně čekajících časovačů.
vi.clearAllTimers
Zruší všechny časovače, které jsou naplánované ke spuštění. Tyto časovače se již nikdy nespustí.
vi.getMockedSystemTime
- Typ:
() => Date | null
Vrací simulované aktuální datum, které bylo nastaveno pomocí setSystemTime
. Pokud datum není simulované, metoda vrátí null
.
vi.getRealSystemTime
- Typ:
() => number
Při použití vi.useFakeTimers
jsou volání Date.now
simulována. Pokud potřebujete získat reálný čas v milisekundách, můžete zavolat tuto funkci.
vi.runAllTicks
- Typ:
() => Vitest
Spustí všechny mikrotasky zařazené do fronty pomocí process.nextTick
. Tím se také spustí všechny mikrotasky naplánované těmito mikrotaskami.
vi.runAllTimers
- Typ:
() => Vitest
Tato metoda spustí všechny spuštěné časovače, dokud není fronta časovačů prázdná. To znamená, že se spustí každý časovač volaný během runAllTimers
. Pokud máte nekonečný interval, vyvolá výjimku po 10 000 pokusech (lze konfigurovat pomocí fakeTimers.loopLimit
).
import { vi } from 'vitest';
// ---cut---
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
- Typ:
() => Promise<Vitest>
Tato metoda asynchronně spustí všechny spuštěné časovače, dokud není fronta časovačů prázdná, včetně asynchronních časovačů. Pokud máte nekonečný interval, vyvolá výjimku po 10 000 pokusech (lze konfigurovat pomocí fakeTimers.loopLimit
).
import { vi } from 'vitest';
// ---cut---
setTimeout(async () => {
console.log(await Promise.resolve('result'));
}, 100);
await vi.runAllTimersAsync();
// log: result
vi.runOnlyPendingTimers
- Typ:
() => Vitest
Tato metoda spustí pouze ty časovače, které byly naplánovány po volání vi.useFakeTimers
. Nespustí žádný časovač spuštěný během tohoto volání.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- Typ:
() => Promise<Vitest>
Tato metoda asynchronně spustí pouze ty časovače, které byly naplánovány po volání vi.useFakeTimers
, včetně asynchronních. Nespustí žádný časovač spuštěný během tohoto volání.
import { vi } from 'vitest';
// ---cut---
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
- Typ:
(date: string | number | Date) => void
Pokud jsou povoleny falešné časovače, tato metoda simuluje změnu systémového času uživatelem (ovlivní API související s datem, jako je hrtime
, performance.now
nebo new Date()
) - nicméně nespustí žádné časovače. Pokud falešné časovače nejsou povoleny, tato metoda simuluje pouze volání Date.*
.
Užitečné, pokud potřebujete otestovat cokoli, co závisí na aktuálním datu - například volání Luxon uvnitř vašeho kódu.
import { expect, vi } from 'vitest';
// ---cut---
const date = new Date(1998, 11, 19);
vi.useFakeTimers();
vi.setSystemTime(date);
expect(Date.now()).toBe(date.valueOf());
vi.useRealTimers();
vi.useFakeTimers
- Typ:
(config?: FakeTimerInstallOpts) => Vitest
Pro povolení simulace časovačů je nutné zavolat tuto metodu. Přesměruje všechna následující volání časovačů (jako setTimeout
, setInterval
, clearTimeout
, clearInterval
, setImmediate
, clearImmediate
a Date
) na falešné implementace, dokud není zavolána metoda vi.useRealTimers()
.
Mockování nextTick
není podporováno při spuštění Vitest uvnitř node:child_process
pomocí --pool=forks
. NodeJS používá process.nextTick
interně v node:child_process
a při mockování dojde k zablokování. Simulace nextTick
je podporována při spuštění Vitest s --pool=threads
.
Implementace je interně založena na @sinonjs/fake-timers
.
TIP
Od verze 0.35.0
vi.useFakeTimers()
již automaticky nesimuluje process.nextTick
. Stále jej lze simulovat zadáním možnosti v argumentu toFake
: vi.useFakeTimers({ toFake: ['nextTick'] })
.
vi.isFakeTimers 0.34.5+
- Typ:
() => boolean
Vrací true
, pokud jsou povoleny falešné časovače.
vi.useRealTimers
- Typ:
() => Vitest
Po použití falešných časovačů můžete zavolat tuto metodu a obnovit původní implementace časovačů. Všechny časovače, které byly naplánovány dříve, budou zrušeny.
Různé
Sada užitečných pomocných funkcí, které Vitest poskytuje.
vi.waitFor 0.34.5+
- Typ:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
Čeká, dokud se zpětné volání úspěšně neprovede. Pokud zpětné volání vyvolá chybu nebo vrátí odmítnutý slib, bude čekat, dokud se nepodaří nebo nevyprší časový limit.
To je velmi užitečné, když potřebujete počkat na dokončení asynchronní akce, například spuštění serveru.
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';
test('Server started successfully', async () => {
const server = createServer();
await vi.waitFor(
() => {
if (!server.isReady) throw new Error('Server not started');
console.log('Server started');
},
{
timeout: 500, // výchozí hodnota je 1000
interval: 20, // výchozí hodnota je 50
}
);
expect(server.isReady).toBe(true);
});
Funguje to také pro asynchronní zpětná volání
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';
test('Element exists in a DOM', async () => {
// start populating DOM
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// try to get the element until it exists
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // výchozí hodnota je 1000
interval: 20, // výchozí hodnota je 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
Pokud je použito vi.useFakeTimers
, vi.waitFor
automaticky volá vi.advanceTimersByTime(interval)
při každém spuštění zpětného volání.
vi.waitUntil 0.34.5+
- Typ:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
To je podobné jako vi.waitFor
, ale pokud zpětné volání vyvolá nějaké chyby, provádění se okamžitě přeruší a obdrží se chybová zpráva. Pokud zpětné volání vrátí hodnotu vyhodnocenou jako false, další kontrola bude pokračovat, dokud se nevrátí hodnota vyhodnocená jako true. To je užitečné, když potřebujete počkat, až něco existuje, než provedete další krok.
Podívejte se na příklad níže. Můžeme použít vi.waitUntil
k čekání na zobrazení prvku na stránce a poté můžeme s prvkem něco udělat.
import { expect, test, vi } from 'vitest';
test('Element render correctly', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // výchozí hodnota je 1000
interval: 20, // výchozí hodnota je 50
});
// do something with the element
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted 0.31.0+
- Typ:
<T>(factory: () => T) => T
Všechny statické příkazy import
v ES modulech jsou přesunuty na začátek souboru, takže jakýkoli kód definovaný před importy bude ve skutečnosti proveden až po vyhodnocení importů.
Může být užitečné vyvolat některé vedlejší účinky, například simulaci dat před importem modulu.
Chcete-li toto omezení obejít, můžete přepsat statické importy na dynamické, jako je tento:
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
Při spuštění vitest
to můžete udělat automaticky pomocí metody vi.hoisted
.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
Tato metoda vrací hodnotu, která byla vrácena z továrny. Tuto hodnotu můžete použít ve svých továrnách vi.mock
, pokud potřebujete snadný přístup k lokálně definovaným proměnným:
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);
Všimněte si, že tuto metodu lze také volat asynchronně, i když vaše prostředí nepodporuje await nejvyšší úrovně:
const promised = await vi.hoisted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
});
vi.setConfig
- Typ:
RuntimeConfig
Aktualizuje konfiguraci pro aktuální testovací soubor. Tato metoda podporuje pouze možnosti konfigurace, které ovlivní aktuální testovací soubor:
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// supports the whole object
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// supports only "sequence.hooks"
},
});
vi.resetConfig
- Typ:
RuntimeConfig
Pokud byla dříve volána funkce vi.setConfig
, obnoví se tím původní konfigurace.