Funciones de Simulación
Puedes crear una función de simulación (mock function) para rastrear su ejecución con el método vi.fn
. Si quieres rastrear un método en un objeto ya creado, puedes usar el 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;
Deberías usar aserciones de mock (por ejemplo, toHaveBeenCalled
) en expect
para verificar el resultado del mock. Esta referencia de la API describe las propiedades y métodos disponibles para manipular el comportamiento del mock.
TIP
La implementación personalizada de la función en los tipos a continuación se indica con un genérico <T>
.
getMockImplementation
function getMockImplementation(): T | undefined;
Devuelve la implementación actual del mock, si existe.
Si el mock fue creado con vi.fn
, utilizará el método proporcionado como implementación del mock.
Si el mock fue creado con vi.spyOn
, devolverá undefined
a menos que se haya proporcionado una implementación personalizada.
getMockName
function getMockName(): string;
Se utiliza para devolver el nombre asignado al mock con el método .mockName(name)
. Por defecto, devolverá vi.fn()
.
mockClear
function mockClear(): MockInstance<T>;
Borra toda la información sobre cada llamada realizada. Después de invocarlo, todas las propiedades en .mock
volverán a su estado inicial. Este método no restablece las implementaciones. Es útil para limpiar los mocks entre diferentes aserciones.
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']]);
// borrar el historial de llamadas pero mantener la implementación simulada
spy.mockClear();
expect(spy.mock.calls).toEqual([]);
expect(person.greet('Bob')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Bob']]);
Para llamar automáticamente a este método antes de cada prueba, habilita la configuración clearMocks
.
mockName
function mockName(name: string): MockInstance<T>;
Establece el nombre interno del mock. Esto es útil para identificar la simulación cuando una aserción falla.
mockImplementation
function mockImplementation(fn: T): MockInstance<T>;
Acepta una función que se usará como la implementación del mock. TypeScript espera que los argumentos y el tipo de retorno coincidan con los de la función original.
const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1);
// o: 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>;
Acepta una función que se usará como la implementación del mock. TypeScript espera que los argumentos y el tipo de retorno coincidan con los de la función original. Este método se puede encadenar para producir diferentes resultados para múltiples llamadas a funciones.
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true) // 1ª llamada
.mockImplementationOnce(() => false); // 2ª llamada
myMockFn(); // 1ª llamada: true
myMockFn(); // 2ª llamada: false
Cuando la función mockeada se queda sin implementaciones once
, invocará la implementación por defecto establecida con vi.fn(() => defaultValue)
o .mockImplementation(() => defaultValue)
si estas fueron definidas:
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>>;
Sobrescribe temporalmente la implementación original del mock mientras se ejecuta la función de callback.
const myMockFn = vi.fn(() => 'original');
myMockFn.withImplementation(
() => 'temp',
() => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
Puede usarse con un callback asíncrono. Es necesario esperar (con await
) el método para usar la implementación original después.
test('async callback', async () => {
const myMockFn = vi.fn(() => 'original');
// Esperamos esta llamada ya que el callback es asíncrono
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
});
Ten en cuenta que este método tiene precedencia sobre mockImplementationOnce
.
mockRejectedValue
function mockRejectedValue(value: unknown): MockInstance<T>;
Recibe un error que será rechazado cuando se llame a la función asíncrona.
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // lanza Error<'Async error'>
mockRejectedValueOnce
function mockRejectedValueOnce(value: unknown): MockInstance<T>;
Acepta un valor que será rechazado durante la siguiente llamada a la función. Si se encadena, cada llamada consecutiva resultará en el rechazo del valor especificado.
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // 'first call'
await asyncMock(); // lanza Error<'Async error'>
mockReset
function mockReset(): MockInstance<T>;
Realiza la misma acción que mockClear
y restablece la implementación interna a la función original. Esto también restablece todas las implementaciones "once".
Ten en cuenta que al restablecer un mock creado con vi.fn()
, la implementación se establecerá a una función vacía que devuelve undefined
. Al restablecer un mock creado con vi.fn(impl)
, se restaurará la implementación a impl
.
Esto es útil cuando quieres restablecer un mock a su 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']]);
// borrar el historial de llamadas y restablecer la implementación, pero el método sigue siendo espiado
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 llamar automáticamente a este método antes de cada prueba, habilita la configuración mockReset
.
mockRestore
function mockRestore(): MockInstance<T>;
Realiza la misma acción que mockReset
y restaura los descriptores originales de los objetos espiados.
Ten en cuenta que al restaurar un mock creado con vi.fn()
, la implementación se establecerá a una función vacía que devuelve undefined
. Al restaurar un mock creado con vi.fn(impl)
, se restaurará la implementación a 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']]);
// borrar el historial de llamadas y restaurar el método del objeto espiado
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 llamar automáticamente a este método antes de cada prueba, habilita la configuración restoreMocks
.
mockResolvedValue
function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>;
Recibe un valor que se resolverá cuando se llame a la función asíncrona. TypeScript solo aceptará valores que coincidan con el tipo de retorno de la función original.
const asyncMock = vi.fn().mockResolvedValue(42);
await asyncMock(); // 42
mockResolvedValueOnce
function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): MockInstance<T>;
Acepta un valor que se resolverá durante la siguiente llamada a la función. TypeScript solo aceptará valores que coincidan con el tipo de retorno de la función original. Si se encadena, cada llamada consecutiva resultará en la resolución del 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>;
Utiliza este método si necesitas devolver el contexto this
del método sin invocar la implementación real. Esto es una abreviatura de:
spy.mockImplementation(function () {
return this;
});
mockReturnValue
function mockReturnValue(value: ReturnType<T>): MockInstance<T>;
Recibe un valor que se devolverá cada vez que se llame a la función mock. TypeScript solo aceptará valores que coincidan con el tipo de retorno de la función original.
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
mockReturnValueOnce
function mockReturnValueOnce(value: ReturnType<T>): MockInstance<T>;
Acepta un valor que se devolverá cada vez que se llame a la función mock. TypeScript solo aceptará valores que coincidan con el tipo de retorno de la función original.
Cuando la función mockeada se queda sin implementaciones once
, invocará la implementación por defecto establecida con vi.fn(() => defaultValue)
o .mockImplementation(() => defaultValue)
si estas fueron definidas:
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 es un array que contiene los argumentos de cada llamada. Cada elemento del array corresponde a los argumentos de una llamada específica.
const fn = vi.fn();
fn('arg1', 'arg2');
fn('arg3');
fn.mock.calls ===
[
['arg1', 'arg2'], // primera llamada
['arg3'], // segunda llamada
];
mock.lastCall
const lastCall: Parameters<T> | undefined;
Esto contiene los argumentos de la última llamada. Si el mock no ha sido llamado, devolverá undefined
.
mock.results
interface MockResultReturn<T> {
type: 'return';
/**
* El valor que fue devuelto por la función.
* Si la función devolvió una Promesa, entonces este será un valor resuelto.
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* Un error que fue lanzado durante la ejecución de la función.
*/
value: any;
}
type MockResult<T> =
| MockResultReturn<T>
| MockResultThrow
| MockResultIncomplete;
const results: MockResult<ReturnType<T>>[];
Este es un array que contiene todos los valores que fueron returned
por la función. Un elemento del array es un objeto con las propiedades type
y value
. Los tipos disponibles son:
'return'
- la función devolvió un valor sin lanzar una excepción.'throw'
- la función lanzó una excepción.
La propiedad value
contiene el valor devuelto o el error producido. Si la función retornó una Promise
, entonces el type
siempre será 'return'
incluso si la promesa fue rechazada.
const fn = vi
.fn()
.mockReturnValueOnce('result')
.mockImplementationOnce(() => {
throw new Error('thrown error');
});
const result = fn(); // devolvió 'result'
try {
fn(); // lanzó Error
} catch {}
fn.mock.results ===
[
// primer 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>>>[];
Un array que contiene todos los valores que fueron resolved
o rejected
por la función.
Este array permanecerá vacío si la función nunca se resuelve o rechaza.
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 propiedad indica el orden de ejecución de la función mock. Es un array de números que es común a todos los 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 propiedad es un array de los contextos (this
) utilizados durante cada llamada a la función 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 propiedad es un array que contiene todas las instancias que se crearon cuando se llamó al mock con la palabra clave new
. Ten en cuenta que este es el contexto (this
) real de la función, no un valor de retorno.
WARNING
Si el mock se creó con new MyClass()
, entonces mock.instances
será un array con un valor:
const MyClass = vi.fn();
const a = new MyClass();
MyClass.mock.instances[0] === a;
Si devuelves un valor del constructor, este no estará en el array instances
, sino que se encontrará en results
:
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();
Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;