Funciones Mock
Puedes crear una función simulada para rastrear su ejecución con el método vi.fn
. Si quieres espiar 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 mocks (p.ej., toHaveBeenCalled
) en expect
para verificar el comportamiento simulado. Esta referencia API describe las propiedades y métodos disponibles para controlar el comportamiento de los mocks.
getMockImplementation
- Tipo:
(...args: any) => any
Devuelve la implementación simulada actual, si existe.
Si la función simulada se creó con vi.fn
, considerará el método pasado como la implementación simulada.
Si el espía se creó con vi.spyOn
, devolverá undefined
a menos que se haya proporcionado una implementación personalizada.
getMockName
- Tipo:
() => string
Se usa para obtener el nombre asignado al mock con el método .mockName(name)
.
mockClear
- Tipo:
() => MockInstance
Borra toda la información de cada llamada. Después de llamarlo, todas las propiedades en .mock
devolverán un estado vacío. Este método no reinicia las implementaciones. Es útil si necesitas limpiar la función simulada entre diferentes aserciones.
Si quieres que este método se llame automáticamente antes de cada test, puedes habilitar la configuración clearMocks
en la configuración.
mockName
- Tipo:
(name: string) => MockInstance
Define el nombre interno del mock. Es útil para ver el nombre del mock si la aserción falla.
mockImplementation
- Tipo:
(fn: Function) => MockInstance
Acepta una función que se utilizará como implementación de la función simulada.
import { vi } from 'vitest';
// ---cut---
const mockFn = vi.fn().mockImplementation(apples => apples + 1);
// or: 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
- Tipo:
(fn: Function) => MockInstance
Acepta una función que se utilizará como implementación del mock durante la siguiente llamada. Puede encadenarse para que llamadas sucesivas produzcan resultados distintos.
import { vi } from 'vitest';
// ---cut---
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true)
.mockImplementationOnce(() => false);
myMockFn(); // true
myMockFn(); // false
Cuando el mock agota sus implementaciones, invocará la implementación por defecto que se estableció con vi.fn(() => defaultValue)
o .mockImplementation(() => defaultValue)
si se llamaron:
import { vi } from 'vitest';
// ---cut---
const myMockFn = vi
.fn(() => 'default')
.mockImplementationOnce(() => 'first call')
.mockImplementationOnce(() => 'second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
withImplementation
- Tipo:
(fn: Function, callback: () => void) => MockInstance
- Tipo:
(fn: Function, callback: () => Promise<unknown>) => Promise<MockInstance>
Reemplaza temporalmente la implementación simulada original mientras se ejecuta el callback.
import { vi } from 'vitest';
// ---cut---
const myMockFn = vi.fn(() => 'original');
myMockFn.withImplementation(
() => 'temp',
() => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
Se puede usar con un callback asíncrono. Se debe esperar (await) el método para usar la implementación original después.
test('async callback', () => {
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
- Tipo:
(value: any) => MockInstance
Acepta un error que se rechazará cuando se llame a la función asíncrona simulada.
import { vi } from 'vitest';
// ---cut---
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // throws "Async error"
mockRejectedValueOnce
- Tipo:
(value: any) => MockInstance
Acepta un valor que se rechazará durante la siguiente llamada a la función. Si se encadena, cada llamada consecutiva rechazará el valor especificado.
import { vi } from 'vitest';
// ---cut---
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // first call
await asyncMock(); // throws "Async error"
mockReset
- Tipo:
() => MockInstance
Realiza las acciones de mockClear
y convierte la implementación interna en una función vacía (devolviendo undefined
cuando se invoca). Esto también reinicia todas las implementaciones "once". Es útil cuando quieres reiniciar completamente la función simulada a su estado predeterminado.
Si quieres que este método se llame automáticamente antes de cada test, puedes habilitar la configuración mockReset
en la configuración.
mockRestore
- Tipo:
() => MockInstance
Realiza las acciones de mockReset
y restaura la implementación interna a la función original.
Ten en cuenta que restaurar una función simulada de vi.fn()
establecerá la implementación a una función vacía que devuelve undefined
. Restaurar un vi.fn(impl)
restaurará la implementación a impl
.
Si quieres que este método se llame automáticamente antes de cada test, puedes habilitar la configuración restoreMocks
en la configuración.
mockResolvedValue
- Tipo:
(value: any) => MockInstance
Acepta un valor que se resolverá cuando se llame a la función asíncrona.
import { vi } from 'vitest';
// ---cut---
const asyncMock = vi.fn().mockResolvedValue(42);
await asyncMock(); // 42
mockResolvedValueOnce
- Tipo:
(value: any) => MockInstance
Acepta un valor que se resolverá durante la siguiente llamada a la función. Si se encadena, cada llamada consecutiva resolverá el valor especificado.
import { vi } from 'vitest';
// ---cut---
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
- Tipo:
() => MockInstance
Usa esto si necesitas devolver el contexto this
desde el método sin invocar la implementación real. Esto es una forma abreviada de:
spy.mockImplementation(function () {
return this;
});
mockReturnValue
- Tipo:
(value: any) => MockInstance
Acepta un valor que se devolverá cada vez que se llame a la función simulada.
import { vi } from 'vitest';
// ---cut---
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
mockReturnValueOnce
- Tipo:
(value: any) => MockInstance
Acepta un valor que se devolverá durante la siguiente llamada a la función. Si se encadena, cada llamada consecutiva devolverá el valor especificado.
Cuando no hay más valores mockReturnValueOnce
para usar, la función simulada recurrirá a la implementación definida previamente, si existe.
import { vi } from 'vitest';
// ---cut---
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
Este es un array que contiene todos los argumentos para cada llamada. Un elemento del array son 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
Esto contiene los argumentos de la última llamada. Si la función simulada no se ha llamado, devolverá undefined
.
mock.results
Este es un array que contiene todos los valores que se returned
(devueltos) desde la función. Un elemento del array es un objeto con las propiedades type
y value
. Los tipos disponibles son:
'return'
- la función retornó sin lanzar una excepción.'throw'
- la función lanzó un valor (excepción).
La propiedad value
contiene el valor devuelto o el error lanzado. Si la función devolvió una promesa, el value
será el valor resuelto, no la Promise
real, a menos que nunca se haya resuelto.
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.invocationCallOrder
El orden de ejecución de la función simulada. Esto devuelve un array de números compartidos 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.instances
Este es un array que contiene todas las instancias que se instanciaron cuando se llamó al mock con la palabra clave new
. Ten en cuenta que este es el contexto (this
) de la función, no un valor de retorno.
WARNING
Si la función simulada se instanció 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 se devuelve un valor desde el constructor, no aparecerá en el array instances
, sino en results
:
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();
Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;