Instantáneas
Aprende sobre instantáneas con video en Vue SchoolLas pruebas de instantáneas son una herramienta muy útil para asegurar que la salida de tus funciones no cambie de forma inesperada.
Al utilizar instantáneas, Vitest captura el valor proporcionado y lo compara con un archivo de instantánea de referencia almacenado junto a la prueba. La prueba fallará si las dos instantáneas no coinciden, ya sea porque el cambio fue inesperado o porque la instantánea de referencia necesita ser actualizada con la nueva versión del resultado.
Uso de Instantáneas
Para capturar una instantánea de un valor, puedes usar toMatchSnapshot()
de la API expect()
:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
La primera vez que se ejecuta esta prueba, Vitest crea un archivo de instantánea con el siguiente contenido:
// Vitest Snapshot v1, https://www.getbook.com/es/book/vitest-1/guide/snapshot
exports['toUpperCase 1'] = '"FOOBAR"';
El artefacto de la instantánea debe ser confirmado (commit) junto con los cambios de código y revisado como parte de tu proceso de revisión de código. En ejecuciones de prueba posteriores, Vitest comparará la salida generada con la instantánea almacenada previamente. Si coinciden, la prueba pasará. Si no coinciden, significa que el ejecutor de pruebas ha encontrado un error en tu código que debe ser corregido, o que la implementación ha cambiado y la instantánea necesita ser actualizada.
WARNING
Al usar instantáneas con pruebas asíncronas concurrentes, se debe utilizar el expect
del Contexto de Prueba local para asegurar que la prueba correcta sea detectada.
Instantáneas en Línea
De manera similar, puedes usar toMatchInlineSnapshot()
para almacenar la instantánea directamente en el archivo de prueba.
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot();
});
En lugar de crear un archivo de instantánea, Vitest modificará el archivo de prueba directamente para actualizar la instantánea como una cadena:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});
Esto te permite ver la salida esperada directamente, sin necesidad de cambiar entre diferentes archivos.
WARNING
Al usar instantáneas con pruebas asíncronas concurrentes, se debe utilizar el expect
del Contexto de Prueba local para asegurar que la prueba correcta sea detectada.
Actualización de Instantáneas
Cuando el valor recibido no coincide con la instantánea, la prueba falla y muestra la diferencia entre ambos. Si el cambio en la instantánea es esperado, es posible que desees actualizarla al estado actual.
En modo watch
, puedes presionar la tecla u
en la terminal para actualizar directamente la instantánea fallida.
Alternativamente, puedes usar la opción --update
o -u
en la CLI para que Vitest actualice las instantáneas.
vitest -u
Instantáneas de Archivos
Al llamar a toMatchSnapshot()
, todas las instantáneas se almacenan en un archivo de instantáneas formateado. Esto implica que debemos escapar algunos caracteres (específicamente las comillas dobles "
y las comillas invertidas `
) en la cadena de la instantánea. Además, podrías perder el resaltado de sintaxis para el contenido de la instantánea (si está en algún idioma específico).
Por esta razón, introdujimos toMatchFileSnapshot()
para comparar explícitamente con un archivo. Esto te permite asignar cualquier extensión de archivo a la instantánea, haciéndola más legible.
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Se comparará con el contenido de ./test/basic.output.html
. Y puede actualizarse con la opción --update
.
Instantáneas de Imágenes
También es posible crear instantáneas de imágenes utilizando jest-image-snapshot
.
npm i -D jest-image-snapshot
test('image snapshot', () => {
expect(readFileSync('./test/stubs/input-image.png')).toMatchImageSnapshot();
});
Serializador Personalizado
Puedes añadir tu propia lógica para modificar cómo se serializan tus instantáneas. Al igual que Jest, Vitest tiene serializadores por defecto para tipos nativos de JavaScript, elementos HTML, ImmutableJS y elementos React.
Puedes añadir explícitamente un serializador personalizado utilizando la API expect.addSnapshotSerializer
.
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
// `printer` es una función que serializa un valor utilizando los plugins existentes.
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
});
También admitimos la opción snapshotSerializers para añadir serializadores personalizados implícitamente.
import { SnapshotSerializer } from 'vitest';
export default {
serialize(val, config, indentation, depth, refs, printer) {
// `printer` es una función que serializa un valor utilizando los plugins existentes.
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
} satisfies SnapshotSerializer;
import { defineConfig } from 'vite';
export default defineConfig({
test: {
snapshotSerializers: ['path/to/custom-serializer.ts'],
},
});
Después de añadir una prueba como esta:
test('foo snapshot test', () => {
const bar = {
foo: {
x: 1,
y: 2,
},
};
expect(bar).toMatchSnapshot();
});
Obtendrás la siguiente instantánea:
Pretty foo: Object {
"x": 1,
"y": 2,
}
Estamos utilizando pretty-format
de Jest para serializar instantáneas. Puedes leer más al respecto aquí: pretty-format.
Diferencias con Jest
Vitest proporciona una característica de Instantáneas casi compatible con la de Jest con algunas excepciones:
1. El encabezado de comentario en el archivo de instantánea es diferente {#_1-comment-header-in-the-snapshot-file-is-different}
- // Jest Snapshot v1, https://goo.gl/fbAQLP
+ // Vitest Snapshot v1, https://www.getbook.com/es/book/vitest-1/guide/snapshot
Esto no afecta la funcionalidad, pero puede influir en el diff
de tus commits al migrar desde Jest.
2. printBasicPrototype
es false
por defecto {#_2-printbasicprototype-is-default-to-false}
Tanto las instantáneas de Jest como las de Vitest están impulsadas por pretty-format
. En Vitest, configuramos printBasicPrototype
a false
por defecto para proporcionar una salida de instantánea más limpia, mientras que en Jest <29.0.0 es true
por defecto.
import { expect, test } from 'vitest';
test('snapshot', () => {
const bar = [
{
foo: 'bar',
},
];
// en Jest
expect(bar).toMatchInlineSnapshot(`
Array [
Object {
"foo": "bar",
},
]
`);
// en Vitest
expect(bar).toMatchInlineSnapshot(`
[
{
"foo": "bar",
},
]
`);
});
Creemos que este es un valor predeterminado más razonable para la legibilidad y la experiencia de desarrollo (DX) en general. Si aún prefieres el comportamiento de Jest, puedes cambiar tu configuración:
// vitest.config.js
export default defineConfig({
test: {
snapshotFormat: {
printBasicPrototype: true,
},
},
});
3. El símbolo de mayor que >
se usa como separador en lugar de dos puntos :
para mensajes personalizados {#_3-chevron-is-used-as-a-separator-instead-of-colon-for-custom-messages}
Vitest usa el símbolo de mayor que >
como separador en lugar de dos puntos :
para mayor legibilidad, cuando se pasa un mensaje personalizado durante la creación de un archivo de instantánea.
Para el siguiente código de prueba de ejemplo:
test('toThrowErrorMatchingSnapshot', () => {
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingSnapshot('hint');
});
En Jest, la instantánea será:
exports[`toThrowErrorMatchingSnapshot: hint 1`] = `"error"`;
En Vitest, la instantánea equivalente será:
exports[`toThrowErrorMatchingSnapshot > hint 1`] = `[Error: error]`;
4. La instantánea de Error
predeterminada es diferente para toThrowErrorMatchingSnapshot
y toThrowErrorMatchingInlineSnapshot
{#_4-default-error-snapshot-is-different-for-tothrowerrormatchingsnapshot-and-tothrowerrormatchinginlinesnapshot}
import { expect, test } from 'vitest';
test('snapshot', () => {
// en Jest y Vitest
expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`);
// Jest captura el `Error.message` en las instantáneas para la instancia de `Error`
// Vitest imprime el mismo valor que toMatchInlineSnapshot
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingInlineSnapshot(`"error"`);
}).toThrowErrorMatchingInlineSnapshot(`[Error: error]`);
});