Funkcje Mock
Możesz utworzyć funkcję mock, aby śledzić jej wykonanie, używając metody vi.fn
. Jeśli chcesz śledzić metodę na już istniejącym obiekcie, możesz użyć metody vi.spyOn
:
import { vi } from 'vitest';
const fn = vi.fn();
fn('hello world');
fn.mock.calls[0] === ['hello world'];
const market = {
getApples: () => 100,
};
const getApplesSpy = vi.spyOn(market, 'getApples');
market.getApples();
getApplesSpy.mock.calls.length === 1;
Należy używać asercji mock (np. toHaveBeenCalled
) w expect
, aby potwierdzić wynik mocka. To odwołanie do API opisuje dostępne właściwości i metody do manipulowania zachowaniem mocka.
TIP
Własna implementacja funkcji w poniższych typach jest oznaczona jako generyczny <T>
.
getMockImplementation
function getMockImplementation(): T | undefined;
Zwraca aktualną implementację mocka, jeśli taka istnieje.
Jeśli mock został utworzony za pomocą vi.fn
, użyje podanej metody jako implementacji mocka.
Jeśli mock został utworzony za pomocą vi.spyOn
, zwróci wartość undefined
, chyba że podana zostanie niestandardowa implementacja.
getMockName
function getMockName(): string;
Użyj tej metody, aby zwrócić nazwę przypisaną do mocka przy użyciu metody .mockName(name)
. Domyślnie zwróci vi.fn()
.
mockClear
function mockClear(): MockInstance<T>;
Czyści wszystkie informacje o każdym wywołaniu mocka. Po wywołaniu tej metody wszystkie właściwości na .mock
wrócą do stanu początkowego. Ta metoda nie resetuje implementacji. Jest przydatna do czyszczenia mocków pomiędzy różnymi asercjami.
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// wyczyść historię wywołań, ale zachowaj implementację mocka
spy.mockClear();
expect(spy.mock.calls).toEqual([]);
expect(person.greet('Bob')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Bob']]);
Aby automatycznie wywoływać tę metodę przed każdym testem, włącz ustawienie clearMocks
w konfiguracji testów.
mockName
function mockName(name: string): MockInstance<T>;
Ustawia wewnętrzną nazwę mocka, co jest przydatne do identyfikacji mocka, gdy asercja zakończy się niepowodzeniem.
mockImplementation
function mockImplementation(fn: T): MockInstance<T>;
Akceptuje funkcję, która ma być użyta jako implementacja mocka, a TypeScript oczekuje, że argumenty i typ zwracany będą zgodne z oryginalną funkcją.
const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1);
// lub: vi.fn(apples => apples + 1);
const NelliesBucket = mockFn(0);
const BobsBucket = mockFn(1);
NelliesBucket === 1; // true
BobsBucket === 2; // true
mockFn.mock.calls[0][0] === 0; // true
mockFn.mock.calls[1][0] === 1; // true
mockImplementationOnce
function mockImplementationOnce(fn: T): MockInstance<T>;
Akceptuje funkcję, która ma być użyta jako implementacja mocka. TypeScript oczekuje, że argumenty i typ zwracany będą zgodne z oryginalną funkcją. Tę metodę można łączyć w łańcuch, aby uzyskać różne wyniki dla kolejnych wywołań funkcji.
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true) // 1st call
.mockImplementationOnce(() => false); // 2nd call
myMockFn(); // 1st call: true
myMockFn(); // 2nd call: false
Gdy zamockowanej funkcji zabraknie implementacji, wywoła ona domyślną implementację ustawioną za pomocą vi.fn(() => defaultValue)
lub .mockImplementation(() => defaultValue)
, jeśli te metody zostały wcześniej wywołane:
const myMockFn = vi
.fn(() => 'default')
.mockImplementationOnce(() => 'first call')
.mockImplementationOnce(() => 'second call');
// 'pierwsze wywołanie', 'drugie wywołanie', 'domyślne', 'domyślne'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
withImplementation
function withImplementation(fn: T, cb: () => void): MockInstance<T>;
function withImplementation(
fn: T,
cb: () => Promise<void>
): Promise<MockInstance<T>>;
Tymczasowo nadpisuje oryginalną implementację mocka podczas wykonywania funkcji zwrotnej.
const myMockFn = vi.fn(() => 'original');
myMockFn.withImplementation(
() => 'temp',
() => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
Może być używana z asynchroniczną funkcją zwrotną. Metoda musi być oczekiwana, aby później użyć oryginalnej implementacji.
test('async callback', async () => {
const myMockFn = vi.fn(() => 'original');
// Oczekujemy na to wywołanie, ponieważ funkcja zwrotna jest asynchroniczna
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
});
Zauważ, że ta metoda ma pierwszeństwo przed metodą mockImplementationOnce
.
mockRejectedValue
function mockRejectedValue(value: unknown): MockInstance<T>;
Akceptuje błąd, który zostanie odrzucony, gdy wywołana zostanie funkcja asynchroniczna.
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // rzuca błąd Error<'Async error'>
mockRejectedValueOnce
function mockRejectedValueOnce(value: unknown): MockInstance<T>;
Akceptuje wartość, która zostanie odrzucona podczas kolejnego wywołania funkcji. Jeśli połączone w łańcuch, każde kolejne wywołanie odrzuci określoną wartość.
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // 'first call'
await asyncMock(); // rzuca błąd Error<'Async error'>
mockReset
function mockReset(): MockInstance<T>;
Wykonuje to, co mockClear
, a dodatkowo resetuje wewnętrzną implementację do oryginalnej funkcji. Resetuje to również wszystkie implementacje "once".
Zauważ, że zresetowanie mocka utworzonego za pomocą vi.fn()
ustawi implementację na pustą funkcję, która zwraca wartość undefined
. Zresetowanie mocka z vi.fn(impl)
przywróci implementację do impl
.
Jest to przydatne, gdy chcesz przywrócić mock do jego pierwotnego stanu.
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// wyczyść historię wywołań i zresetuj implementację, ale metoda jest nadal szpiegowana
spy.mockReset();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([['Bob']]);
Aby automatycznie wywoływać tę metodę przed każdym testem, włącz ustawienie mockReset
w konfiguracji testów.
mockRestore
function mockRestore(): MockInstance<T>;
Wykonuje to, co mockReset
, a dodatkowo przywraca oryginalne deskryptory szpiegowanych obiektów.
Zauważ, że przywrócenie mocka utworzonego za pomocą vi.fn()
ustawi implementację na pustą funkcję, która zwraca wartość undefined
. Przywrócenie mocka z vi.fn(impl)
przywróci implementację do impl
.
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// wyczyść historię wywołań i przywróć metodę szpiegowanego obiektu
spy.mockRestore();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).not.toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([]);
Aby automatycznie wywoływać tę metodę przed każdym testem, włącz ustawienie restoreMocks
w konfiguracji.
mockResolvedValue
function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>;
Akceptuje wartość, która zostanie zwrócona po wywołaniu funkcji asynchronicznej. TypeScript zaakceptuje tylko wartości, które pasują do typu zwracanego przez oryginalną funkcję.
const asyncMock = vi.fn().mockResolvedValue(42);
await asyncMock(); // 42
mockResolvedValueOnce
function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): MockInstance<T>;
Akceptuje wartość, która zostanie zwrócona podczas kolejnego wywołania funkcji. TypeScript zaakceptuje tylko wartości, które pasują do typu zwracanego przez oryginalną funkcję. Jeśli połączone w łańcuch, każde kolejne wywołanie rozwiąże określoną wartość.
const asyncMock = vi
.fn()
.mockResolvedValue('default')
.mockResolvedValueOnce('first call')
.mockResolvedValueOnce('second call');
await asyncMock(); // first call
await asyncMock(); // second call
await asyncMock(); // default
await asyncMock(); // default
mockReturnThis
function mockReturnThis(): MockInstance<T>;
Użyj tego, jeśli potrzebujesz zwrócić kontekst this
z metody bez wywoływania rzeczywistej implementacji. Jest to skrót dla:
spy.mockImplementation(function () {
return this;
});
mockReturnValue
function mockReturnValue(value: ReturnType<T>): MockInstance<T>;
Akceptuje wartość, która zostanie zwrócona za każdym razem, gdy funkcja mock zostanie wywołana. TypeScript zaakceptuje tylko wartości, które pasują do typu zwracanego przez oryginalną funkcję.
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
mockReturnValueOnce
function mockReturnValueOnce(value: ReturnType<T>): MockInstance<T>;
Akceptuje wartość, która zostanie zwrócona za każdym razem, gdy funkcja mock zostanie wywołana. TypeScript zaakceptuje tylko wartości, które pasują do typu zwracanego przez oryginalną funkcję.
Gdy zamockowanej funkcji zabraknie implementacji, wywoła ona domyślną implementację ustawioną za pomocą vi.fn(() => defaultValue)
lub .mockImplementation(() => defaultValue)
, jeśli zostały wywołane:
const myMockFn = vi
.fn()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');
// 'pierwsze wywołanie', 'drugie wywołanie', 'domyślne', 'domyślne'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
mock.calls
const calls: Parameters<T>[];
To tablica zawierająca wszystkie argumenty dla każdego wywołania. Jeden element tablicy to argumenty tego wywołania.
const fn = vi.fn();
fn('arg1', 'arg2');
fn('arg3');
fn.mock.calls ===
[
['arg1', 'arg2'], // first call
['arg3'], // second call
];
mock.lastCall
const lastCall: Parameters<T> | undefined;
Zawiera argumenty ostatniego wywołania. Jeśli mock nie został wywołany, zwróci wartość undefined
.
mock.results
interface MockResultReturn<T> {
type: 'return';
/**
* Wartość zwrócona przez funkcję.
* Jeśli funkcja zwróciła Promise, to będzie to rozwiązana wartość.
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* Błąd rzucony podczas wykonywania funkcji.
*/
value: any;
}
type MockResult<T> =
| MockResultReturn<T>
| MockResultThrow
| MockResultIncomplete;
const results: MockResult<ReturnType<T>>[];
To tablica zawierająca wszystkie wartości, które zostały zwrócone
przez funkcję. Jeden element tablicy to obiekt z właściwościami type
i value
. Dostępne typy to:
'return'
- funkcja zwróciła wartość bez rzucania błędu.'throw'
- funkcja rzuciła wartość.
Właściwość value
zawiera zwróconą wartość lub błąd, który został rzucony. Jeśli funkcja zwróciła Promise
, to result
zawsze będzie 'return'
, nawet jeśli obietnica została odrzucona.
const fn = vi
.fn()
.mockReturnValueOnce('result')
.mockImplementationOnce(() => {
throw new Error('thrown error');
});
const result = fn(); // zwróciła 'result'
try {
fn(); // rzuciła Error
} catch {}
fn.mock.results ===
[
// pierwszy wynik
{
type: 'return',
value: 'result',
},
// ostatni wynik
{
type: 'throw',
value: Error,
},
];
mock.settledResults
interface MockSettledResultFulfilled<T> {
type: 'fulfilled';
value: T;
}
interface MockSettledResultRejected {
type: 'rejected';
value: any;
}
export type MockSettledResult<T> =
| MockSettledResultFulfilled<T>
| MockSettledResultRejected;
const settledResults: MockSettledResult<Awaited<ReturnType<T>>>[];
Tablica zawierająca wszystkie wartości, które zostały rozwiązane
lub odrzucone
przez funkcję.
Tablica będzie pusta, jeśli funkcja nigdy nie została rozwiązana ani odrzucona.
const fn = vi.fn().mockResolvedValueOnce('result');
const result = fn();
fn.mock.settledResults === [];
await result;
fn.mock.settledResults ===
[
{
type: 'fulfilled',
value: 'result',
},
];
mock.invocationCallOrder
const invocationCallOrder: number[];
Ta właściwość zwraca kolejność wywołań funkcji mock. Jest to tablica liczb, które są współdzielone pomiędzy wszystkimi zdefiniowanymi mockami.
const fn1 = vi.fn();
const fn2 = vi.fn();
fn1();
fn2();
fn1();
fn1.mock.invocationCallOrder === [1, 3];
fn2.mock.invocationCallOrder === [2];
mock.contexts
const contexts: ThisParameterType<T>[];
Ta właściwość to tablica wartości this
, które były używane podczas każdego wywołania funkcji mock.
const fn = vi.fn();
const context = {};
fn.apply(context);
fn.call(context);
fn.mock.contexts[0] === context;
fn.mock.contexts[1] === context;
mock.instances
const instances: ReturnType<T>[];
Ta właściwość to tablica zawierająca wszystkie instancje, które zostały utworzone, gdy mock został wywołany z użyciem słowa kluczowego new
. Należy zauważyć, że jest to rzeczywisty kontekst (this
) funkcji, a nie wartość, którą ona zwraca.
WARNING
Jeśli mock został utworzony za pomocą new MyClass()
, to mock.instances
będzie tablicą zawierającą jedną wartość:
const MyClass = vi.fn();
const a = new MyClass();
MyClass.mock.instances[0] === a;
Jeśli zwrócisz wartość z konstruktora, nie znajdzie się ona w tablicy instances
, ale znajdzie się w results
:
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();
Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;