Vi
Vitest poskytuje pomocné funkce, které jsou dostupné prostřednictvím globálního pomocníka vi
. Můžete k němu přistupovat globálně (pokud je povolena globální konfigurace), 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ů. Mějte na paměti, že Vitest nepodporuje mockování modulů importovaných pomocí require()
.
vi.mock
- Typ:
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Typ:
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
Nahradí všechny importované moduly z poskytnuté path
jiným modulem. V cestě můžete použít nakonfigurované Vite aliasy. Volání vi.mock
je hoistováno, takže nezáleží na tom, kde ho zavoláte. Vždy bude provedeno před všemi importy. Pokud potřebujete odkazovat na některé proměnné mimo jeho rozsah, můžete je definovat uvnitř vi.hoisted
a odkazovat na ně uvnitř vi.mock
.
WARNING
vi.mock
funguje pouze pro moduly, které byly importovány klíčovým slovem import
. Nefunguje s require
.
Aby bylo možné vi.mock
hoistovat, Vitest staticky analyzuje vaše soubory. To znamená, že vi
, které nebylo přímo importováno z balíčku vitest
(například z nějakého pomocného souboru), nelze použít. 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ř inicializačního souboru, protože jsou v době spuštění testovacího souboru již cachovány. Můžete zavolat vi.resetModules()
uvnitř vi.hoisted
pro vymazání všech cachovaných modulů před spuštěním testovacího souboru.
Pokud je definována funkce factory
, všechny importy vrátí její výsledek. Vitest volá factory pouze jednou a cachuje výsledky pro všechny následné importy, dokud není zavoláno vi.unmock
nebo vi.doUnmock
.
Na rozdíl od jest
může být factory asynchronní. Můžete použít vi.importActual
nebo pomocnou funkci s factory předanou jako první argument a získat původní modul uvnitř.
Můžete také poskytnout objekt s vlastností spy
namísto factory funkce. Pokud je spy
true
, pak Vitest automockuje modul jako obvykle, ale nepřepíše implementaci exportů. To je užitečné, pokud chcete pouze ověřit, že exportovaná metoda byla správně volána jinou metodou.
import { calculator } from './src/calculator.ts';
vi.mock('./src/calculator.ts', { spy: true });
// volá původní implementaci,
// ale umožňuje pozdější ověření chování
const result = calculator(1, 2);
expect(result).toBe(3);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);
Vitest také podporuje promise modulu namísto řetězce v metodách vi.mock
a vi.doMock
pro lepší podporu IDE. Když je soubor přesunut, cesta se aktualizuje a importOriginal
automaticky zdědí typ. Použití této signatury také vynutí, aby návratový typ factory byl kompatibilní s původním modulem (při zachování volitelných exportů).
// @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(); // typ je odvozen
// ^?
return {
...mod,
// nahradit některé exporty
total: vi.fn(),
};
});
Pod kapotou Vitest stále pracuje s řetězcem, nikoli s objektem modulu.
Pokud však používáte TypeScript s aliasy paths
nakonfigurovanými v tsconfig.json
, kompilátor nebude schopen správně vyřešit typy importů. Aby to fungovalo, ujistěte se, že nahradíte všechny aliasované importy jejich odpovídajícími relativními cestami. Např. použijte import('./path/to/module.js')
namísto import('@/module')
.
WARNING
vi.mock
je hoistován (jinými slovy, přesunut) na začátek souboru. To znamená, že kdykoli ho napíšete (ať už uvnitř beforeEach
nebo test
), bude skutečně volán předtím.
To také znamená, že uvnitř factory nemůžete použít žádné proměnné, které jsou definovány mimo factory.
Pokud potřebujete použít proměnné uvnitř factory, zkuste vi.doMock
. Funguje to stejně, ale není hoistováno. Mějte na paměti, že mockuje pouze následné 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 poskytnout klíč default
v objektu vrácené factory funkce. Toto je specifická vlastnost pro moduly ES; 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 existuje složka __mocks__
vedle souboru, který mockujete, a factory není poskytnuta, 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()
). Vitestu můžete sdělit, kde se závislosti nacházejí, pomocí 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 zavoláte vi.mock
v testovacím souboru bez poskytnuté factory nebo možností, najde soubor ve složce __mocks__
, který bude použit jako modul:
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
Mějte na paměti, že pokud nezavoláte vi.mock
, moduly nejsou mockovány automaticky. Chcete-li replikovat chování automockování Jestu, můžete zavolat vi.mock
pro každý požadovaný modul uvnitř setupFiles
.
Pokud neexistuje složka __mocks__
nebo není poskytnuta factory, Vitest importuje původní modul a automockuje všechny jeho exporty. Pravidla, která se použijí, naleznete v algoritmu.
vi.doMock
- Typ:
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Typ:
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
Stejné jako vi.mock
, ale není hoistováno na začátek souboru, takže můžete odkazovat na proměnné v globálním rozsahu souboru. Další dynamický import modulu bude mockován.
WARNING
Toto nebude mockovat moduly, které byly importovány předtím, než bylo toto voláno. Nezapomeňte, že všechny statické importy v ESM jsou vždy hoistovány, takže umístění tohoto před statický import nezpůsobí, že bude voláno před importem:
vi.doMock('./increment.js'); // toto bude voláno _po_ příkazu import
import { increment } from './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ě nebylo voláno
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// můžete přistupovat k proměnným uvnitř factory
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('importování dalšího modulu importuje mockovaný modul', async () => {
// původní import NEBYL MOCKOVÁN, protože vi.doMock je vyhodnoceno 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 typu pro TypeScript. Pouze vrátí předaný objekt.
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, abyste TypeScriptu řekli, že je mockován celý objekt, pokud tomu tak skutečně je.
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 se rovná 10', async () => {
vi.mocked(example.add).mockReturnValue(10);
expect(example.add(1, 1)).toBe(10);
});
test('mock návratová hodnota s pouze částečně správným typováním', 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 }) // toto je chyba typu
});
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 originalModule = await vi.importActual('./example.js');
return { ...originalModule, 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. Řídí se stejnými pravidly jako vi.mock
. Pravidla, která se použijí, naleznete v algoritmu.
vi.unmock
- Typ:
(path: string | Promise<Module>) => void
Odstraní modul z mockovaného registru. Všechna volání importu vrátí původní modul, i když byl předtím mockován. Toto volání je hoistováno na začátek souboru, takže odmockuje pouze moduly, které byly definovány například v setupFiles
.
vi.doUnmock
- Typ:
(path: string | Promise<Module>) => void
Stejné jako vi.unmock
, ale není hoistováno na začátek souboru. Další import modulu importuje původní modul namísto mocku. Toto neodmockuje dříve importované moduly.
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// increment je již mockován, protože vi.mock je hoistováno
increment(1) === 100;
// toto je hoistováno 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í hoistováno, takže jiný import vrátí neodmockovaný 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 neodmockován, nyní `increment` je 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ů vymazáním cache všech modulů. To umožňuje opětovné vyhodnocení modulů při opětovném importu. Importy na nejvyšší úrovni nelze znovu vyhodnotit. Může být užitečné pro izolaci modulů, kde se lokální stav střetává mezi testy.
import { vi } from 'vitest';
import { data } from './data.js'; // Nebude znovu vyhodnoceno před každým testem
beforeEach(() => {
vi.resetModules();
});
test('změna stavu', async () => {
const mod = await import('./some/path.js'); // Bude znovu vyhodnoceno
mod.changeLocalState('new value');
expect(mod.getLocalState()).toBe('new value');
});
test('modul má starý stav', async () => {
const mod = await import('./some/path.js'); // Bude znovu vyhodnoceno
expect(mod.getLocalState()).toBe('old value');
});
WARNING
Neresetuje registr mocků. Pro vymazání registru 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 jehož dokončení nelze jinak čekat.
import { expect, test } from 'vitest';
// nelze sledovat import, protože Promise není vrácen
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 se během dynamického importu spustí další dynamický import, tato metoda počká, dokud se všechny nevyřeší.
Tato metoda také počká na další setTimeout
tick poté, co se import vyřeší, takže všechny synchronní operace by měly být dokončeny v době, kdy se vyřeší.
Mockování funkcí a objektů
Tato sekce popisuje, jak pracovat s mocky metod a nahrazovat proměnné prostředí a globální proměnné.
vi.fn
- Typ:
(fn?: Function) => Mock
Vytvoří spy na funkci, i když může být inicializován bez ní. Pokaždé, když je funkce vyvolána, ukládá 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.
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+
- Typ:
<T>(value: T) => MaybeMockedDeep<T>
Hluboce mockuje vlastnosti a metody daného objektu stejným způsobem, jako vi.mock()
mockuje exporty modulů. Podrobnosti viz automockování.
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
- Typ:
(fn: Function) => boolean
Zkontroluje, zda je daný parametr mockovací funkcí. Pokud používáte TypeScript, zúží také jeho typ.
vi.clearAllMocks
Volá .mockClear()
na všech spyích. Tím se vymaže historie mocků bez ovlivnění implementace mocků.
vi.resetAllMocks
Volá .mockReset()
na všech spyích. Tím se vymaže historie mocků a resetuje implementace každého mocku na původní.
vi.restoreAllMocks
Volá .mockRestore()
na všech spyích. Tím se vymaže historie mocků, obnoví všechny původní implementace mocků a obnoví původní deskriptory spied-on objektů.
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()
. Vrátí mockovací funkci.
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
V prostředích, která podporují Explicitní správu zdrojů, můžete použít using
namísto const
k automatickému volání mockRestore
na jakékoli mockované funkci při opuštění obsahujícího bloku. To je obzvláště užitečné pro spied metody:
it('volá console.log', () => {
using spy = vi.spyOn(console, 'log').mockImplementation(() => {})
debug('zpráva')
expect(spy).toHaveBeenCalled()
})
// console.log je zde obnoven
TIP
Můžete zavolat vi.restoreAllMocks
uvnitř afterEach
(nebo povolit test.restoreMocks
) pro obnovení všech metod 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!
TIP
Není možné spy na exportované metody v režimu prohlížeče. Místo toho můžete spy na každou exportovanou metodu voláním vi.mock("./file-path.js", { spy: true })
. Tím se mockuje každý export, ale zachová se jeho implementace, což vám umožní ověřit, zda byla metoda správně volána.
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);
A i když je možné spy na exporty v jsdom
nebo jiných prostředích Node.js, toto se může v budoucnu změnit.
vi.stubEnv
- Typ:
<T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => Vitest
Změní hodnotu proměnné prostředí v process.env
a import.meta.env
. Její hodnotu můžete obnovit 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';
vi.stubEnv('NODE_ENV', undefined);
process.env.NODE_ENV === undefined;
import.meta.env.NODE_ENV === undefined;
// nemění ostatní prostředí
import.meta.env.MODE === 'development';
TIP
Hodnotu můžete také změnit jednoduchým přiřazením, ale nebudete moci použít vi.unstubAllEnvs
k obnovení předchozí hodnoty:
import.meta.env.MODE = 'test';
vi.unstubAllEnvs
- Typ:
() => Vitest
Obnoví všechny hodnoty import.meta.env
a process.env
, které byly změněny pomocí vi.stubEnv
. Když je volána poprvé, Vitest si zapamatuje původní hodnotu a uloží ji, dokud nebude unstubAllEnvs
znovu volána.
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í na 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
Změní hodnotu globální proměnné. Její původní hodnotu můžete obnovit 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 můžete také změnit jednoduchým 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
- 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
. Když je volána poprvé, Vitest si zapamatuje původní hodnotu a uloží ji, dokud nebude unstubAllGlobals
znovu volána.
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;
// vyhodí ReferenceError, protože není definováno
IntersectionObserver === undefined;
Falešné časovače
Tato sekce popisuje, jak pracovat s falešnými časovači.
vi.advanceTimersByTime
- Typ:
(ms: number) => Vitest
Tato metoda vyvolá každý inicializovaný časovač, dokud neuplyne zadaný počet milisekund nebo dokud není fronta prázdná – podle toho, co nastane dříve.
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 vyvolá každý inicializovaný časovač, dokud neuplyne zadaný počet milisekund nebo dokud není fronta prázdná – podle toho, co nastane dříve. To bude zahrnovat asynchronně nastavené časovače.
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
Zavolá další dostupný časovač. Užitečné pro provádění ověření mezi jednotlivými voláními časovače. Můžete jej řetězit a spravovat časovače sami.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer(); // log: 3
vi.advanceTimersToNextTimerAsync
- Typ:
() => Promise<Vitest>
Zavolá další dostupný časovač a počká, dokud se nevyřeší, pokud byl nastaven asynchronně. Užitečné pro provádění ověření mezi jednotlivými voláními časovače.
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+
- Typ:
() => Vitest
Podobně jako vi.advanceTimersByTime
, ale posune časovače o milisekundy potřebné k provedení zpětných volání aktuálně naplánovaných pomocí requestAnimationFrame
.
let frameRendered = false;
requestAnimationFrame(() => {
frameRendered = true;
});
vi.advanceTimersToNextFrame();
expect(frameRendered).toBe(true);
vi.getTimerCount
- Typ:
() => number
Získá počet čekajících časovačů.
vi.clearAllTimers
Odstraní všechny časovače, které jsou naplánovány ke spuštění. Tyto časovače se v budoucnu nikdy nespustí.
vi.getMockedSystemTime
- Typ:
() => Date | null
Vrátí mockované aktuální datum. Pokud datum není mockováno, metoda vrátí null
.
vi.getRealSystemTime
- Typ:
() => number
Při použití vi.useFakeTimers
jsou volání Date.now
mockována. Pokud potřebujete získat skutečný čas v milisekundách, můžete zavolat tuto funkci.
vi.runAllTicks
- Typ:
() => Vitest
Volá každou mikroúlohu, která byla zařazena do fronty pomocí process.nextTick
. Tím se také spustí všechny mikroúlohy naplánované samy sebou.
vi.runAllTimers
- Typ:
() => Vitest
Tato metoda vyvolá každý inicializovaný časovač, dokud není fronta časovačů prázdná. To znamená, že každý časovač volaný během runAllTimers
bude spuštěn. Pokud máte nekonečný interval, vyhodí chybu po 10 000 pokusech (lze konfigurovat pomocí fakeTimers.loopLimit
).
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ě vyvolá každý inicializovaný časovač, dokud není fronta časovačů prázdná. To znamená, že každý časovač volaný během runAllTimersAsync
bude spuštěn, dokonce i asynchronní časovače. Pokud máte nekonečný interval, vyhodí chybu po 10 000 pokusech (lze konfigurovat pomocí fakeTimers.loopLimit
).
setTimeout(async () => {
console.log(await Promise.resolve('result'));
}, 100);
await vi.runAllTimersAsync();
// log: result
vi.runOnlyPendingTimers
- Typ:
() => Vitest
Tato metoda zavolá každý časovač, který byl inicializován po volání vi.useFakeTimers
. Nebude spouštět žádný časovač, který byl inicializován během jejího volání.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- Typ:
() => Promise<Vitest>
Tato metoda asynchronně zavolá každý časovač, který byl inicializován po volání vi.useFakeTimers
, dokonce i asynchronní. Nebude spouštět žádný časovač, který byl inicializován během jejího volání.
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, že uživatel mění systémové hodiny (ovlivní API související s datem, jako hrtime
, performance.now
nebo new Date()
) – nicméně nespustí žádné časovače. Pokud falešné časovače nejsou povoleny, tato metoda bude mockovat pouze volání Date.*
.
Užitečné, pokud potřebujete testovat cokoli, co závisí na aktuálním datu – například volání Luxon ve vašem kódu.
Přijímá stejné řetězcové a číselné argumenty jako Date
.
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í mockování časovačů musíte zavolat tuto metodu. Obalí všechna další volání časovačů (jako setTimeout
, setInterval
, clearTimeout
, clearInterval
, setImmediate
, clearImmediate
a Date
), dokud není zavoláno vi.useRealTimers()
.
Mockování nextTick
není podporováno při spouštění Vitestu uvnitř node:child_process
pomocí --pool=forks
. NodeJS interně používá process.nextTick
v node:child_process
a zamrzne, když je mockováno. Mockování nextTick
je podporováno při spouštění Vitestu s --pool=threads
.
Implementace je interně založena na @sinonjs/fake-timers
.
TIP
vi.useFakeTimers()
automaticky nemockuje process.nextTick
a queueMicrotask
. Můžete to však povolit zadáním možnosti v argumentu toFake
: vi.useFakeTimers({ toFake: ['nextTick', 'queueMicrotask'] })
.
vi.isFakeTimers
- Typ:
() => boolean
Vrátí true
, pokud jsou povoleny falešné časovače.
vi.useRealTimers
- Typ:
() => Vitest
Když časovače doběhly, můžete zavolat tuto metodu, abyste vrátili mockované časovače k jejich původním implementacím. Všechny časovače, které byly naplánovány dříve, budou zahozeny.
Různé
Sada užitečných pomocných funkcí, které Vitest poskytuje.
vi.waitFor
- Typ:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
Počká, dokud se zpětné volání úspěšně neprovede. Pokud zpětné volání vyhodí chybu nebo vrátí zamítnutý slib, bude pokračovat v čekání, dokud se nepodaří nebo nevyprší časový limit.
Pokud jsou možnosti nastaveny na číslo, je to ekvivalentní nastavení { timeout: options }
.
To je velmi užitečné, když potřebujete počkat na dokončení nějaké asynchronní akce, například když spustíte server a potřebujete počkat, než se spustí.
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';
test('Server se úspěšně spustil', async () => {
const server = createServer();
await vi.waitFor(
() => {
if (!server.isReady) {
throw new Error('Server nebyl spuštěn');
}
console.log('Server spuštěn');
},
{
timeout: 500, // výchozí je 1000
interval: 20, // výchozí je 50
}
);
expect(server.isReady).toBe(true);
});
Funguje to i pro asynchronní zpětná volání
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';
test('Element existuje v DOM', async () => {
// začít plnit DOM
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// pokusit se získat element, dokud neexistuje
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // výchozí je 1000
interval: 20, // výchozí je 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
Pokud je použito vi.useFakeTimers
, vi.waitFor
automaticky volá vi.advanceTimersByTime(interval)
v každém zpětném volání kontroly.
vi.waitUntil
- Typ:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
Toto je podobné vi.waitFor
, ale pokud zpětné volání vyhodí jakékoli chyby, provádění je okamžitě přerušeno a je přijata chybová zpráva. Pokud zpětné volání vrátí hodnotu vyhodnocenou jako false, další kontrola bude pokračovat, dokud nebude vrácena hodnota vyhodnocená jako true. To je užitečné, když potřebujete počkat, než něco existuje, než podniknete další krok.
Podívejte se na příklad níže. Můžeme použít vi.waitUntil
k čekání, než se element objeví na stránce, a pak s elementem něco udělat.
import { expect, test, vi } from 'vitest';
test('Element se vykreslí správně', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // výchozí je 1000
interval: 20, // výchozí je 50
});
// něco s elementem udělat
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted
- Typ:
<T>(factory: () => T) => T
Všechny statické příkazy import
v modulech ES jsou hoistovány na začátek souboru, takže jakýkoli kód, který je definován před importy, bude ve skutečnosti proveden po vyhodnocení importů.
Může však být užitečné vyvolat některé vedlejší efekty, jako je mockování dat před importem modulu.
Chcete-li toto omezení obejít, můžete statické importy přepsat na dynamické takto:
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
Při spouštění vitest
to můžete provést automaticky pomocí metody vi.hoisted
. Pod kapotou Vitest převede statické importy na dynamické s zachovanými živými vazbami.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
IMPORTY NEJSOU DOSTUPNÉ
Spuštění kódu před importy znamená, že nemůžete přistupovat k importovaným proměnným, protože ještě nejsou definovány:
import { value } from './some/module.js';
vi.hoisted(() => { value }); // vyhodí chybu
Tento kód vygeneruje chybu:
Nelze přistupovat k '__vi_import_0__' před inicializací
Pokud potřebujete přistupovat k proměnné z jiného modulu uvnitř vi.hoisted
, použijte dynamický import:
await vi.hoisted(async () => {
const { value } = await import('./some/module.js');
});
Nicméně, nedoporučuje se importovat cokoli uvnitř vi.hoisted
, protože importy jsou již hoistovány – pokud potřebujete něco spustit před spuštěním testů, stačí to spustit v samotném importovaném modulu.
Tato metoda vrací hodnotu, která byla vrácena z factory. Tuto hodnotu můžete použít ve svých vi.mock
factories, 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 tato metoda může být volána asynchronně, i když vaše prostředí nepodporuje top-level await:
const json = 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),
// podporuje celý objekt
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// podporuje pouze "sequence.hooks"
},
});
vi.resetConfig
- Typ:
RuntimeConfig
Pokud bylo dříve voláno vi.setConfig
, toto resetuje konfiguraci do původního stavu.