Saltar al contenido principal
Versión: 30.0

Pruebas de Instantáneas

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Las pruebas de instantáneas son una herramienta muy útil cuando quieres asegurarte de que tu interfaz de usuario no cambie de forma inesperada.

Un caso típico de prueba de instantánea renderiza un componente de UI, toma una instantánea y luego la compara con un archivo de instantánea de referencia almacenado junto a la prueba. La prueba fallará si las dos instantáneas no coinciden: o el cambio es inesperado, o la instantánea de referencia necesita actualizarse a la nueva versión del componente de UI.

Pruebas de Instantáneas con Jest

Puedes adoptar un enfoque similar al probar componentes de React. En lugar de renderizar la UI gráfica, lo que requeriría construir toda la aplicación, puedes usar un renderizador de pruebas para generar rápidamente un valor serializable para tu árbol de React. Considera este ejemplo de prueba para un componente Link:

import renderer from 'react-test-renderer';
import Link from '../Link';

it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.facebook.com">Facebook</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});

La primera vez que se ejecuta esta prueba, Jest crea un archivo de instantánea que luce así:

exports[`renders correctly 1`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Facebook
</a>
`;

El artefacto de instantánea debe confirmarse junto con los cambios de código y revisarse como parte de tu proceso de revisión de código. Jest usa pretty-format para hacer las instantáneas legibles durante la revisión de código. En ejecuciones posteriores de la prueba, Jest comparará la salida renderizada con la instantánea anterior. Si coinciden, la prueba pasará. Si no coinciden, o el ejecutor de pruebas encontró un error en tu código (en este caso, en el componente <Link>) que debe corregirse, o la implementación ha cambiado y la instantánea necesita actualizarse.

nota

La instantánea está directamente delimitada a los datos que renderizas – en nuestro ejemplo el componente <Link> con la prop page pasada. Esto implica que incluso si otro archivo tiene props faltantes (por ejemplo, App.js) en el componente <Link>, aún pasará la prueba porque la prueba no conoce el uso del componente <Link> y está delimitada solo al archivo Link.js. Además, renderizar el mismo componente con diferentes props en otras pruebas de instantáneas no afectará la primera, ya que las pruebas no se conocen entre sí.

información

Puedes encontrar más información sobre cómo funcionan las pruebas de instantáneas y por qué las creamos en la publicación de blog del lanzamiento. Recomendamos leer esta publicación de blog para entender mejor cuándo usar pruebas de instantáneas. También recomendamos ver este video de egghead sobre Pruebas de Instantáneas con Jest.

Actualizando Instantáneas

Es sencillo detectar cuándo falla una prueba de instantánea después de introducir un error. Cuando esto ocurra, corrige el problema y asegúrate de que tus pruebas de instantáneas vuelvan a pasar. Ahora hablemos del caso cuando una prueba de instantánea falla debido a un cambio intencional en la implementación.

Una situación así puede ocurrir si cambiamos intencionalmente la dirección a la que apunta el componente Link en nuestro ejemplo.

// Updated test case with a Link to a different address
it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.instagram.com">Instagram</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});

En ese caso, Jest mostrará esta salida:

Como acabamos de actualizar nuestro componente para apuntar a una dirección diferente, es razonable esperar cambios en la instantánea de este componente. Nuestro caso de prueba de instantánea falla porque la instantánea de nuestro componente actualizado ya no coincide con el artefacto de instantánea para este caso de prueba.

Para resolver esto, necesitaremos actualizar nuestros artefactos de instantánea. Puedes ejecutar Jest con una bandera que le indique regenerar las instantáneas:

jest --updateSnapshot

Adelante, acepta los cambios ejecutando el comando anterior. También puedes usar la bandera equivalente de un solo carácter -u para regenerar las instantáneas si lo prefieres. Esto regenerará los artefactos de instantánea para todas las pruebas de instantáneas fallidas. Si tuviéramos pruebas de instantáneas adicionales fallidas debido a un error no intencionado, necesitaríamos corregir el error antes de regenerar las instantáneas para evitar registrar instantáneas del comportamiento defectuoso.

Si deseas limitar qué casos de prueba de instantáneas se regeneran, puedes pasar una bandera adicional --testNamePattern para volver a grabar instantáneas solo para aquellas pruebas que coincidan con el patrón.

Puedes probar esta funcionalidad clonando el ejemplo de instantánea, modificando el componente Link y ejecutando Jest.

Modo Interactivo de Instantáneas

Las instantáneas fallidas también pueden actualizarse interactivamente en modo de observación:

Una vez que ingresas al Modo Interactivo de Instantáneas, Jest te guiará a través de las instantáneas fallidas una prueba a la vez y te dará la oportunidad de revisar la salida fallida.

Desde aquí puedes elegir actualizar esa instantánea o saltar a la siguiente:

Una vez que hayas terminado, Jest te mostrará un resumen antes de regresar al modo de observación:

Instantáneas en Línea

Las instantáneas en línea se comportan de manera idéntica a las instantáneas externas (archivos .snap), excepto que los valores de las instantáneas se escriben automáticamente en el código fuente. Esto significa que obtienes los beneficios de las instantáneas generadas automáticamente sin tener que cambiar a un archivo externo para verificar que se escribió el valor correcto.

Ejemplo:

Primero escribes una prueba, llamando a .toMatchInlineSnapshot() sin argumentos:

it('renders correctly', () => {
const tree = renderer
.create(<Link page="https://example.com">Example Site</Link>)
.toJSON();
expect(tree).toMatchInlineSnapshot();
});

La próxima vez que ejecutes Jest, tree será evaluado y se escribirá una instantánea como argumento para toMatchInlineSnapshot:

it('renders correctly', () => {
const tree = renderer
.create(<Link page="https://example.com">Example Site</Link>)
.toJSON();
expect(tree).toMatchInlineSnapshot(`
<a
className="normal"
href="https://example.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Example Site
</a>
`);
});

¡Eso es todo! Incluso puedes actualizar las instantáneas con --updateSnapshot o usando la tecla u en modo --watch.

Por defecto, Jest maneja la escritura de instantáneas en tu código fuente. Sin embargo, si usas prettier en tu proyecto, Jest detectará esto y delegará el trabajo a prettier (respetando tu configuración).

Comparadores de Propiedades

A menudo hay campos en el objeto que deseas capturar en instantáneas que se generan dinámicamente (como IDs y fechas). Si intentas capturar estos objetos en instantáneas, harán que la prueba falle en cada ejecución:

it('will fail every time', () => {
const user = {
createdAt: new Date(),
id: Math.floor(Math.random() * 20),
name: 'LeBron James',
};

expect(user).toMatchSnapshot();
});

// Snapshot
exports[`will fail every time 1`] = `
{
"createdAt": 2018-05-19T23:36:09.816Z,
"id": 3,
"name": "LeBron James",
}
`;

Para estos casos, Jest permite proporcionar un comparador asimétrico para cualquier propiedad. Estos comparadores se verifican antes de escribir o probar la instantánea, y luego se guardan en el archivo de instantánea en lugar del valor recibido:

it('will check the matchers and pass', () => {
const user = {
createdAt: new Date(),
id: Math.floor(Math.random() * 20),
name: 'LeBron James',
};

expect(user).toMatchSnapshot({
createdAt: expect.any(Date),
id: expect.any(Number),
});
});

// Snapshot
exports[`will check the matchers and pass 1`] = `
{
"createdAt": Any<Date>,
"id": Any<Number>,
"name": "LeBron James",
}
`;

Cualquier valor que no sea un comparador se verificará exactamente y se guardará en la instantánea:

it('will check the values and pass', () => {
const user = {
createdAt: new Date(),
name: 'Bond... James Bond',
};

expect(user).toMatchSnapshot({
createdAt: expect.any(Date),
name: 'Bond... James Bond',
});
});

// Snapshot
exports[`will check the values and pass 1`] = `
{
"createdAt": Any<Date>,
"name": 'Bond... James Bond',
}
`;

Si el caso implica una cadena y no un objeto, necesitas reemplazar la parte aleatoria de esa cadena por tu cuenta antes de probar la instantánea.
Puedes usar para esto replace() y expresiones regulares.

const randomNumber = Math.round(Math.random() * 100);
const stringWithRandomData = `<div id="${randomNumber}">Lorem ipsum</div>`;
const stringWithConstantData = stringWithRandomData.replace(/id="\d+"/, 123);
expect(stringWithConstantData).toMatchSnapshot();

Otras formas de hacerlo son usando el serializador de instantáneas o simulando la biblioteca responsable de generar la parte aleatoria del código que estás capturando.

Mejores Prácticas

Las instantáneas son una herramienta fantástica para identificar cambios inesperados en la interfaz de tu aplicación, ya sea que esa interfaz sea una respuesta de API, una UI, registros o mensajes de error. Como con cualquier estrategia de pruebas, existen algunas mejores prácticas que debes conocer y pautas que debes seguir para usarlas efectivamente.

1. Trata las instantáneas como código

Confirma las instantáneas en tu repositorio y revísalas como parte de tu proceso regular de revisión de código. Esto significa tratar las instantáneas como tratarías cualquier otro tipo de prueba o código en tu proyecto.

Asegúrate de que tus instantáneas sean legibles manteniéndolas enfocadas, breves y utilizando herramientas que hagan cumplir estas convenciones estilísticas.

Como se mencionó anteriormente, Jest usa pretty-format para hacer que las instantáneas sean legibles para humanos, pero puede resultarte útil introducir herramientas adicionales como eslint-plugin-jest con su opción no-large-snapshots, o snapshot-diff con su función de comparación de instantáneas de componentes, para promover la confirmación de aserciones cortas y enfocadas.

El objetivo es facilitar la revisión de instantáneas en las pull requests y combatir el hábito de regenerar instantáneas cuando las suites de prueba fallan en lugar de examinar las causas raíz de sus fallos.

2. Las pruebas deben ser deterministas

Tus pruebas deben ser deterministas. Ejecutar las mismas pruebas múltiples veces en un componente que no ha cambiado debería producir los mismos resultados cada vez. Eres responsable de asegurarte de que tus instantáneas generadas no incluyan datos específicos de plataforma u otros datos no deterministas.

Por ejemplo, si tienes un componente Clock que usa Date.now(), la instantánea generada será diferente cada vez que se ejecute el caso de prueba. En este caso podemos simular el método Date.now() para que devuelva un valor consistente cada vez que se ejecute la prueba:

Date.now = jest.fn(() => 1_482_363_367_071);

Ahora, cada vez que se ejecute el caso de prueba de instantánea, Date.now() devolverá consistentemente 1482363367071. Esto generará la misma instantánea para este componente independientemente de cuándo se ejecute la prueba.

3. Usa nombres descriptivos para las instantáneas

Siempre procura usar nombres descriptivos de pruebas y/o instantáneas. Los mejores nombres describen el contenido esperado de la instantánea. Esto facilita que los revisores verifiquen las instantáneas durante la revisión y que cualquiera pueda determinar si una instantánea desactualizada muestra el comportamiento correcto antes de actualizarla.

Por ejemplo, compara:

exports[`<UserName /> should handle some test case`] = `null`;

exports[`<UserName /> should handle some other test case`] = `
<div>
Alan Turing
</div>
`;

Para:

exports[`<UserName /> should render null`] = `null`;

exports[`<UserName /> should render Alan Turing`] = `
<div>
Alan Turing
</div>
`;

Con:

exports[`<UserName /> should render null`] = `
<div>
Alan Turing
</div>
`;

exports[`<UserName /> should render Alan Turing`] = `null`;

Preguntas Frecuentes

Preguntas frecuentes

No, a partir de Jest 20, las instantáneas en Jest no se escriben automáticamente cuando Jest se ejecuta en un sistema de CI sin pasar explícitamente --updateSnapshot. Se espera que todas las instantáneas formen parte del código que se ejecuta en CI y, dado que las nuevas instantáneas pasan automáticamente, no deberían pasar una ejecución de pruebas en un sistema de CI. Se recomienda siempre confirmar todas las instantáneas y mantenerlas en el control de versiones.

¿Se deben confirmar los archivos de instantáneas?

¿Se deben confirmar los archivos de instantáneas?

¿Funciona la prueba de instantáneas solo con componentes de React?

Los componentes de React y React Native son un buen caso de uso para las pruebas de instantáneas. Sin embargo, las instantáneas pueden capturar cualquier valor serializable y deberían usarse siempre que el objetivo sea probar si la salida es correcta. El repositorio de Jest contiene muchos ejemplos de pruebas de la salida del propio Jest, la salida de la librería de aserciones de Jest así como mensajes de registro de varias partes de la base de código de Jest. Consulta un ejemplo de captura de instantánea de la salida de la CLI en el repositorio de Jest.

¿Cuál es la diferencia entre pruebas de instantáneas y pruebas de regresión visual?

Las pruebas de instantáneas y las pruebas de regresión visual son dos enfoques distintos para probar interfaces de usuario, y sirven para propósitos diferentes. Las herramientas de regresión visual capturan pantallas de páginas web y comparan las imágenes resultantes píxel por píxel. En las pruebas de instantáneas, los valores se serializan, almacenan en archivos de texto y se comparan mediante un algoritmo de diferencias. Existen diferentes compensaciones a considerar, y enumeramos las razones para crear pruebas de instantáneas en el blog de Jest.

¿Reemplazan las pruebas de instantáneas a las pruebas unitarias?

Las pruebas de instantáneas son solo una de las más de 20 aserciones incluidas en Jest. Su objetivo no es reemplazar las pruebas unitarias existentes, sino aportar valor adicional y simplificar las pruebas. En algunos escenarios, las pruebas de instantáneas podrían eliminar la necesidad de pruebas unitarias para funcionalidades específicas (ej. componentes React), aunque también pueden funcionar conjuntamente.

¿Cómo es el rendimiento de las pruebas de instantáneas en velocidad y tamaño de archivos?

Jest se ha reescrito priorizando el rendimiento, y las pruebas de instantáneas no son la excepción. Al almacenarse en archivos de texto, este enfoque es rápido y confiable. Jest genera un nuevo archivo por cada archivo de prueba que usa el comparador toMatchSnapshot. El tamaño de las instantáneas es bastante reducido: como referencia, todos los archivos de instantáneas en la base de código de Jest ocupan menos de 300 KB.

¿Cómo resuelvo conflictos en archivos de instantáneas?

Los archivos de instantáneas siempre deben reflejar el estado actual de los módulos que cubren. Por lo tanto, si encuentras conflictos al fusionar ramas, puedes resolverlos manualmente o actualizar el archivo de instantáneas ejecutando Jest y revisando el resultado.

¿Puedo aplicar principios de desarrollo guiado por pruebas (TDD) con instantáneas?

Aunque es posible escribir archivos de instantáneas manualmente, esto no suele ser práctico. Las instantáneas ayudan a detectar cambios en la salida de los módulos cubiertos, no a guiar el diseño inicial del código.

¿Funciona la cobertura de código con pruebas de instantáneas?

Sí, al igual que con cualquier otra prueba.