Funciones Simuladas
Puedes crear una función simulada para rastrear su ejecución utilizando el método vi.fn
. Si deseas rastrear un método en un objeto ya existente, 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;
Debes usar aserciones de mock (por ejemplo, toHaveBeenCalled
) junto con 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 de función personalizada en los siguientes tipos está marcada con un genérico <T>
.
getMockImplementation
function getMockImplementation(): T | undefined;
Devuelve la implementación mock actual, si existe.
Si el mock fue creado con vi.fn
, utilizará el método proporcionado como implementación simulada.
Si el mock fue creado con vi.spyOn
, devolverá undefined
a menos que se haya proporcionado una implementación específica.
getMockName
function getMockName(): string;
Úsalo para devolver el nombre asignado al mock con el método .mockName(name)
. Por defecto, devuelve vi.fn()
.
mockClear
function mockClear(): MockInstance<T>;
Elimina toda la información sobre cada llamada. Después de llamarlo, todas las propiedades en .mock
volverán a su estado inicial. Este método no reinicia las implementaciones. Es útil para limpiar mocks entre diferentes aserciones.
Para que este método se llame automáticamente antes de cada prueba, habilita la configuración clearMocks
.
mockName
function mockName(name: string): MockInstance<T>;
Define el nombre interno del mock. Esto es útil para identificar el mock en caso de que falle una aserción.
mockImplementation
function mockImplementation(fn: T): MockInstance<T>;
Acepta una función para ser utilizada como la implementación 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 para ser utilizada como la implementación 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 en múltiples llamadas a la función.
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true) // 1st call
.mockImplementationOnce(() => false); // 2nd call
myMockFn(); // 1st call: true
myMockFn(); // 2nd call: false
Cuando la función mockeada se queda sin implementaciones, utilizará la implementación predeterminada establecida con vi.fn(() => defaultValue)
o .mockImplementation(() => defaultValue)
, si fueron llamadas:
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>>;
Reemplaza temporalmente la implementación mock original mientras se ejecuta la función de callback.
const myMockFn = vi.fn(() => 'original');
myMockFn.withImplementation(
() => 'temp',
() => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
Puede usarse con una función de callback asíncrona. Se debe esperar el método para poder usar la implementación original después.
test('async callback', async () => {
const myMockFn = vi.fn(() => 'original');
// We await this call since the callback is async
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
});
Cabe destacar que este método tiene prioridad 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(); // throws Error<'Async error'>
mockRejectedValueOnce
function mockRejectedValueOnce(value: unknown): MockInstance<T>;
Acepta un valor que será rechazado durante la próxima llamada a la función. Si se encadenan, cada llamada consecutiva rechazará el valor especificado.
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // 'first call'
await asyncMock(); // throws Error<'Async error'>
mockReset
function mockReset(): MockInstance<T>;
Realiza las mismas acciones que mockClear
y establece la implementación interna a una función vacía (que devuelve undefined
cuando se invoca). Esto también reinicia todas las implementaciones "once". Es útil para restablecer completamente un mock a su estado por defecto.
Para que este método se llame automáticamente antes de cada prueba, habilita la configuración mockReset
.
mockRestore
function mockRestore(): MockInstance<T>;
Realiza las mismas acciones que mockReset
y restaura la implementación interna a la función original.
Ten en cuenta que restaurar un mock creado con vi.fn()
establecerá la implementación a una función vacía que devuelve undefined
. Restaurar un mock creado con vi.fn(impl)
restaurará la implementación a impl
.
Para que este método se llame automáticamente antes de cada prueba, habilita la configuración restoreMocks
.
mockResolvedValue
function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>;
Acepta un valor que será resuelto 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 será resuelto durante la próxima 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 resolverá el 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>;
Usa esto si necesitas devolver el contexto this
del método sin invocar la implementación real. Esto equivale a:
spy.mockImplementation(function () {
return this;
});
mockReturnValue
function mockReturnValue(value: ReturnType<T>): MockInstance<T>;
Acepta un valor que será devuelto 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 será devuelto 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, utilizará la implementación predeterminada establecida con vi.fn(() => defaultValue)
o .mockImplementation(() => defaultValue)
, si fueron llamadas:
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 todos los argumentos para cada llamada. Cada elemento del array contiene los argumentos de esa llamada.
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;
Esto contiene los argumentos de la última llamada. Si el mock no fue llamado, devuelve undefined
.
mock.results
interface MockResultReturn<T> {
type: 'return';
/**
* The value that was returned from the function.
* If function returned a Promise, then this will be a resolved value.
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* An error that was thrown during function execution.
*/
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
(devueltos) por la función. Cada elemento del array es un objeto con las propiedades type
y value
. Los tipos disponibles son:
'return'
- la función retornó sin lanzar un error.'throw'
- la función arrojó un valor.
La propiedad value
contiene el valor devuelto o el error lanzado. Si la función devolvió una Promise
, entonces result
siempre será 'return'
incluso si la promesa fue rechazada.
const fn = vi
.fn()
.mockReturnValueOnce('result')
.mockImplementationOnce(() => {
throw new Error('thrown error');
});
const result = fn(); // returned 'result'
try {
fn(); // threw Error
} catch {}
fn.mock.results ===
[
// first result
{
type: 'return',
value: 'result',
},
// last result
{
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
(resueltos) o rejected
(rechazados) por la función.
Este array permanecerá vacío si la función nunca se resolvió o se rechazó.
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 simulada. Es un array de números que se comparten entre 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 contiene un array de valores 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 real (this
) de la función, no un valor de retorno.
WARNING
Si el mock fue instanciado 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 desde el constructor, no estará en el array instances
, sino dentro de results
:
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();
Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;