Funções Mock
Você pode criar uma função mock para rastrear sua execução usando o método vi.fn
. Se você quiser rastrear um método em um objeto já existente, você pode usar o método 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;
Você deve usar asserções de mock (por exemplo, toHaveBeenCalled
) em expect
para verificar o resultado do mock. Esta referência da API descreve as propriedades e métodos disponíveis para manipular o comportamento dos mocks.
TIP
A implementação de função personalizada nos tipos abaixo é marcada com um genérico <T>
.
getMockImplementation
function getMockImplementation(): T | undefined;
Retorna a implementação mock atual, se houver uma.
Se o mock foi criado com vi.fn
, ele usará a função fornecida como implementação do mock.
Se o mock foi criado com vi.spyOn
, ele retornará undefined
a menos que uma implementação personalizada seja fornecida.
getMockName
function getMockName(): string;
Use este método para retornar o nome atribuído ao mock com o método .mockName(name)
. Por padrão, retornará vi.fn()
.
mockClear
function mockClear(): MockInstance<T>;
Limpa todas as informações sobre cada chamada. Após chamá-lo, todas as propriedades de .mock
retornarão ao seu estado inicial. Este método não redefine as implementações. É útil para limpar mocks entre várias asserções.
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']]);
// limpa o histórico de chamadas, mas mantém a implementação do mock
spy.mockClear();
expect(spy.mock.calls).toEqual([]);
expect(person.greet('Bob')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Bob']]);
Para chamar automaticamente este método antes de cada teste, ative a configuração clearMocks
.
mockName
function mockName(name: string): MockInstance<T>;
Define o nome interno do mock. Isso é útil para identificar o mock quando uma asserção falha.
mockImplementation
function mockImplementation(fn: T): MockInstance<T>;
Aceita uma função para ser usada como a implementação do mock. O TypeScript espera que os argumentos e o tipo de retorno correspondam aos da função original.
const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1);
// ou: 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>;
Aceita uma função para ser usada como a implementação do mock. O TypeScript espera que os argumentos e o tipo de retorno correspondam aos da função original. Este método pode ser encadeado para produzir resultados diferentes para várias chamadas de função.
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true) // 1ª chamada
.mockImplementationOnce(() => false); // 2ª chamada
myMockFn(); // 1ª chamada: true
myMockFn(); // 2ª chamada: false
Quando a função mockada fica sem implementações, ela invocará a implementação padrão definida com vi.fn(() => defaultValue)
ou .mockImplementation(() => defaultValue)
se tiverem sido chamadas:
const myMockFn = vi
.fn(() => 'default')
.mockImplementationOnce(() => 'first call')
.mockImplementationOnce(() => 'second call');
// 'first call', 'second call', 'default', 'default'
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>>;
Sobrescreve temporariamente a implementação mock original enquanto o callback está sendo executado.
const myMockFn = vi.fn(() => 'original');
myMockFn.withImplementation(
() => 'temp',
() => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
Pode ser usado com um callback assíncrono. É necessário aguardar o método para depois usar a implementação original.
test('async callback', async () => {
const myMockFn = vi.fn(() => 'original');
// Aguardamos esta chamada, pois o callback é assíncrono
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
});
Note que este método tem precedência sobre o mockImplementationOnce
.
mockRejectedValue
function mockRejectedValue(value: unknown): MockInstance<T>;
Recebe um erro que será rejeitado quando a função assíncrona for chamada.
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // dispara Error('Async error')
mockRejectedValueOnce
function mockRejectedValueOnce(value: unknown): MockInstance<T>;
Aceita um valor que será rejeitado durante a próxima chamada de função. Se encadeado, cada chamada subsequente rejeitará o valor especificado.
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // 'first call'
await asyncMock(); // dispara Error('Async error')
mockReset
function mockReset(): MockInstance<T>;
Faz o mesmo que mockClear
e redefine a implementação interna para a função original. Isso também redefine todas as implementações definidas com métodos Once
.
Note que ao redefinir um mock criado com vi.fn()
, a implementação será definida como uma função vazia que retorna undefined
. Ao redefinir um mock criado com vi.fn(impl)
, a implementação será restaurada para impl
.
Isso é útil quando você deseja redefinir um mock para seu estado original.
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']]);
// limpa o histórico de chamadas e redefine a implementação, mas o método ainda é espionado
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']]);
Para chamar automaticamente este método antes de cada teste, habilite a configuração mockReset
.
mockRestore
function mockRestore(): MockInstance<T>;
Faz o mesmo que mockReset
e restaura os descritores originais de objetos espionados.
Note que ao restaurar um mock criado com vi.fn()
, a implementação será definida como uma função vazia que retorna undefined
. Ao restaurar um mock criado com vi.fn(impl)
, a implementação será restaurada para 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']]);
// limpa o histórico de chamadas e restaura o método do objeto espionado
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([]);
Para chamar automaticamente este método antes de cada teste, habilite a configuração restoreMocks
.
mockResolvedValue
function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>;
Aceita um valor que será resolvido quando a função assíncrona for chamada. O TypeScript só aceitará valores que correspondam ao tipo de retorno da função original.
const asyncMock = vi.fn().mockResolvedValue(42);
await asyncMock(); // 42
mockResolvedValueOnce
function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): MockInstance<T>;
Aceita um valor que será resolvido durante a próxima chamada de função. O TypeScript só aceitará valores que correspondam ao tipo de retorno da função original. Se encadeado, cada chamada consecutiva resolverá o valor especificado.
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>;
Use este método se você precisar retornar o contexto this
do método sem invocar a implementação real. Isso é um atalho para:
spy.mockImplementation(function () {
return this;
});
mockReturnValue
function mockReturnValue(value: ReturnType<T>): MockInstance<T>;
Aceita um valor que será retornado sempre que a função mock for chamada. O TypeScript só aceitará valores que correspondam ao tipo de retorno da função original.
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
mockReturnValueOnce
function mockReturnValueOnce(value: ReturnType<T>): MockInstance<T>;
Aceita um valor que será retornado sempre que a função mock for chamada. O TypeScript só aceitará valores que correspondam ao tipo de retorno da função original.
Quando a função mockada fica sem implementações, ela invocará a implementação padrão definida com vi.fn(() => defaultValue)
ou .mockImplementation(() => defaultValue)
se tiverem sido chamadas:
const myMockFn = vi
.fn()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
mock.calls
const calls: Parameters<T>[];
Este é um array contendo todos os argumentos para cada chamada. Cada item do array contém os argumentos dessa chamada.
const fn = vi.fn();
fn('arg1', 'arg2');
fn('arg3');
fn.mock.calls ===
[
['arg1', 'arg2'], // primeira chamada
['arg3'], // segunda chamada
];
mock.lastCall
const lastCall: Parameters<T> | undefined;
Isso contém os argumentos da última chamada. Se o mock não foi chamado, ele retornará undefined
.
mock.results
interface MockResultReturn<T> {
type: 'return';
/**
* O valor que foi retornado da função.
* Se a função retornou uma Promise, então este será um valor resolvido.
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* Um erro que foi lançado durante a execução da função.
*/
value: any;
}
type MockResult<T> =
| MockResultReturn<T>
| MockResultThrow
| MockResultIncomplete;
const results: MockResult<ReturnType<T>>[];
Este é um array contendo todos os valores que foram retornados
da função. Cada item do array é um objeto com as propriedades type
e value
. Os tipos disponíveis são:
'return'
- a função retornou sem lançar um erro.'throw'
- a função lançou um valor.
A propriedade value
contém o valor retornado ou o erro lançado. Se a função retornou uma Promise
, então o type
sempre será 'return'
mesmo que a promise tenha sido rejeitada.
const fn = vi
.fn()
.mockReturnValueOnce('result')
.mockImplementationOnce(() => {
throw new Error('thrown error');
});
const result = fn(); // retornou 'result'
try {
fn(); // lançou Error
} catch {}
fn.mock.results ===
[
// primeiro resultado
{
type: 'return',
value: 'result',
},
// último resultado
{
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>>>[];
Um array contendo todos os valores que foram resolvidos
ou rejeitados
da função.
Este array ficará vazio se a função nunca for resolvida ou rejeitada.
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[];
Esta propriedade indica a ordem de execução da função mock. É um array de números que são compartilhados entre todos os mocks definidos.
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>[];
Esta propriedade é um array de valores this
usados durante cada chamada à função 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>[];
Esta propriedade é um array contendo todas as instâncias que foram criadas quando o mock foi chamado com a palavra-chave new
. Observe que este é o contexto real (this
) da função, e não o valor de retorno.
WARNING
Se o mock foi instanciado com new MyClass()
, então mock.instances
será um array com uma única instância:
const MyClass = vi.fn();
const a = new MyClass();
MyClass.mock.instances[0] === a;
Se você retornar um valor do construtor, ele não estará no array instances
, mas sim no array results
:
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();
Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;