Extender Matchers
Dado que Vitest es compatible tanto con Chai como con Jest, puedes elegir entre usar la API chai.use
o expect.extend
.
Esta guía se centrará en cómo extender los matchers con expect.extend
. Si te interesa la API de Chai, consulta su guía.
Para extender los matchers predeterminados, llama a expect.extend
con un objeto que contenga tus matchers personalizados.
expect.extend({
toBeFoo(received, expected) {
const { isNot } = this;
return {
// No modifiques el valor de "pass" basándote en isNot. Vitest lo gestiona automáticamente.
pass: received === 'foo',
message: () => `${received} is${isNot ? ' not' : ''} foo`,
};
},
});
Si estás utilizando TypeScript, puedes extender la interfaz Assertion
predeterminada en un archivo de declaración de entorno (por ejemplo: vitest.d.ts
) con el siguiente código:
import 'vitest';
interface CustomMatchers<R = unknown> {
toBeFoo: () => R;
}
declare module 'vitest' {
interface Matchers<T = any> extends CustomMatchers<T> {}
}
import 'vitest';
interface CustomMatchers<R = unknown> {
toBeFoo: () => R;
}
declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}
TIP
A partir de Vitest 3.2, puedes extender la interfaz Matchers
para obtener aserciones de tipo seguro en los métodos expect.extend
, expect().*
y expect.*
simultáneamente. Anteriormente, era necesario definir interfaces separadas para cada uno de ellos.
WARNING
No olvides incluir el archivo de declaración de entorno en tu tsconfig.json
.
El valor de retorno de un matcher debe ser compatible con la siguiente interfaz:
interface ExpectationResult {
pass: boolean;
message: () => string;
// Si proporcionas estos valores, aparecerán automáticamente en un diff cuando
// el matcher falle, eliminando la necesidad de imprimir el diff manualmente.
actual?: unknown;
expected?: unknown;
}
WARNING
Si creas un matcher asíncrono, recuerda usar await
con el resultado (await expect('foo').toBeFoo()
) en la prueba:
expect.extend({
async toBeAsyncAssertion() {
// ...
},
});
await expect().toBeAsyncAssertion();
El primer argumento dentro de la función de un matcher es el valor recibido (el que se pasa a expect(received)
). Los argumentos adicionales se pasan directamente al matcher.
La función del matcher tiene acceso al contexto this
con las siguientes propiedades:
isNot
Devuelve true
si el matcher fue llamado con not
(expect(received).not.toBeFoo()
).
promise
Si el matcher fue llamado con los modificadores resolved
o rejected
, este valor contendrá el nombre del modificador. De lo contrario, será una cadena vacía.
equals
Esta es una función de utilidad que te permite comparar dos valores. Devolverá true
si los valores son iguales, false
en caso contrario. Esta función se utiliza internamente para casi todos los matchers y, por defecto, soporta objetos con matchers asimétricos.
utils
Contiene un conjunto de funciones de utilidad que puedes usar para formatear mensajes.
El contexto this
también contiene información sobre la prueba actual. También puedes obtenerla llamando a expect.getState()
. Las propiedades más útiles son:
currentTestName
Nombre completo de la prueba actual (incluido el bloque describe).
testPath
Ruta al archivo de la prueba actual.