Vi
Vitest stellt Hilfsfunktionen über seinen vi
-Helfer bereit. Sie können global darauf zugreifen (wenn die globale Konfiguration aktiviert ist) oder es direkt aus vitest
importieren:
import { vi } from 'vitest';
Module mocken
Dieser Abschnitt beschreibt die API, die Sie beim Mocken eines Moduls verwenden können. Beachten Sie, dass Vitest das Mocken von Modulen, die mit require()
importiert wurden, nicht unterstützt.
vi.mock
- Typ:
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Typ:
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
Ersetzt alle Importe des Moduls vom angegebenen path
durch ein anderes Modul. Sie können konfigurierte Vite-Aliase innerhalb eines Pfades verwenden. Der Aufruf von vi.mock
wird an den Anfang der Datei verschoben (hoisted), sodass es keine Rolle spielt, wo Sie ihn aufrufen. Er wird immer vor allen Importanweisungen ausgeführt. Wenn Sie auf Variablen außerhalb seines Geltungsbereichs zugreifen müssen, können Sie diese innerhalb von vi.hoisted
definieren und innerhalb von vi.mock
darauf verweisen.
WARNING
vi.mock
funktioniert nur für Module, die mit dem import
-Schlüsselwort importiert wurden. Es funktioniert nicht mit require
.
Um vi.mock
an den Anfang der Datei zu verschieben, analysiert Vitest Ihre Dateien statisch. Das bedeutet, dass vi
nicht verwendet werden kann, wenn es nicht direkt aus dem vitest
-Paket importiert wurde (z. B. aus einer Hilfsdatei). Verwenden Sie vi.mock
mit vi
, das aus vitest
importiert wurde, oder aktivieren Sie die Konfigurationsoption globals
.
Vitest mockt keine Module, die in einer Setup-Datei importiert wurden, da diese bereits zwischengespeichert sind, wenn eine Testdatei ausgeführt wird. Sie können vi.resetModules()
innerhalb von vi.hoisted
aufrufen, um alle Modul-Caches zu löschen, bevor eine Testdatei ausgeführt wird.
Wenn die factory
-Funktion definiert ist, geben alle Importe ihr Ergebnis zurück. Vitest ruft die Factory nur einmal auf und verwendet das Ergebnis für alle nachfolgenden Importe, bis vi.unmock
oder vi.doUnmock
aufgerufen wird.
Im Gegensatz zu jest
kann die Factory asynchron sein. Sie können vi.importActual
oder einen Helfer verwenden, dem die Factory als erstes Argument übergeben wird, um das ursprüngliche Modul darin zu erhalten.
Seit Vitest 2.1 können Sie anstelle einer Factory-Funktion auch ein Objekt mit einer spy
-Eigenschaft bereitstellen. Wenn spy
auf true
gesetzt ist, mockt Vitest das Modul wie gewohnt automatisch, behält aber die ursprüngliche Implementierung der Exporte bei. Dies ist nützlich, wenn Sie nur überprüfen möchten, ob eine exportierte Methode von einer anderen Methode korrekt aufgerufen wurde.
import { calculator } from './src/calculator.ts';
vi.mock('./src/calculator.ts', { spy: true });
// ruft die ursprüngliche Implementierung auf,
// ermöglicht aber später die Überprüfung des Verhaltens
const result = calculator(1, 2);
expect(result).toBe(3);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);
Vitest unterstützt auch ein Promise, das ein Modul auflöst, anstelle eines Strings in den Methoden vi.mock
und vi.doMock
für eine bessere IDE-Unterstützung. Wenn die Datei verschoben wird, wird der Pfad aktualisiert, und der Typ von importOriginal
wird automatisch abgeleitet. Die Verwendung dieser Signatur stellt auch sicher, dass der Rückgabetyp der Factory mit dem ursprünglichen Modul kompatibel ist (wobei Exporte optional sein können).
// @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 wird abgeleitet
// ^?
return {
...mod,
// einige Exporte ersetzen
total: vi.fn(),
};
});
Intern arbeitet Vitest weiterhin mit einem String und nicht mit einem Modulobjekt.
Wenn Sie jedoch TypeScript mit in tsconfig.json
konfigurierten paths
-Aliasen verwenden, kann der Compiler die Importtypen möglicherweise nicht korrekt auflösen. Damit dies funktioniert, stellen Sie sicher, dass Sie alle Importe mit Aliasen durch ihre entsprechenden relativen Pfade ersetzen. Verwenden Sie z. B. import('./path/to/module.js')
anstelle von import('@/module')
.
WARNING
vi.mock
wird an den Anfang der Datei verschoben (mit anderen Worten, hochgezogen). Das bedeutet, dass es immer, unabhängig davon, wo Sie es schreiben (sei es innerhalb von beforeEach
oder test
), tatsächlich davor aufgerufen wird.
Das bedeutet auch, dass Sie keine Variablen verwenden können, die außerhalb der Factory definiert sind.
Wenn Sie Variablen innerhalb der Factory verwenden müssen, versuchen Sie vi.doMock
. Es funktioniert auf die gleiche Weise, wird aber nicht an den Anfang der Datei verschoben. Beachten Sie, dass es nur nachfolgende Importe beeinflusst.
Sie können auch auf Variablen verweisen, die durch die Methode vi.hoisted
definiert wurden, sofern diese vor vi.mock
deklariert wurde:
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
Wenn Sie ein Modul mit einem Standardexport mocken, müssen Sie einen default
-Schlüssel innerhalb des zurückgegebenen Factory-Funktionsobjekts bereitstellen. Dies ist eine Besonderheit von ES-Modulen; daher kann die jest
-Dokumentation abweichen, da jest
CommonJS-Module verwendet. Zum Beispiel:
vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
// etc...
};
});
Wenn sich neben einer Datei, die Sie mocken, ein __mocks__
-Ordner befindet und keine Factory bereitgestellt wird, versucht Vitest, eine Datei mit demselben Namen im Unterordner __mocks__
zu finden und diese als tatsächliches Modul zu verwenden. Wenn Sie eine Abhängigkeit mocken, versucht Vitest, einen __mocks__
-Ordner im Stammverzeichnis des Projekts zu finden (Standard ist process.cwd()
). Über die Konfigurationsoption deps.moduleDirectories
können Sie Vitest mitteilen, wo sich die Abhängigkeiten befinden.
Zum Beispiel haben Sie diese Dateistruktur:
- __mocks__
- axios.js
- src
__mocks__
- increment.js
- increment.js
- tests
- increment.test.js
Wenn Sie vi.mock
in einer Testdatei aufrufen, ohne eine Factory oder Optionen bereitzustellen, findet es eine Datei im __mocks__
-Ordner, die als Modul verwendet werden soll:
// increment.test.js
import { vi } from 'vitest';
// axios ist ein Standardexport aus `__mocks__/axios.js`
import axios from 'axios';
// increment ist ein benannter Export aus `src/__mocks__/increment.js`
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
Beachten Sie, dass Module nicht automatisch gemockt werden, wenn Sie vi.mock
nicht aufrufen. Um das Automocking-Verhalten von Jest zu replizieren, können Sie vi.mock
für jedes benötigte Modul innerhalb von setupFiles
aufrufen.
Wenn kein __mocks__
-Ordner oder keine Factory bereitgestellt wird, importiert Vitest das ursprüngliche Modul und mockt automatisch alle seine Exporte. Die angewendeten Regeln finden Sie unter Algorithmus.
vi.doMock
- Typ:
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Typ:
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
Dasselbe wie vi.mock
, wird aber nicht an den Anfang der Datei verschoben, sodass Sie auf Variablen im globalen Dateibereich verweisen können. Der nächste dynamische Import des Moduls wird durch einen Mock ersetzt.
WARNING
Dies beeinflusst keine Module, die vor diesem Aufruf importiert wurden. Vergessen Sie nicht, dass alle statischen Importe in ESM immer an den Anfang der Datei verschoben werden, sodass das Platzieren dieses vor einem statischen Import nicht dazu führt, dass es vor dem Import aufgerufen wird:
vi.doMock('./increment.js'); // dies wird **nach** der Importanweisung aufgerufen
import { increment } from './increment.js';
// ./increment.js
export function increment(number) {
return number + 1;
}
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';
// das Modul ist nicht gemockt, da `vi.doMock` noch nicht aufgerufen wurde
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// Sie können auf Variablen innerhalb einer Factory zugreifen
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('importing the next module imports mocked one', async () => {
// der ursprüngliche Import WURDE NICHT GEMOCKT, da `vi.doMock` NACH den Importen ausgewertet wird
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// neuer dynamischer Import gibt gemocktes Modul zurück
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>
Ein Typ-Helfer für TypeScript. Gibt einfach das übergebene Objekt zurück.
Wenn partial
auf true
gesetzt ist, erwartet es einen Partial<T>
als Rückgabewert. Standardmäßig lässt dies TypeScript nur annehmen, dass die Werte der ersten Ebene gemockt sind. Sie können { deep: true }
als zweites Argument übergeben, um TypeScript mitzuteilen, dass das gesamte Objekt gemockt ist, falls dies zutrifft.
// 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 equals 10', async () => {
vi.mocked(example.add).mockReturnValue(10);
expect(example.add(1, 1)).toBe(10);
});
test('mock return value with only partially correct typing', 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 }) // dies führt zu einem Typfehler
});
vi.importActual
- Typ:
<T>(path: string) => Promise<T>
Importiert ein Modul und umgeht dabei alle Prüfungen, ob es gemockt werden soll. Kann nützlich sein, wenn Sie ein Modul teilweise mocken möchten.
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>>
Importiert ein Modul, bei dem alle Eigenschaften (einschließlich verschachtelter Eigenschaften) gemockt sind. Es folgt denselben Regeln wie vi.mock
. Die angewendeten Regeln finden Sie unter Algorithmus.
vi.unmock
- Typ:
(path: string | Promise<Module>) => void
Entfernt das Modul aus dem Mock-Register. Alle Importaufrufe geben das ursprüngliche Modul zurück, selbst wenn es zuvor gemockt wurde. Dieser Aufruf wird an den Anfang der Datei verschoben, sodass er nur Module entmockt, die beispielsweise in setupFiles
definiert wurden.
vi.doUnmock
- Typ:
(path: string | Promise<Module>) => void
Dasselbe wie vi.unmock
, wird aber nicht an den Anfang der Datei verschoben. Beim nächsten Import des Moduls wird das ursprüngliche Modul anstelle des Mocks importiert. Dies beeinflusst keine zuvor importierten Module.
// ./increment.js
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// increment ist bereits gemockt, da `vi.mock` an den Anfang der Datei verschoben wurde
increment(1) === 100;
// dies wird an den Anfang der Datei verschoben, und die Factory wird vor dem Import in Zeile 1 aufgerufen
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// alle Aufrufe sind gemockt, und `increment` gibt immer 100 zurück
increment(1) === 100;
increment(30) === 100;
// dies wird nicht hochgezogen, sodass ein anderer Import ein ungemocktes Modul zurückgibt
vi.doUnmock('./increment.js');
// dies gibt **immer noch** 100 zurück, da `vi.doUnmock` ein Modul nicht neu auswertet
increment(1) === 100;
increment(30) === 100;
// der nächste Import ist ungemockt, jetzt ist `increment` die ursprüngliche Funktion, die `count + 1` zurückgibt
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- Typ:
() => Vitest
Setzt das Modulregister zurück, indem der Cache aller Module gelöscht wird. Dadurch können Module beim erneuten Import neu ausgewertet werden. Top-Level-Importe können nicht neu ausgewertet werden. Kann nützlich sein, um Module zu isolieren, bei denen lokale Zustände zwischen Tests in Konflikt geraten.
import { vi } from 'vitest';
import { data } from './data.js'; // Wird vor jedem Test nicht neu ausgewertet
beforeEach(() => {
vi.resetModules();
});
test('change state', async () => {
const mod = await import('./some/path.js'); // Wird neu ausgewertet
mod.changeLocalState('new value');
expect(mod.getLocalState()).toBe('new value');
});
test('module has old state', async () => {
const mod = await import('./some/path.js'); // Wird neu ausgewertet
expect(mod.getLocalState()).toBe('old value');
});
WARNING
Setzt das Mock-Register nicht zurück. Um das Mock-Register zu löschen, verwenden Sie vi.unmock
oder vi.doUnmock
.
vi.dynamicImportSettled
Wartet, bis alle dynamischen Importe geladen sind. Nützlich, wenn Sie einen synchronen Aufruf haben, der den Import eines Moduls startet, auf das Sie sonst nicht warten können.
import { expect, test } from 'vitest';
// kann den Import nicht verfolgen, da kein Promise zurückgegeben wird
function renderComponent() {
import('./component.js').then(({ render }) => {
render();
});
}
test('operations are resolved', async () => {
renderComponent();
await vi.dynamicImportSettled();
expect(document.querySelector('.component')).not.toBeNull();
});
TIP
Wenn während eines dynamischen Imports ein weiterer dynamischer Import initiiert wird, wartet diese Methode, bis alle aufgelöst sind.
Diese Methode wartet auch auf den nächsten setTimeout
-Tick, nachdem der Import aufgelöst wurde. Dadurch sollten alle synchronen Operationen abgeschlossen sein, wenn er aufgelöst wird.
Funktionen und Objekte mocken
Dieser Abschnitt beschreibt, wie Sie mit Methoden-Mocks arbeiten und Umgebungs- und globale Variablen ersetzen.
vi.fn
- Typ:
(fn?: Function) => Mock
Erstellt einen Spy auf eine Funktion, kann aber auch ohne eine initialisiert werden. Jedes Mal, wenn eine Funktion aufgerufen wird, speichert sie ihre Aufrufargumente, Rückgabewerte und Instanzen. Sie können ihr Verhalten auch mit Methoden manipulieren. Wenn keine Funktion angegeben ist, gibt der Mock undefined
zurück, wenn er aufgerufen wird.
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
Prüft, ob ein gegebener Parameter eine Mock-Funktion ist. Wenn Sie TypeScript verwenden, wird auch der Typ eingeschränkt.
vi.clearAllMocks
Ruft .mockClear()
für alle Spies auf. Dies löscht den Mock-Verlauf, setzt aber die Implementierung nicht auf die Standardimplementierung zurück.
vi.resetAllMocks
Ruft .mockReset()
für alle Spies auf. Dies löscht den Mock-Verlauf und setzt die Implementierung auf eine leere Funktion zurück (die undefined
zurückgibt).
vi.restoreAllMocks
Ruft .mockRestore()
für alle Spies auf. Dies löscht den Mock-Verlauf und setzt die Implementierung auf die ursprüngliche Implementierung zurück.
vi.spyOn
- Typ:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
Erstellt einen Spy auf eine Methode oder einen Getter/Setter eines Objekts, ähnlich wie vi.fn()
. Es gibt eine Mock-Funktion zurück.
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
Sie können vi.restoreAllMocks
innerhalb von afterEach
aufrufen (oder test.restoreMocks
aktivieren), um alle Methoden auf ihre ursprünglichen Implementierungen zurückzusetzen. Dies stellt den ursprünglichen Objekt-Deskriptor wieder her, sodass Sie die Implementierung der Methode nicht mehr ändern können:
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()); // immer noch 42!
TIP
Es ist nicht möglich, exportierte Methoden im Browser-Modus auszuspionieren. Stattdessen können Sie jede exportierte Methode ausspionieren, indem Sie vi.mock("./file-path.js", { spy: true })
aufrufen. Dies mockt jeden Export, behält aber seine Implementierung intakt, sodass Sie überprüfen können, ob die Methode korrekt aufgerufen wurde.
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);
Und obwohl es möglich ist, Exporte in jsdom
oder anderen Node.js-Umgebungen auszuspionieren, könnte sich dies in Zukunft ändern.
vi.stubEnv
- Typ:
<T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => Vitest
Ändert den Wert einer Umgebungsvariable in process.env
und import.meta.env
. Sie können den Wert wiederherstellen, indem Sie vi.unstubAllEnvs
aufrufen.
import { vi } from 'vitest';
// `process.env.NODE_ENV` und `import.meta.env.NODE_ENV`
// sind "development" vor dem Aufruf von `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;
// ändert andere Umgebungsvariablen nicht
import.meta.env.MODE === 'development';
TIP
Sie können den Wert auch einfach durch Zuweisung ändern, aber Sie können vi.unstubAllEnvs
nicht verwenden, um den vorherigen Wert wiederherzustellen:
import.meta.env.MODE = 'test';
vi.unstubAllEnvs
- Typ:
() => Vitest
Stellt alle import.meta.env
- und process.env
-Werte wieder her, die mit vi.stubEnv
geändert wurden. Wenn es zum ersten Mal aufgerufen wird, merkt sich Vitest den ursprünglichen Wert und speichert ihn, bis unstubAllEnvs
erneut aufgerufen wird.
import { vi } from 'vitest';
// `process.env.NODE_ENV` und `import.meta.env.NODE_ENV`
// sind "development" vor dem Aufruf von `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();
// stellt den Wert wieder her, der vor dem ersten `stubEnv`-Aufruf gespeichert wurde
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
- Typ:
(name: string | number | symbol, value: unknown) => Vitest
Ändert den Wert einer globalen Variable. Sie können ihren ursprünglichen Wert wiederherstellen, indem Sie vi.unstubAllGlobals
aufrufen.
import { vi } from 'vitest';
// `innerWidth` ist "0" vor dem Aufruf von `stubGlobal`
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// wenn Sie `jsdom` oder `happy-dom` verwenden
window.innerWidth === 100;
TIP
Sie können den Wert auch einfach durch Zuweisung an globalThis
oder window
ändern (wenn Sie die jsdom
- oder happy-dom
-Umgebung verwenden). Allerdings können Sie vi.unstubAllGlobals
nicht verwenden, um den ursprünglichen Wert wiederherzustellen:
globalThis.innerWidth = 100;
// wenn Sie `jsdom` oder `happy-dom` verwenden
window.innerWidth = 100;
vi.unstubAllGlobals
- Typ:
() => Vitest
Stellt alle globalen Werte auf globalThis
/global
(und window
/top
/self
/parent
, wenn Sie die jsdom
- oder happy-dom
-Umgebung verwenden) wieder her, die mit vi.stubGlobal
geändert wurden. Wenn es zum ersten Mal aufgerufen wird, merkt sich Vitest den ursprünglichen Wert und speichert ihn, bis unstubAllGlobals
erneut aufgerufen wird.
import { vi } from 'vitest';
const Mock = vi.fn();
// `IntersectionObserver` ist "undefined" vor dem Aufruf von `stubGlobal`
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// wenn Sie `jsdom` oder `happy-dom` verwenden
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// wirft einen ReferenceError, da es nicht definiert ist
IntersectionObserver === undefined;
Fake-Timer
Dieser Abschnitt beschreibt, wie Sie mit Fake-Timern arbeiten.
vi.advanceTimersByTime
- Typ:
(ms: number) => Vitest
Diese Methode ruft jeden initiierten Timer auf, bis die angegebene Anzahl von Millisekunden verstrichen ist oder die Warteschlange leer ist – je nachdem, was zuerst eintritt.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersByTime(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersByTimeAsync
- Typ:
(ms: number) => Promise<Vitest>
Diese Methode ruft jeden initiierten Timer auf, bis die angegebene Anzahl von Millisekunden verstrichen ist oder die Warteschlange leer ist – je nachdem, was zuerst eintritt. Dies schließt asynchron gesetzte Timer ein.
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
Ruft den nächsten verfügbaren Timer auf. Nützlich, um Zusicherungen zwischen jedem Timer-Aufruf zu machen. Sie können die Aufrufe verketten, um Timer selbst zu verwalten.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer(); // log: 3
vi.advanceTimersToNextTimerAsync
- Typ:
() => Promise<Vitest>
Ruft den nächsten verfügbaren Timer auf und wartet, bis er aufgelöst ist, falls er asynchron gesetzt wurde. Nützlich, um Zusicherungen zwischen jedem Timer-Aufruf zu machen.
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
Ähnlich wie vi.advanceTimersByTime
, aber es rückt die Timer um die Millisekunden vor, die benötigt werden, um Rückrufe auszuführen, die derzeit mit requestAnimationFrame
geplant sind.
let frameRendered = false;
requestAnimationFrame(() => {
frameRendered = true;
});
vi.advanceTimersToNextFrame();
expect(frameRendered).toBe(true);
vi.getTimerCount
- Typ:
() => number
Ruft die Anzahl der wartenden Timer ab.
vi.clearAllTimers
Entfernt alle Timer, die zur Ausführung geplant sind. Diese Timer werden in Zukunft nie ausgeführt.
vi.getMockedSystemTime
- Typ:
() => Date | null
Gibt das gemockte aktuelle Datum zurück, das mit setSystemTime
gesetzt wurde. Wenn das Datum nicht gemockt ist, gibt die Methode null
zurück.
vi.getRealSystemTime
- Typ:
() => number
Bei Verwendung von vi.useFakeTimers
werden Date.now
-Aufrufe gemockt. Wenn Sie die tatsächliche Zeit in Millisekunden abrufen müssen, können Sie diese Funktion aufrufen.
vi.runAllTicks
- Typ:
() => Vitest
Ruft jede Mikroaufgabe auf, die von process.nextTick
in die Warteschlange gestellt wurde. Dies führt auch alle Mikroaufgaben aus, die von ihnen selbst geplant wurden.
vi.runAllTimers
- Typ:
() => Vitest
Diese Methode ruft jeden initiierten Timer auf, bis die Timer-Warteschlange leer ist. Das bedeutet, dass jeder Timer, der während runAllTimers
aufgerufen wird, auch tatsächlich ausgelöst wird. Wenn Sie ein unendliches Intervall haben, wird nach 10.000 Versuchen ein Fehler ausgelöst (dies kann mit fakeTimers.loopLimit
konfiguriert werden).
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>
Diese Methode ruft jeden initiierten Timer asynchron auf, bis die Timer-Warteschlange leer ist. Das bedeutet, dass jeder Timer, der während runAllTimersAsync
aufgerufen wird, ausgelöst wird, auch asynchrone Timer. Wenn Sie ein unendliches Intervall haben, wird nach 10.000 Versuchen ein Fehler ausgelöst (dies kann mit fakeTimers.loopLimit
konfiguriert werden).
setTimeout(async () => {
console.log(await Promise.resolve('result'));
}, 100);
await vi.runAllTimersAsync();
// log: result
vi.runOnlyPendingTimers
- Typ:
() => Vitest
Diese Methode ruft jeden Timer auf, der nach dem Aufruf von vi.useFakeTimers
initiiert wurde. Sie löst keine Timer aus, die während ihres Aufrufs initiiert wurden.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- Typ:
() => Promise<Vitest>
Diese Methode ruft jeden Timer, der nach dem Aufruf von vi.useFakeTimers
initiiert wurde, asynchron auf, auch asynchrone. Sie löst keine Timer aus, die während ihres Aufrufs initiiert wurden.
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
Wenn Fake-Timer aktiviert sind, simuliert diese Methode, dass ein Benutzer die Systemuhr ändert. Dies wirkt sich auf datumsbezogene APIs wie hrtime
, performance.now
oder new Date()
aus, löst jedoch keine Timer aus. Wenn Fake-Timer nicht aktiviert sind, mockt diese Methode nur Date.*
-Aufrufe.
Nützlich, wenn Sie etwas testen müssen, das vom aktuellen Datum abhängt – zum Beispiel Luxon-Aufrufe in Ihrem Code.
Akzeptiert dieselben String- und Zahlenargumente wie 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
Um Timer zu mocken, müssen Sie diese Methode aufrufen. Sie umschließt alle weiteren Aufrufe an Timer (wie setTimeout
, setInterval
, clearTimeout
, clearInterval
, setImmediate
, clearImmediate
und Date
), bis vi.useRealTimers()
aufgerufen wird.
Das Mocken von nextTick
wird nicht unterstützt, wenn Vitest innerhalb von node:child_process
mit --pool=forks
ausgeführt wird. NodeJS verwendet process.nextTick
intern in node:child_process
und hängt, wenn es gemockt wird. Das Mocken von nextTick
wird unterstützt, wenn Vitest mit --pool=threads
ausgeführt wird.
Die Implementierung basiert intern auf @sinonjs/fake-timers
.
TIP
vi.useFakeTimers()
mockt process.nextTick
nicht automatisch. Sie können es jedoch aktivieren, indem Sie die Option im Argument toFake
angeben: vi.useFakeTimers({ toFake: ['nextTick'] })
.
vi.isFakeTimers
- Typ:
() => boolean
Gibt true
zurück, wenn Fake-Timer aktiviert sind.
vi.useRealTimers
- Typ:
() => Vitest
Wenn die Timer abgelaufen sind, können Sie diese Methode aufrufen, um gemockte Timer auf ihre ursprünglichen Implementierungen zurückzusetzen. Alle zuvor geplanten Timer werden verworfen.
Verschiedenes
Eine Reihe nützlicher Hilfsfunktionen, die Vitest bereitstellt.
vi.waitFor
- Typ:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
Wartet auf die erfolgreiche Ausführung des Callbacks. Wenn der Callback einen Fehler auslöst oder ein abgewiesenes Promise zurückgibt, wird weiter gewartet, bis er erfolgreich ist oder die Zeit abläuft.
Dies ist sehr nützlich, wenn Sie auf den Abschluss einer asynchronen Aktion warten müssen, z. B. wenn Sie einen Server starten und warten müssen, bis er gestartet ist.
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, // Standard ist 1000
interval: 20, // Standard ist 50
}
);
expect(server.isReady).toBe(true);
});
Es funktioniert auch für asynchrone Callbacks
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';
test('Element exists in a DOM', async () => {
// DOM-Befüllung starten
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// versucht, das Element zu erhalten, bis es existiert
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // Standard ist 1000
interval: 20, // Standard ist 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
Wenn vi.useFakeTimers
verwendet wird, ruft vi.waitFor
automatisch vi.advanceTimersByTime(interval)
bei jedem Prüf-Rückruf auf.
vi.waitUntil
- Typ:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
Dies ähnelt vi.waitFor
, aber wenn der Callback Fehler auslöst, wird die Ausführung sofort unterbrochen und eine Fehlermeldung empfangen. Wenn der Callback einen Wert zurückgibt, der als falsch interpretiert wird (falsy), wird die nächste Prüfung fortgesetzt, bis ein Wert zurückgegeben wird, der als wahr interpretiert wird (truthy). Dies ist nützlich, wenn Sie warten müssen, bis etwas existiert, bevor Sie den nächsten Schritt ausführen.
Betrachten Sie das Beispiel unten. Wir können vi.waitUntil
verwenden, um darauf zu warten, dass das Element auf der Seite erscheint, und dann können wir etwas mit dem Element tun.
import { expect, test, vi } from 'vitest';
test('Element render correctly', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // Standard ist 1000
interval: 20, // Standard ist 50
});
// etwas mit dem Element tun
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted
- Typ:
<T>(factory: () => T) => T
Alle statischen import
-Anweisungen in ES-Modulen werden an den Anfang der Datei verschoben, sodass jeder Code, der vor den Importen definiert ist, tatsächlich nach der Auswertung der Importe ausgeführt wird.
Es kann jedoch nützlich sein, einige Nebeneffekte wie das Mocken von Daten vor dem Importieren eines Moduls aufzurufen.
Um diese Einschränkung zu umgehen, können Sie statische Importe wie folgt in dynamische umschreiben:
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
Beim Ausführen von vitest
können Sie dies automatisch mit der Methode vi.hoisted
tun.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
Diese Methode gibt den Wert zurück, der von der Factory zurückgegeben wurde. Sie können diesen Wert in Ihren vi.mock
-Factories verwenden, wenn Sie einfachen Zugriff auf lokal definierte Variablen benötigen:
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);
Beachten Sie, dass diese Methode auch asynchron aufgerufen werden kann, selbst wenn Ihre Umgebung Top-Level-Await nicht unterstützt:
const promised = await vi.hoisted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
});
vi.setConfig
- Typ:
RuntimeConfig
Aktualisiert die Konfiguration für die aktuelle Testdatei. Diese Methode unterstützt nur Konfigurationsoptionen, die sich auf die aktuelle Testdatei auswirken:
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// unterstützt das gesamte Objekt
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// unterstützt nur `sequence.hooks`
},
});
vi.resetConfig
- Typ:
RuntimeConfig
Wenn vi.setConfig
zuvor aufgerufen wurde, setzt dies die Konfiguration auf den ursprünglichen Zustand zurück.