Vi
Vitest udostępnia funkcje narzędziowe za pomocą pomocnika vi
. Możesz uzyskać do niego dostęp globalnie (gdy konfiguracja globals jest włączona), lub zaimportować z vitest
:
import { vi } from 'vitest';
vi.advanceTimersByTime
Typ:
(ms: number) => Vitest
Działa jak
runAllTimers
, ale przesuwa zegar o określoną liczbę milisekund. Na przykład, poniższy kod wypisze1, 2, 3
i nie zgłosi błędu:tslet i = 0; setInterval(() => console.log(++i), 50); vi.advanceTimersByTime(150);
vi.advanceTimersByTimeAsync
Typ:
(ms: number) => Promise<Vitest>
Działa podobnie do
runAllTimersAsync
, ale przesuwa zegar o określoną liczbę milisekund, uwzględniając asynchroniczne timery. Na przykład, poniższy kod wypisze1, 2, 3
i nie zgłosi błędu:tslet i = 0; setInterval(() => Promise.resolve().then(() => console.log(++i)), 50); await vi.advanceTimersByTimeAsync(150);
vi.advanceTimersToNextTimer
Typ:
() => Vitest
Wywołuje następny oczekujący timer. Przydatne przy tworzeniu asercji pomiędzy wywołaniami timerów. Możesz łańcuchowo wywoływać tę funkcję, aby precyzyjnie kontrolować wykonanie timerów.
tslet i = 0; setInterval(() => console.log(++i), 50); vi.advanceTimersToNextTimer() // wypisze 1 .advanceTimersToNextTimer() // wypisze 2 .advanceTimersToNextTimer(); // wypisze 3
vi.advanceTimersToNextTimerAsync
Typ:
() => Promise<Vitest>
Wywołuje następny oczekujący timer, nawet jeśli został ustawiony asynchronicznie. Przydatne do tworzenia asercji między każdym wywołaniem timera. Możesz łańcuchowo wywoływać tę funkcję, aby precyzyjnie kontrolować wykonanie timerów.
tslet i = 0; setInterval(() => Promise.resolve().then(() => console.log(++i)), 50); vi.advanceTimersToNextTimerAsync() // wypisze 1 .advanceTimersToNextTimerAsync() // wypisze 2 .advanceTimersToNextTimerAsync(); // wypisze 3
vi.getTimerCount
Typ:
() => number
Zwraca liczbę oczekujących timerów.
vi.clearAllMocks
Wywołuje .mockClear()
na wszystkich szpiegach (ang. spies). Powoduje to wyczyszczenie historii wywołań mocków, ale nie resetuje ich implementacji do domyślnej.
vi.clearAllTimers
Usuwa wszystkie timery, które są zaplanowane do uruchomienia. Te timery nie zostaną już wykonane.
vi.dynamicImportSettled
Czeka na zakończenie wszystkich dynamicznych importów. Przydatne, gdy masz synchroniczne wywołanie, które inicjuje import modułu i potrzebujesz poczekać na jego zakończenie.
vi.fn
Typ:
(fn?: Function) => Mock
Tworzy szpiega funkcji (ang. function spy), opcjonalnie z początkową implementacją. Za każdym razem, gdy funkcja jest wywoływana, rejestruje argumenty, wartości zwracane i kontekst (
this
). Możesz również manipulować jej zachowaniem za pomocą metod. Jeśli nie podano funkcji, mock zwróciundefined
po wywołaniu.tsconst 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.getMockedSystemTime
Typ:
() => Date | null
Zwraca zamockowaną aktualną datę, która została ustawiona za pomocą
setSystemTime
. Jeśli data nie jest zamockowana, zwrócinull
.
vi.getRealSystemTime
Typ:
() => number
Gdy używasz
vi.useFakeTimers
, wywołaniaDate.now
są zamockowane. Jeśli potrzebujesz uzyskać rzeczywisty czas w milisekundach, możesz wywołać tę funkcję.
vi.hoisted
Typ:
<T>(factory: () => T) => T
Wersja: Od Vitest 0.31.0
Statyczne instrukcje
import
w modułach ES są wynoszone (ang. hoisted) na początek pliku, co oznacza, że kod zdefiniowany przed importami jest wykonywany po obliczeniu importów.Może być jednak konieczne wywołanie pewnych efektów ubocznych, takich jak mockowanie dat, przed zaimportowaniem modułu.
Aby obejść to ograniczenie, możesz przekształcić statyczne importy w dynamiczne:
diffcallFunctionWithSideEffect() - import { value } from './some/module.ts' + const { value } = await import('./some/module.ts')
Podczas uruchamiania
vitest
, możesz to zrobić automatycznie za pomocą metodyvi.hoisted
.diff- callFunctionWithSideEffect() import { value } from './some/module.ts' + vi.hoisted(() => callFunctionWithSideEffect())
Ta metoda zwraca wartość zwróconą przez funkcję fabryczną. Możesz użyć tej wartości w swoich fabrykach
vi.mock
, jeśli potrzebujesz łatwego dostępu do lokalnie zdefiniowanych zmiennych:tsimport { 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);
vi.mock
Typ:
(path: string, factory?: () => unknown) => void
Zastępuje wszystkie importy z
path
innym modułem. Możesz użyć skonfigurowanych aliasów Vite wewnątrz ścieżki. Wywołanievi.mock
jest podnoszone (ang. hoisted), więc jego umiejscowienie w kodzie nie ma znaczenia. Zawsze zostanie wykonane przed wszystkimi importami. Jeśli potrzebujesz odwołać się do zmiennych spoza jego zakresu, możesz zdefiniować je wewnątrzvi.hoisted
i odwołać się do nich wewnątrzvi.mock
.WARNING
vi.mock
działa tylko dla modułów, które zostały zaimportowane za pomocą słowa kluczowegoimport
. Nie działa zrequire
.Vitest statycznie analizuje twoje pliki, aby podnieść
vi.mock
. Oznacza to, że nie możesz używaćvi
, które nie zostało zaimportowane bezpośrednio z pakietuvitest
(na przykład z jakiegoś pliku narzędziowego). Aby to naprawić, zawsze używajvi.mock
zvi
zaimportowanym zvitest
, lub włącz opcję konfiguracjiglobals
.WARNING
Mockowanie modułów nie jest obecnie obsługiwane w trybie przeglądarki. Możesz śledzić postęp w zgłoszeniu na GitHubie.
Jeśli
factory
jest zdefiniowane, wszystkie importy zwrócą jego wynik. Vitest wywołuje fabrykę tylko raz i buforuje wynik dla wszystkich kolejnych importów, dopóki nie zostanie wywołanevi.unmock
lubvi.doUnmock
.W przeciwieństwie do
jest
, fabryka może być asynchroniczna, więc możesz użyćvi.importActual
lub pomocnika, otrzymanego jako pierwszy argument, wewnątrz, aby uzyskać oryginalny moduł.tsvi.mock('./path/to/module.js', async importOriginal => { const mod = await importOriginal(); return { ...mod, // zastąp niektóre eksporty namedExport: vi.fn(), }; });
WARNING
vi.mock
jest podnoszone (innymi słowy, przenoszone) na górę pliku. Oznacza to, że gdziekolwiek je umieścisz (czy to wewnątrzbeforeEach
czytest
), zostanie faktycznie wywołane przed tym.Oznacza to również, że nie można używać w fabryce zmiennych zdefiniowanych poza nią.
Jeśli potrzebujesz użyć zmiennych wewnątrz fabryki, spróbuj
vi.doMock
. Działa tak samo, ale nie jest podnoszone. Pamiętaj, że dotyczy to tylko kolejnych importów.Możesz również odwoływać się do zmiennych zdefiniowanych przez metodę
vi.hoisted
, jeśli została zadeklarowana przedvi.mock
:tsimport { 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
Jeśli mockujesz moduł z eksportem domyślnym (ang. default export), będziesz musiał podać klucz
default
w zwróconym obiekcie funkcji fabrycznej. Jest to specyficzne dla modułów ES, dlatego dokumentacjajest
może się różnić, ponieważjest
używa modułów CommonJS. Na przykład,tsvi.mock('./path/to/module.js', () => { return { default: { myDefaultKey: vi.fn() }, namedExport: vi.fn(), // itd... }; });
Jeśli obok pliku, który mockujesz, znajduje się folder
__mocks__
, a fabryka nie jest dostarczona, Vitest spróbuje znaleźć plik o tej samej nazwie w podfolderze__mocks__
i użyć go jako moduł mockujący. Jeśli mockujesz zależność, Vitest spróbuje znaleźć folder__mocks__
w korzeniu projektu (domyślnie jest toprocess.cwd()
). Możesz poinformować Vitest, gdzie znajdują się zależności, za pomocą opcji konfiguracji deps.moduleDirectories.Na przykład, masz następującą strukturę plików:
- __mocks__ - axios.js - src __mocks__ - increment.js - increment.js - tests - increment.test.js
Jeśli wywołasz
vi.mock
w pliku testowym bez podanej fabryki, znajdzie plik w folderze__mocks__
, który będzie używany jako moduł:ts// increment.test.js import { vi } from 'vitest'; // axios jest eksportem domyślnym z `__mocks__/axios.js` import axios from 'axios'; // increment jest eksportem nazwanym z `src/__mocks__/increment.js` import { increment } from '../increment.js'; vi.mock('axios'); vi.mock('../increment.js'); axios.get(`/apples/${increment(1)}`);
WARNING
Pamiętaj, że jeśli nie wywołasz
vi.mock
, moduły nie są mockowane automatycznie. Aby odtworzyć zachowanie automatycznego mockowania Jest, możesz wywołaćvi.mock
dla każdego wymaganego modułu wewnątrzsetupFiles
.Jeśli nie ma folderu
__mocks__
lub nie podano fabryki, Vitest zaimportuje oryginalny moduł i automatycznie zamockuje wszystkie jego eksporty. Aby zapoznać się z zastosowanymi regułami, zobacz algorytm.
vi.doMock
Typ:
(path: string, factory?: () => unknown) => void
Działa tak samo jak
vi.mock
, ale nie jest podnoszone na górę pliku, więc możesz odwoływać się do zmiennych w globalnym zakresie pliku. Kolejny dynamiczny import modułu zostanie zamockowany. Nie zamockuje to modułów, które zostały zaimportowane przed tym wywołaniem.
// ./increment.js
export function increment(number) {
return number + 1;
}
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';
// moduł nie jest mockowany, bo vi.doMock nie wywołano
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// możesz uzyskać dostęp do zmiennych wewnątrz fabryki
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('importowanie następnego modułu importuje zamockowany', async () => {
// oryginalny import NIE BYŁ ZAMOCKOWANY, ponieważ vi.doMock jest obliczane PO importach
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// nowy dynamiczny import zwraca zamockowany moduł
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>
Pomocnik typu dla TypeScript. W rzeczywistości po prostu zwraca przekazany obiekt.
Gdy
partial
ma wartośćtrue
, oczekujePartial<T>
jako wartości zwrotnej.tsimport example from './example.js'; vi.mock('./example.js'); test('1+1 równa się 2', async () => { vi.mocked(example.calc).mockRestore(); const res = example.calc(1, '+', 1); expect(res).toBe(2); });
vi.importActual
Typ:
<T>(path: string) => Promise<T>
Importuje moduł, pomijając wszystkie mechanizmy mockowania. Może być przydatne, jeśli chcesz zamockować moduł częściowo.
tsvi.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 moduł ze wszystkimi jego właściwościami (w tym właściwościami zagnieżdżonymi) zamockowanymi. Przestrzega tych samych reguł, co
vi.mock
. Aby zapoznać się z zastosowanymi regułami, zobacz algorytm.
vi.resetAllMocks
Wywołuje .mockReset()
na wszystkich szpiegach. Powoduje to wyczyszczenie historii wywołań mocków i zresetowanie ich implementacji do pustej funkcji (zwracającej undefined
).
vi.resetConfig
Typ:
RuntimeConfig
Jeśli wcześniej wywołano
vi.setConfig
, to zresetuje konfigurację do stanu początkowego.
vi.resetModules
Typ:
() => Vitest
Resetuje rejestr modułów, usuwając je z pamięci podręcznej. Pozwala to na ponowną ocenę modułów po ponownym zaimportowaniu. Importy najwyższego poziomu nie mogą być ponownie ocenione. Może być przydatne przy izolowaniu modułów z konfliktami stanu między testami.
tsimport { vi } from 'vitest'; import { data } from './data.js'; // Nie zostanie ponownie ocenione przed każdym testem beforeEach(() => { vi.resetModules(); }); test('zmień stan', async () => { const mod = await import('./some/path.js'); // Zostanie ponownie ocenione mod.changeLocalState('nowa wartość'); expect(mod.getLocalState()).toBe('nowa wartość'); }); test('moduł ma stary stan', async () => { const mod = await import('./some/path.js'); // Zostanie ponownie ocenione expect(mod.getLocalState()).toBe('stara wartość'); });
WARNING
Nie czyści rejestru mocków. Aby wyczyścić rejestr mocków, użyj vi.unmock
lub vi.doUnmock
.
vi.restoreAllMocks
Wywołuje .mockRestore()
na wszystkich szpiegach. Powoduje to wyczyszczenie historii wywołań mocków i przywrócenie oryginalnej implementacji.
vi.stubEnv
Typ:
(name: string, value: string) => Vitest
Wersja: Od Vitest 0.26.0
Ustawia wartość zmiennej środowiskowej w
process.env
iimport.meta.env
. Możesz przywrócić jej pierwotną wartość, wywołującvi.unstubAllEnvs
.
import { vi } from 'vitest';
// `process.env.NODE_ENV` i `import.meta.env.NODE_ENV`
// są "development" przed wywołaniem "vi.stubEnv"
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
// nie zmienia innych zmiennych środowiskowych
import.meta.env.MODE === 'development';
TIP
Możesz również zmienić wartość, po prostu ją przypisując, ale nie będziesz mógł użyć vi.unstubAllEnvs
, aby przywrócić poprzednią wartość:
import.meta.env.MODE = 'test';
vi.unstubAllEnvs
Typ:
() => Vitest
Wersja: Od Vitest 0.26.0
Przywraca oryginalne wartości wszystkich zmiennych środowiskowych (
import.meta.env
iprocess.env
), które zostały zmodyfikowane za pomocąvi.stubEnv
. Vitest zapamiętuje oryginalne wartości przy pierwszym wywołaniuvi.stubEnv
i przechowuje je do momentu wywołaniavi.unstubAllEnvs
.
import { vi } from 'vitest';
// `process.env.NODE_ENV` i `import.meta.env.NODE_ENV`
// mają wartość "development" przed wywołaniem `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();
// przywraca wartość, która była przechowywana przed pierwszym wywołaniem "stubEnv"
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
Typ:
(name: string | number | symbol, value: unknown) => Vitest
Zmienia wartość zmiennej globalnej. Możesz przywrócić jej oryginalną wartość, wywołując
vi.unstubAllGlobals
.
import { vi } from 'vitest';
// `innerWidth` ma wartość "0" przed wywołaniem `stubGlobal`
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// jeśli używasz jsdom lub happy-dom
window.innerWidth === 100;
TIP
Możesz również zmienić wartość, po prostu przypisując ją do globalThis
lub window
(jeśli używasz środowiska jsdom
lub happy-dom
), ale nie będziesz mógł użyć vi.unstubAllGlobals
do przywrócenia oryginalnej wartości:
globalThis.innerWidth = 100;
// jeśli używasz jsdom lub happy-dom
window.innerWidth = 100;
vi.unstubAllGlobals
Typ:
() => Vitest
Wersja: Od Vitest 0.26.0
Przywraca oryginalne wartości wszystkich zmiennych globalnych w
globalThis
/global
(iwindow
/top
/self
/parent
, jeśli używasz środowiskajsdom
lubhappy-dom
), które zostały zmodyfikowane za pomocąvi.stubGlobal
. Vitest zapamiętuje oryginalne wartości przy pierwszym wywołaniuvi.stubGlobal
i przechowuje je do momentu wywołaniavi.unstubAllGlobals
.
import { vi } from 'vitest';
const Mock = vi.fn();
// IntersectionObserver jest "undefined" przed wywołaniem "stubGlobal"
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// jeśli używasz jsdom lub happy-dom
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// wyrzuca ReferenceError, ponieważ nie jest zdefiniowany
IntersectionObserver === undefined;
vi.runAllTicks
Typ:
() => Vitest
Wykonuje wszystkie mikrozadania (microtasks) umieszczone w kolejce przez
process.nextTick
. Spowoduje to również uruchomienie wszystkich mikrozadań zaplanowanych przez te mikrozadania.
vi.runAllTimers
Typ:
() => Vitest
Ta metoda wywołuje wszystkie zainicjowane timery, dopóki kolejka timerów nie będzie pusta. Oznacza to, że każdy timer wywołany podczas
runAllTimers
zostanie również uruchomiony. Jeśli masz nieskończony interwał, zostanie zgłoszony wyjątek po 10 000 próbach. Na przykład, poniższy kod wyświetli1, 2, 3
:tslet i = 0; setTimeout(() => console.log(++i)); const interval = setInterval(() => { console.log(++i); if (i === 3) clearInterval(interval); }, 50); vi.runAllTimers();
vi.runAllTimersAsync
Typ:
() => Promise<Vitest>
Ta metoda asynchronicznie wywołuje wszystkie zainicjowane timery, dopóki kolejka timerów nie będzie pusta. Oznacza to, że każdy timer wywołany podczas
runAllTimersAsync
zostanie również uruchomiony, nawet timery asynchroniczne. Jeśli masz nieskończony interwał, zostanie zgłoszony wyjątek po 10 000 próbach. Na przykład, poniższy kod wyświetliresult
:tssetTimeout(async () => { console.log(await Promise.resolve('result')); }, 100); await vi.runAllTimersAsync();
vi.runOnlyPendingTimers
Typ:
() => Vitest
Ta metoda wywołuje tylko te timery, które zostały zainicjowane po wywołaniu
vi.useFakeTimers()
. Nie uruchomi żadnego timera, który został zainicjowany podczas jej wywołania. Na przykład, poniższy kod wyświetli tylko1
:tslet i = 0; setInterval(() => console.log(++i), 50); vi.runOnlyPendingTimers();
vi.runOnlyPendingTimersAsync
Typ:
() => Promise<Vitest>
Ta metoda asynchronicznie wywołuje tylko te timery, które zostały zainicjowane po wywołaniu
vi.useFakeTimers()
, włącznie z timerami asynchronicznymi. Nie uruchomi żadnego timera, który został zainicjowany podczas jej wywołania. Na przykład, poniższy kod wyświetli2, 3, 3, 1
:tssetTimeout(() => { console.log(1); }, 100); setTimeout(() => { Promise.resolve().then(() => { console.log(2); setInterval(() => { console.log(3); }, 40); }); }, 10); await vi.runOnlyPendingTimersAsync();
vi.setSystemTime
Typ:
(date: string | number | Date) => void
Ustawia bieżącą datę na przekazaną wartość. Wszystkie wywołania
Date
będą zwracać tę datę.Przydatne, jeśli musisz przetestować kod, który zależy od bieżącej daty - na przykład wywołania luxon wewnątrz twojego kodu.
tsconst date = new Date(1998, 11, 19); vi.useFakeTimers(); vi.setSystemTime(date); expect(Date.now()).toBe(date.valueOf()); vi.useRealTimers();
vi.setConfig
Typ:
RuntimeConfig
Aktualizuje konfigurację dla bieżącego pliku testowego. Możesz wpływać tylko na wartości, które są używane podczas wykonywania testów.
vi.spyOn
Typ:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
Tworzy szpiega (spy) na metodzie lub getterze/setterze obiektu.
tslet apples = 0; const cart = { getApples: () => 13, }; const spy = vi.spyOn(cart, 'getApples').mockImplementation(() => apples); apples = 1; expect(cart.getApples()).toBe(1); expect(spy).toHaveBeenCalled(); expect(spy).toHaveReturnedWith(1);
vi.stubGlobal
Typ:
(key: keyof globalThis & Window, value: any) => Vitest
Umieszcza wartość w zmiennej globalnej. Jeśli używasz
jsdom
lubhappy-dom
, umieszcza również wartość w obiekciewindow
.Przeczytaj więcej w sekcji „Mockowanie zmiennych globalnych”.
vi.unmock
Typ:
(path: string) => void
Usuwa moduł z mockowanego rejestru. Wszystkie wywołania importu zwrócą oryginalny moduł, nawet jeśli był wcześniej mockowany. To wywołanie jest przesuwane (ang. hoisted) na początek pliku, więc odmockuje tylko moduły zdefiniowane na przykład w
setupFiles
.
vi.doUnmock
Typ:
(path: string) => void
To samo co
vi.unmock
, ale nie jest podnoszone (hoisted) na górę pliku. Następny import modułu zaimportuje oryginalny moduł zamiast mocka. Nie spowoduje to odmockowania wcześniej zaimportowanych modułów.
// ./increment.js
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// increment jest już mockowany, ponieważ vi.mock jest podnoszone (hoisted)
increment(1) === 100;
// to jest podnoszone (hoisted), a fabryka jest wywoływana przed importem w linii 1
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// wszystkie wywołania są mockowane, a `increment` zawsze zwraca 100
increment(1) === 100;
increment(30) === 100;
// to nie jest podnoszone (hoisted), więc inny import zwróci niemockowany moduł
vi.doUnmock('./increment.js');
// to WCIĄŻ zwraca 100, ponieważ `vi.doUnmock` nie przelicza modułu
increment(1) === 100;
increment(30) === 100;
// następny import jest niemockowany, teraz `increment` jest oryginalną funkcją, która zwraca count + 1
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.useFakeTimers
Typ:
() => Vitest
Aby włączyć mockowanie timerów, musisz wywołać tę metodę. Spowoduje to mockowanie wszystkich kolejnych wywołań funkcji związanych z czasem (takich jak
setTimeout
,setInterval
,clearTimeout
,clearInterval
,nextTick
,setImmediate
,clearImmediate
iDate
) do momentu wywołaniavi.useRealTimers()
.Symulowanie
nextTick
nie jest obsługiwane podczas uruchamiania Vitest wewnątrznode:child_process
za pomocą--no-threads
. NodeJS używaprocess.nextTick
wewnętrznie wnode:child_process
i zawiesza się, gdy jest mockowany. MockowanienextTick
jest obsługiwane podczas uruchamiania Vitest z--threads
.Implementacja opiera się wewnętrznie na
@sinonjs/fake-timers
.TIP
Od wersji
0.35.0
vi.useFakeTimers()
nie mockuje już automatycznieprocess.nextTick
. Można go nadal mockować, określając opcję w argumencietoFake
:vi.useFakeTimers({ toFake: ['nextTick'] })
.
vi.isFakeTimers
Typ:
() => boolean
Wersja: Od Vitest 0.34.5
Zwraca
true
, jeśli włączone jest mockowanie timerów.
vi.useRealTimers
Typ:
() => Vitest
Po zakończeniu korzystania z mockowanych timerów, możesz wywołać tę metodę, aby przywrócić oryginalne implementacje timerów. Wszystkie timery, które zostały uruchomione wcześniej, nie zostaną przywrócone.
vi.waitFor
- Typ:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
- Wersja: Od Vitest 0.34.5
Czeka na pomyślne wykonanie callbacku. Jeśli funkcja zwrotna zgłosi błąd lub zwróci odrzuconą obietnicę, funkcja będzie kontynuować czekanie, aż operacja się powiedzie lub upłynie limit czasu.
Jest to bardzo przydatne, gdy trzeba poczekać na zakończenie działania asynchronicznego, na przykład, gdy uruchamiasz serwer i musisz poczekać na jego uruchomienie.
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, // domyślnie 1000
interval: 20, // domyślnie 50
}
);
expect(server.isReady).toBe(true);
});
Działa również dla asynchronicznych callbacków
// @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 () => {
// próbuj pobrać element, aż zostanie znaleziony
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // domyślnie 1000
interval: 20, // domyślnie 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
Jeśli używany jest vi.useFakeTimers
, vi.waitFor
automatycznie wywołuje vi.advanceTimersByTime(interval)
w każdym callbacku sprawdzającym.
vi.waitUntil
- Typ:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
- Wersja: Od Vitest 0.34.5
Jest to podobne do vi.waitFor
, ale jeśli callback zgłosi jakiekolwiek błędy, wykonanie jest natychmiast przerywane i otrzymywana jest wiadomość o błędzie. Jeśli funkcja zwrotna zwróci wartość fałszywą, kolejne sprawdzenie będzie kontynuowane, aż zostanie zwrócona wartość prawdziwa. Jest to przydatne, gdy trzeba poczekać, aż coś zaistnieje, zanim podejmiesz następny krok.
Spójrz na poniższy przykład. Możemy użyć vi.waitUntil
, aby poczekać, aż element pojawi się na stronie, a następnie możemy coś zrobić z tym elementem.
import { expect, test, vi } from 'vitest';
test('Element render correctly', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // domyślnie 1000
interval: 20, // domyślnie 50
});
// wykonaj operacje na elemencie
expect(element.querySelector('.element-child')).toBeTruthy();
});