Saltar al contenido principal

Migrar desde Enzyme

[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 →

Esta página está dirigida a desarrolladores con experiencia en Enzyme que desean entender cómo migrar a React Testing Library. No profundiza en cómo migrar todos los tipos de pruebas, pero ofrece información útil para quienes comparan Enzyme con React Testing Library.

¿Qué es React Testing Library?

React Testing Library forma parte de un proyecto de código abierto llamado Testing Library. El proyecto Testing Library incluye varias herramientas y bibliotecas adicionales que puedes usar para escribir pruebas más concisas y útiles. Además de React Testing Library, estas son otras bibliotecas del proyecto que pueden ayudarte:

  • @testing-library/jest-dom: jest-dom proporciona un conjunto de matchers personalizados para Jest que extienden sus capacidades. Esto hace tus pruebas más declarativas, más claras de leer y más fáciles de mantener.

  • @testing-library/user-event: user-event simula eventos reales del navegador que ocurren cuando el usuario interactúa con elementos de la página. Por ejemplo, userEvent.click(checkbox) cambiaría el estado del checkbox.

¿Por qué debería usar React Testing Library?

Enzyme es una biblioteca de pruebas poderosa y sus colaboradores han contribuido significativamente a la comunidad JavaScript. De hecho, muchos mantenedores de React Testing Library usaron y contribuyeron a Enzyme durante años antes de desarrollar React Testing Library. ¡Queremos agradecer a los colaboradores de Enzyme!

El propósito principal de React Testing Library es aumentar la confianza en tus pruebas evaluando componentes como lo haría un usuario. A los usuarios no les importa lo que ocurre internamente, solo ven e interactúan con el resultado. En lugar de acceder a APIs internas de componentes o evaluar su state, obtendrás mayor confianza escribiendo pruebas basadas en el resultado del componente.

React Testing Library resuelve un problema común al escribir pruebas con Enzyme, que permite (e incentiva) probar detalles de implementación. Estas pruebas impiden modificar y refactorizar componentes sin cambiar sus pruebas. Como resultado, las pruebas ralentizan la velocidad de desarrollo y productividad. Cada cambio pequeño puede requerir reescribir parte de tus pruebas, incluso si no afecta el resultado del componente.

Reescribir tus pruebas en React Testing Library vale la pena porque intercambiarás pruebas que te ralentizan por pruebas que brindan más confianza y aumentan tu productividad a largo plazo.

¿Cómo migrar desde Enzyme a React Testing Library?

Para una migración exitosa, recomendamos un enfoque incremental ejecutando ambas bibliotecas simultáneamente en la misma aplicación, migrando pruebas de Enzyme a React Testing Library una por una. Esto permite migrar incluso aplicaciones grandes y complejas sin afectar otras operaciones, ya que el trabajo puede realizarse colaborativamente y distribuirse en el tiempo.

Instalar React Testing Library

Primero, instala React Testing Library y la biblioteca de utilidades jest-dom (puedes consultar esta página para la guía completa de instalación y configuración).

npm install --save-dev @testing-library/react @testing-library/jest-dom

Importar React Testing Library en tu prueba

Si usas Jest (puedes usar otros frameworks de pruebas), solo necesitas importar estos módulos en tu archivo de prueba:

// import React so you can use JSX (React.createElement) in your test
import React from 'react'

/**
* render: lets us render the component as React would
* screen: a utility for finding elements the same way the user does
*/
import {render, screen} from '@testing-library/react'

La estructura de la prueba puede ser similar a como la escribirías con Enzyme:

test('test title', () => {
// Your tests come here...
})

Nota: también puedes usar bloques describe e it con React Testing Library. React Testing Library no reemplaza Jest, solo Enzyme. Recomendamos test porque ayuda con esto: Avoid Nesting When You're Testing.

Ejemplos básicos de migración de Enzyme a React Testing Library

Es importante tener en cuenta que no existe una correspondencia directa entre las funciones de Enzyme y React Testing Library. Muchas características de Enzyme generan pruebas ineficientes, por lo que algunas funcionalidades a las que estás acostumbrado en Enzyme deberán dejarse atrás (como la variable wrapper o las llamadas a wrapper.update(), etc.).

React Testing Library ofrece consultas útiles que te permiten acceder a los elementos de tu componente y sus propiedades. Mostraremos algunos tests típicos de Enzyme junto con alternativas usando React Testing Library.

Supongamos que tenemos un componente Welcome que muestra un mensaje de bienvenida. Examinaremos tanto los tests de Enzyme como de React Testing Library para aprender cómo probar este componente:

Componente React

El siguiente componente recibe un name por props y muestra un mensaje de bienvenida en un elemento h1. También tiene un campo de texto que los usuarios pueden modificar para cambiar el nombre, actualizando la plantilla en consecuencia. Consulta la versión en vivo en CodeSandbox.

const Welcome = props => {
const [values, setValues] = useState({
firstName: props.firstName,
lastName: props.lastName,
})

const handleChange = event => {
setValues({...values, [event.target.name]: event.target.value})
}

return (
<div>
<h1>
Welcome, {values.firstName} {values.lastName}
</h1>

<form name="userName">
<label>
First Name
<input
value={values.firstName}
name="firstName"
onChange={handleChange}
/>
</label>

<label>
Last Name
<input
value={values.lastName}
name="lastName"
onChange={handleChange}
/>
</label>
</form>
</div>
)
}

export default Welcome

Prueba 1: Renderizar el componente y verificar que el valor de h1 sea correcto

Test con Enzyme

test('has correct welcome text', () => {
const wrapper = shallow(<Welcome firstName="John" lastName="Doe" />)
expect(wrapper.find('h1').text()).toEqual('Welcome, John Doe')
})

Test con React Testing Library

test('has correct welcome text', () => {
render(<Welcome firstName="John" lastName="Doe" />)
expect(screen.getByRole('heading')).toHaveTextContent('Welcome, John Doe')
})

Como ves, los tests son bastante similares. El renderizador shallow de Enzyme no renderiza subcomponentes, por lo que el método render de React Testing Library se asemeja más al método mount de Enzyme.

En React Testing Library, no necesitas asignar el resultado de render a una variable (como wrapper). Puedes acceder directamente al resultado renderizado mediante funciones del objeto screen. Otro aspecto positivo es que React Testing Library limpia automáticamente el entorno después de cada test, por lo que no necesitas llamar a cleanup en funciones afterEach o beforeEach.

Otro detalle que notarás es getByRole con 'heading' como argumento. 'heading' es el rol accesible del elemento h1. Puedes aprender más sobre estos conceptos en la página de documentación de consultas. Algo que la gente aprende rápidamente a valorar de Testing Library es cómo fomenta la creación de aplicaciones más accesibles (porque si no es accesible, es más difícil de probar).

Prueba 2: Los textos de entrada deben tener el valor correcto

En el componente anterior, los valores de entrada se inicializan con los valores props.firstName y props.lastName. Necesitamos verificar si el valor es correcto.

Enzyme

test('has correct input value', () => {
const wrapper = shallow(<Welcome firstName="John" lastName="Doe" />)
expect(wrapper.find('input[name="firstName"]').value).toEqual('John')
expect(wrapper.find('input[name="lastName"]').value).toEqual('Doe')
})

React Testing Library

test('has correct input value', () => {
render(<Welcome firstName="John" lastName="Doe" />)
expect(screen.getByRole('form')).toHaveFormValues({
firstName: 'John',
lastName: 'Doe',
})
})

¡Genial! Es bastante simple y práctico, y los tests son lo suficientemente claros como para no requerir mucha explicación. Algo que podrías notar es que el <form> tiene un atributo role="form", pero ¿qué significa?

role es uno de los atributos relacionados con accesibilidad que se recomienda usar para mejorar tu aplicación web para personas con discapacidades. Algunos elementos tienen valores role predeterminados y no necesitas establecerlos, pero otros como <div> no tienen valores role predeterminados. Puedes usar diferentes enfoques para acceder al elemento <div>, pero recomendamos intentar acceder a los elementos mediante su role implícito para garantizar que tu componente sea accesible para personas con discapacidades y usuarios de lectores de pantalla. Esta sección de la documentación de consultas puede ayudarte a comprender mejor los conceptos.

Un elemento <form> debe tener un atributo name para tener un role implícito de 'form' (según lo requiere la especificación).

React Testing Library busca probar los componentes como los usuarios los utilizan. Los usuarios ven botones, encabezados, formularios y otros elementos por su función, no por su id, class o nombre de etiqueta. Por lo tanto, al usar React Testing Library debes evitar acceder al DOM con la API document.querySelector. (Puedes usarla en tus pruebas, pero no se recomienda por las razones mencionadas en este párrafo).

React Testing Library expone algunas API de consulta prácticas que te ayudan a acceder eficientemente a los elementos del componente. Puedes ver la lista de consultas disponibles aquí. Si no estás seguro de qué consulta usar en una situación dada, tenemos una excelente página que explica qué consulta usar, ¡échale un vistazo!

Si aún tienes dudas sobre qué consulta de React Testing Library utilizar, visita testing-playground.com y la extensión de Chrome Testing Playground, cuyo objetivo es permitir que los desarrolladores encuentren la mejor consulta al escribir pruebas. También te ayuda a encontrar las mejores consultas para seleccionar elementos. Te permite inspeccionar las jerarquías de elementos en las Chrome Developer Tools y te proporciona sugerencias sobre cómo seleccionarlos, todo mientras fomenta buenas prácticas de pruebas.

Usando act() y wrapper.update()

Al probar código asíncrono en Enzyme, normalmente necesitas llamar a act() para ejecutar correctamente tus pruebas. Con React Testing Library, no necesitas llamar explícitamente a act() la mayoría de las veces porque envuelve las llamadas API con act() por defecto.

update() sincroniza la instantánea del árbol de componentes de Enzyme con el árbol de componentes de React, por lo que puedes ver wrapper.update() en pruebas de Enzyme. React Testing Library no tiene (ni necesita) un método similar, ¡lo cual es bueno porque tienes que manejar menos cosas!

Simular eventos de usuario

Hay dos formas de simular eventos de usuario con React Testing Library. Una es usar la biblioteca user-event, y la otra es usar fireEvent que está incluida en React Testing Library. user-event realmente está construida sobre fireEvent (que simplemente llama a dispatchEvent en el elemento dado). Generalmente se recomienda user-event porque garantiza que todos los eventos se disparen en el orden correcto para interacciones de usuario típicas. Esto ayuda a asegurar que tus pruebas se asemejen a cómo se usa realmente tu software.

Para usar el módulo @testing-library/user-event, primero instálalo:

npm install --save-dev @testing-library/user-event @testing-library/dom

Ahora puedes importarlo en tu prueba:

import userEvent from '@testing-library/user-event'

Para demostrar cómo usar la biblioteca user-event, imagina que tenemos un componente Checkbox que muestra un input de tipo checkbox y una etiqueta asociada. Queremos simular el evento de un usuario haciendo clic en el checkbox:

import React from 'react'

const Checkbox = () => {
return (
<div>
<label htmlFor="checkbox">Check</label>
<input id="checkbox" type="checkbox" />
</div>
)
}

export default Checkbox

Queremos probar que cuando un usuario hace clic en la etiqueta asociada al checkbox, la propiedad "checked" del input se establece correctamente. Veamos cómo podríamos escribir una prueba para ese caso:

test('handles click correctly', async () => {
render(<Checkbox />)
const user = userEvent.setup()

// You can also call this method directly on userEvent,
// but using the methods from `.setup()` is recommended.
await user.click(screen.getByText('Check'))

expect(screen.getByLabelText('Check')).toBeChecked()
})

¡Perfecto!

Activar métodos de clase en pruebas (wrapper.instance())

Como ya discutimos, recomendamos no probar detalles de implementación y cosas que los usuarios no percibirán. Nuestro objetivo es probar e interactuar con el componente de manera más similar a como lo harían nuestros usuarios.

Si tu prueba usa `instance()` o `state()`, ten en cuenta que estás probando aspectos que el usuario no podría conocer ni le importarían, lo que alejará tus pruebas de brindarte confianza en que las cosas funcionarán cuando tu usuario las utilice. — Kent C. Dodds

Si no estás seguro de cómo probar algo interno de tu componente, da un paso atrás y considera: "¿Qué haría el usuario para activar la ejecución de este código?" Luego haz que tu prueba haga eso.

¿Cómo hacer renderizado superficial (shallow) de un componente?

En general, debes evitar simular componentes. Sin embargo, si necesitas hacerlo, intenta usar las funciones de simulación de Jest. Para más información, consulta las FAQ.