Introducción
React Testing Library (RTL) es una herramienta diseñada para probar componentes de React de una manera que se asemeje a cómo los usuarios interactúan con la aplicación. A diferencia de otras bibliotecas de pruebas, RTL se enfoca en la accesibilidad y en probar el comportamiento de los componentes en lugar de sus implementaciones internas.
Objetivos de esta sección:
- Entender los conceptos básicos de React Testing Library.
- Aprender a configurar React Testing Library en un proyecto de React.
- Escribir pruebas básicas para componentes de React.
- Explorar técnicas avanzadas para pruebas de componentes.
Configuración de React Testing Library
Para comenzar a usar React Testing Library, primero necesitas instalarla junto con Jest, que es el framework de pruebas recomendado.
Instalación
Ejecuta el siguiente comando para instalar React Testing Library y Jest:
Configuración de Jest
Asegúrate de que Jest esté configurado en tu proyecto. Puedes agregar un script en tu package.json
para ejecutar las pruebas:
Escribiendo Pruebas Básicas
Estructura de una Prueba
Una prueba básica en React Testing Library sigue esta estructura:
- Renderizar el componente: Usamos la función
render
para montar el componente en un contenedor de prueba. - Seleccionar elementos: Utilizamos selectores para encontrar elementos en el DOM.
- Realizar acciones: Simulamos interacciones del usuario, como clics o cambios de entrada.
- Afirmar resultados: Verificamos que el componente se comporte como se espera.
Ejemplo Práctico
Vamos a escribir una prueba para un componente simple de botón que cambia su texto al hacer clic.
Componente: Button.js
import React, { useState } from 'react'; const Button = () => { const [text, setText] = useState('Click me'); return ( <button onClick={() => setText('Clicked!')}> {text} </button> ); }; export default Button;
Prueba: Button.test.js
import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import Button from './Button'; test('cambia el texto al hacer clic', () => { // Renderizar el componente render(<Button />); // Seleccionar el botón por su texto inicial const buttonElement = screen.getByText('Click me'); // Simular un clic en el botón fireEvent.click(buttonElement); // Afirmar que el texto del botón ha cambiado expect(buttonElement).toHaveTextContent('Clicked!'); });
Explicación del Código
-
Renderizar el componente:
render(<Button />);
- Montamos el componente
Button
en un contenedor de prueba.
- Montamos el componente
-
Seleccionar elementos:
screen.getByText('Click me');
- Usamos
screen.getByText
para encontrar el botón por su texto inicial.
- Usamos
-
Realizar acciones:
fireEvent.click(buttonElement);
- Simulamos un clic en el botón usando
fireEvent.click
.
- Simulamos un clic en el botón usando
-
Afirmar resultados:
expect(buttonElement).toHaveTextContent('Clicked!');
- Verificamos que el texto del botón haya cambiado a "Clicked!".
Técnicas Avanzadas
Pruebas Asíncronas
Algunas veces, los componentes realizan operaciones asíncronas, como llamadas a API. React Testing Library proporciona herramientas para manejar estas situaciones.
Ejemplo: Componente Asíncrono
import React, { useState, useEffect } from 'react'; const AsyncComponent = () => { const [data, setData] = useState(null); useEffect(() => { setTimeout(() => { setData('Data loaded'); }, 1000); }, []); return ( <div> {data ? data : 'Loading...'} </div> ); }; export default AsyncComponent;
Prueba: AsyncComponent.test.js
import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import AsyncComponent from './AsyncComponent'; test('muestra datos cargados después de la carga', async () => { render(<AsyncComponent />); // Afirmar que el texto inicial es "Loading..." expect(screen.getByText('Loading...')).toBeInTheDocument(); // Esperar a que el texto cambie a "Data loaded" await waitFor(() => expect(screen.getByText('Data loaded')).toBeInTheDocument()); });
Explicación del Código
-
Renderizar el componente:
render(<AsyncComponent />);
- Montamos el componente
AsyncComponent
en un contenedor de prueba.
- Montamos el componente
-
Afirmar el estado inicial:
expect(screen.getByText('Loading...')).toBeInTheDocument();
- Verificamos que el texto inicial sea "Loading...".
-
Esperar y afirmar el estado final:
await waitFor(() => expect(screen.getByText('Data loaded')).toBeInTheDocument());
- Usamos
waitFor
para esperar a que el texto cambie a "Data loaded".
- Usamos
Ejercicios Prácticos
Ejercicio 1: Prueba de un Componente de Entrada
Crea un componente de entrada que actualice su valor en el estado y escribe una prueba para verificar que el valor se actualiza correctamente.
Componente: Input.js
import React, { useState } from 'react'; const Input = () => { const [value, setValue] = useState(''); return ( <input type="text" value={value} onChange={(e) => setValue(e.target.value)} /> ); }; export default Input;
Prueba: Input.test.js
import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import Input from './Input'; test('actualiza el valor del input al escribir', () => { render(<Input />); const inputElement = screen.getByRole('textbox'); fireEvent.change(inputElement, { target: { value: 'Hello' } }); expect(inputElement).toHaveValue('Hello'); });
Ejercicio 2: Prueba de un Componente de Lista
Crea un componente que renderice una lista de elementos y escribe una prueba para verificar que los elementos se renderizan correctamente.
Componente: List.js
import React from 'react'; const List = ({ items }) => { return ( <ul> {items.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> ); }; export default List;
Prueba: List.test.js
import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import List from './List'; test('renderiza una lista de elementos', () => { const items = ['Item 1', 'Item 2', 'Item 3']; render(<List items={items} />); items.forEach(item => { expect(screen.getByText(item)).toBeInTheDocument(); }); });
Conclusión
En esta sección, hemos aprendido a usar React Testing Library para escribir pruebas de componentes de React. Hemos cubierto desde la configuración básica hasta técnicas avanzadas para manejar componentes asíncronos. Las pruebas son una parte crucial del desarrollo de software, y React Testing Library nos proporciona herramientas poderosas para asegurar que nuestros componentes funcionen correctamente.
Próximos Pasos
En la siguiente sección, exploraremos las pruebas de extremo a extremo con Cypress, que nos permitirá probar la aplicación completa en un entorno realista.
Curso de React
Módulo 1: Introducción a React
- ¿Qué es React?
- Configuración del Entorno de Desarrollo
- Hola Mundo en React
- JSX: Extensión de Sintaxis de JavaScript
Módulo 2: Componentes de React
- Entendiendo los Componentes
- Componentes Funcionales vs de Clase
- Props: Pasando Datos a Componentes
- State: Gestión del Estado del Componente
Módulo 3: Trabajando con Eventos
- Manejo de Eventos en React
- Renderizado Condicional
- Listas y Claves
- Formularios y Componentes Controlados
Módulo 4: Conceptos Avanzados de Componentes
- Elevando el Estado
- Composición vs Herencia
- Métodos del Ciclo de Vida de React
- Hooks: Introducción y Uso Básico
Módulo 5: Hooks de React
Módulo 6: Enrutamiento en React
Módulo 7: Gestión del Estado
- Introducción a la Gestión del Estado
- API de Contexto
- Redux: Introducción y Configuración
- Redux: Acciones y Reductores
- Redux: Conectando a React
Módulo 8: Optimización del Rendimiento
- Técnicas de Optimización del Rendimiento en React
- Memorización con React.memo
- Hooks useMemo y useCallback
- División de Código y Carga Perezosa
Módulo 9: Pruebas en React
- Introducción a las Pruebas
- Pruebas Unitarias con Jest
- Pruebas de Componentes con React Testing Library
- Pruebas de Extremo a Extremo con Cypress
Módulo 10: Temas Avanzados
- Renderizado del Lado del Servidor (SSR) con Next.js
- Generación de Sitios Estáticos (SSG) con Next.js
- TypeScript con React
- React Native: Creación de Aplicaciones Móviles