React Testing Library: Desentrañando Pruebas Robustas y Centradas en el Usuario 🧪
Este tutorial te guiará a través de los fundamentos y las mejores prácticas de React Testing Library (RTL). Aprenderás a escribir pruebas unitarias y de integración que se centran en el comportamiento del usuario, asegurando que tus componentes funcionen como se espera en un entorno real. Prepárate para construir aplicaciones React más confiables y mantenibles.
Introducción a React Testing Library (RTL) ✨
En el mundo del desarrollo de software, las pruebas son un pilar fundamental para asegurar la calidad y la fiabilidad de nuestras aplicaciones. Cuando trabajamos con React, tenemos varias opciones para probar nuestros componentes. Sin embargo, React Testing Library se ha convertido en la herramienta preferida por muchos desarrolladores debido a su enfoque en las pruebas centradas en el usuario.
A diferencia de otras librerías que se enfocan en la implementación interna de los componentes (como el estado o los props), RTL nos anima a probar cómo interactúa el usuario con nuestra aplicación. Esto significa que escribimos pruebas que imitan el comportamiento de un usuario real, lo que a menudo resulta en pruebas más robustas y menos propensas a romperse con refactorizaciones internas del código.
¿Por qué elegir React Testing Library? 🤔
Hay varias razones de peso para adoptar RTL en tus proyectos React:
- Centrado en el usuario: Fomenta pruebas que se asemejan al uso real de la aplicación, lo que las hace más significativas y menos frágiles.
- Confianza en el refactor: Si refactorizas el código interno de un componente sin cambiar su comportamiento externo, tus pruebas con RTL deberían seguir pasando.
- Accesibilidad inherente: Al priorizar la búsqueda de elementos por roles de accesibilidad o texto visible, RTL indirectamente promueve el desarrollo de componentes más accesibles.
- Integración sencilla: Se integra perfectamente con Jest (o cualquier otro test runner) y herramientas de bundling como Vite o Create React App.
- Comunidad activa: Goza de una gran comunidad y excelentes recursos de documentación.
Configuración Inicial: Preparando el Entorno 🛠️
Antes de sumergirnos en la escritura de pruebas, necesitamos configurar nuestro entorno de desarrollo. Supondremos que ya tienes un proyecto React configurado (por ejemplo, con Create React App, Vite o Next.js).
Instalación de Dependencias ⬇️
Necesitaremos instalar jest (como test runner) y @testing-library/react junto con @testing-library/jest-dom para matchers personalizados de Jest que facilitan las aserciones de DOM.
npm install --save-dev @testing-library/react @testing-library/jest-dom jest babel-jest @babel/preset-env @babel/preset-react
# o
yarn add --dev @testing-library/react @testing-library/jest-dom jest babel-jest @babel/preset-env @babel/preset-react
Configuración de Jest y Babel ⚙️
Necesitamos indicarle a Jest cómo procesar nuestros archivos JSX/TSX. Para ello, crearemos un archivo babel.config.js (o .babelrc) en la raíz de nuestro proyecto:
// babel.config.js
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
['@babel/preset-react', { runtime: 'automatic' }]
],
};
Además, para que @testing-library/jest-dom extienda las expectativas de Jest, crea un archivo de configuración de configuración de pruebas (por ejemplo, src/setupTests.js o setupTests.ts si usas TypeScript) y asegúrate de que Jest lo cargue.
// src/setupTests.js
// Importa el módulo para extender las expectativas de Jest
import '@testing-library/jest-dom';
Finalmente, asegúrate de que Jest sepa dónde encontrar este archivo de configuración. Esto se hace típicamente en package.json o en un archivo de configuración de Jest (por ejemplo, jest.config.js).
// package.json (fragmento)
{
"scripts": {
"test": "jest"
},
"jest": {
"testEnvironment": "jsdom",
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.js"
]
}
}
Renderizando Componentes y Primeras Asersiones 🎯
React Testing Library nos proporciona la función render para renderizar componentes en un contenedor DOM virtual y funciones de consulta para encontrar elementos. Vamos a crear un componente simple y luego escribir nuestra primera prueba.
Componente Bienvenida
// src/components/Bienvenida.jsx
import React from 'react';
function Bienvenida({ nombre }) {
return (
<div>
<h1>¡Hola, {nombre || 'Invitado'}!</h1>
<p>Bienvenido a nuestra aplicación.</p>
<button>Entrar</button>
</div>
);
}
export default Bienvenida;
Nuestra Primera Prueba con Bienvenida 🧪
// src/components/Bienvenida.test.jsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import Bienvenida from './Bienvenida';
describe('Componente Bienvenida', () => {
test('renderiza el mensaje de bienvenida con el nombre del usuario', () => {
render(<Bienvenida nombre="Mundo" />);
const headingElement = screen.getByText(/Hola, Mundo!/i);
expect(headingElement).toBeInTheDocument();
});
test('renderiza el mensaje de bienvenida para un invitado si no se pasa nombre', () => {
render(<Bienvenida />);
const headingElement = screen.getByText(/Hola, Invitado!/i);
expect(headingElement).toBeInTheDocument();
});
test('renderiza un botón de "Entrar"', () => {
render(<Bienvenida nombre="Usuario" />);
const buttonElement = screen.getByRole('button', { name: /entrar/i });
expect(buttonElement).toBeInTheDocument();
});
});
Estrategias de Consulta: Cómo Encontrar Elementos en el DOM 🔍
RTL nos ofrece varias formas de buscar elementos en el DOM renderizado. Es crucial entender el orden de preferencia de estas consultas para escribir pruebas efectivas y accesibles.
Prioridad de las Queries (queries) ✅
getByRole: La mejor opción. Busca elementos por su rol de accesibilidad (por ejemplo,button,link,heading,textbox,checkbox). Es lo que un usuario de lector de pantalla percibiría.
// Ejemplo: buscar un botón
screen.getByRole('button', { name: /enviar/i });
// Ejemplo: buscar un checkbox
screen.getByRole('checkbox', { name: /aceptar términos/i });
getByLabelText: Para elementos de formulario. Busca la etiqueta (<label>) asociada a un campo de entrada.
// Ejemplo: buscar un input con su label
screen.getByLabelText(/nombre de usuario/i);
getByPlaceholderText: Busca elementos por su texto de placeholder.
// Ejemplo: buscar un input por placeholder
screen.getByPlaceholderText(/tu correo/i);
getByText: Busca elementos que contengan un texto específico. Útil para párrafos, encabezados, botones (si no tienen un rol específico claro).
// Ejemplo: buscar un párrafo de texto
screen.getByText(/bienvenido a la app/i);
getByDisplayValue: Busca elementos de entrada (input, textarea, select) por su valor actual.
// Ejemplo: buscar un input con un valor preestablecido
screen.getByDisplayValue('valor inicial');
getByAltText: Para elementos con texto alternativo (imágenes, áreas conaltatributo).
// Ejemplo: buscar una imagen por su texto alternativo
screen.getByAltText(/logo de la empresa/i);
getByTitle: Busca elementos con un atributotitle.
// Ejemplo: buscar un icono con un título
screen.getByTitle(/cerrar ventana/i);
getByTestId: La última opción. Busca elementos por un atributodata-testidpersonalizado. Útil cuando las otras opciones no son posibles (por ejemplo, contenido dinámico o elementos puramente decorativos sin significado para el usuario).
<!-- Componente -->
<div data-testid="caja-info">...</div>
// Prueba
screen.getByTestId('caja-info');
Variantes de Queries 📊
Cada tipo de consulta viene con tres variantes que definen cómo se comporta cuando no encuentra un elemento o encuentra varios:
get*: Lanza un error si no encuentra un elemento o si encuentra más de uno. Ideal para asegurarse de que un elemento debe estar presente y es único.query*: Devuelvenullsi no encuentra un elemento. Útil para verificar que un elemento no está presente en el DOM. Lanza un error si encuentra más de uno.find*: Devuelve unaPromiseque se resuelve cuando el elemento se encuentra, o se rechaza después de un tiempo de espera si no se encuentra. Ideal para elementos que aparecen asincrónicamente (por ejemplo, después de una llamada a API).- Existe también la variante
findAll*para encontrar múltiples elementos asincrónicamente.
- Existe también la variante
Simulación de Eventos de Usuario con fireEvent y userEvent 🧑💻
RTL no solo nos permite encontrar elementos, sino también simular interacciones del usuario como clics, entradas de texto, cambios de foco, etc. Para esto, tenemos dos herramientas principales: fireEvent y @testing-library/user-event.
fireEvent (Básico) 💥
fireEvent es una utilidad básica que dispara eventos DOM directamente. Es útil para casos simples, pero no simula la interacción completa del navegador.
// src/components/Contador.jsx
import React, { useState } from 'react';
function Contador() {
const [count, setCount] = useState(0);
return (
<div>
<p>Contador: {count}</p>
<button onClick={() => setCount(count + 1)}>Incrementar</button>
<button onClick={() => setCount(count - 1)}>Decrementar</button>
</div>
);
}
export default Contador;
// src/components/Contador.test.jsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Contador from './Contador';
describe('Componente Contador', () => {
test('incrementa el contador al hacer clic en el botón de incrementar', () => {
render(<Contador />);
const incrementButton = screen.getByRole('button', { name: /incrementar/i });
const countElement = screen.getByText(/Contador: 0/i);
fireEvent.click(incrementButton);
expect(countElement).toHaveTextContent('Contador: 1');
});
test('decrementa el contador al hacer clic en el botón de decrementar', () => {
render(<Contador />);
const decrementButton = screen.getByRole('button', { name: /decrementar/i });
const countElement = screen.getByText(/Contador: 0/i);
// Primero incrementamos para tener un valor > 0
const incrementButton = screen.getByRole('button', { name: /incrementar/i });
fireEvent.click(incrementButton);
fireEvent.click(decrementButton);
expect(countElement).toHaveTextContent('Contador: 0');
});
});
@testing-library/user-event (Recomendado) ✨
user-event es una librería complementaria que simula interacciones de usuario de manera mucho más realista, disparando los mismos eventos que el navegador. Por ejemplo, al escribir en un <input>, user-event disparará keyDown, keyPress, keyUp, e input eventos, mientras que fireEvent.change solo dispararía el evento change.
Para usarlo, primero instálalo:
npm install --save-dev @testing-library/user-event
# o
yarn add --dev @testing-library/user-event
Vamos a usarlo en un formulario simple.
Componente FormularioLogin
// src/components/FormularioLogin.jsx
import React, { useState } from 'react';
function FormularioLogin({ onSubmit }) {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
onSubmit({ username, password });
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="username">Usuario:</label>
<input
id="username"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div>
<label htmlFor="password">Contraseña:</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<button type="submit">Iniciar Sesión</button>
</form>
);
}
export default FormularioLogin;
Prueba de FormularioLogin con user-event
// src/components/FormularioLogin.test.jsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import FormularioLogin from './FormularioLogin';
describe('Componente FormularioLogin', () => {
test('llama a la función onSubmit con los datos correctos al enviar el formulario', async () => {
const mockOnSubmit = jest.fn(); // Creamos un mock de función
render(<FormularioLogin onSubmit={mockOnSubmit} />);
// Simular escritura de usuario
await userEvent.type(screen.getByLabelText(/usuario:/i), 'testuser');
await userEvent.type(screen.getByLabelText(/contraseña:/i), 'password123');
// Simular clic en el botón de envío
await userEvent.click(screen.getByRole('button', { name: /iniciar sesión/i }));
// Verificar que onSubmit fue llamado con los datos esperados
expect(mockOnSubmit).toHaveBeenCalledTimes(1);
expect(mockOnSubmit).toHaveBeenCalledWith({
username: 'testuser',
password: 'password123',
});
});
test('muestra un mensaje de error si los campos están vacíos (ejemplo conceptual)', async () => {
// Esta prueba asume que FormularioLogin tiene lógica para mostrar errores.
// Aquí solo simulamos el envío de un formulario vacío.
const mockOnSubmit = jest.fn();
render(<FormularioLogin onSubmit={mockOnSubmit} />);
await userEvent.click(screen.getByRole('button', { name: /iniciar sesión/i }));
// En un componente real, aquí esperaríamos que apareciera un mensaje de error
// Por ejemplo:
// expect(screen.getByText(/El usuario no puede estar vacío/i)).toBeInTheDocument();
expect(mockOnSubmit).toHaveBeenCalledWith({ username: '', password: '' });
});
});
Pruebas Asíncronas y waitFor ⏳
Las aplicaciones React a menudo interactúan con APIs o realizan operaciones asíncronas. RTL proporciona utilidades para manejar estas situaciones y asegurar que nuestras pruebas esperen a que los elementos aparezcan o cambien en el DOM.
El Problema de la Asincronía
Cuando un componente carga datos de forma asíncrona, los elementos que dependan de esos datos no estarán presentes en el DOM inmediatamente después del render. Necesitamos decirle a nuestras pruebas que esperen a que estos elementos aparezcan.
findBy* Queries (Recordatorio) ✅
Como mencionamos antes, las queries findBy* (findByText, findByRole, etc.) son las primeras herramientas para manejar la asincronía. Internamente, usan waitFor.
// src/components/ListadoUsuarios.jsx
import React, { useState, useEffect } from 'react';
const fetchUsers = () =>
new Promise((resolve) =>
setTimeout(() => {
resolve([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
]);
}, 100)
);
function ListadoUsuarios() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchUsers().then((data) => {
setUsers(data);
setLoading(false);
});
}, []);
if (loading) {
return <div>Cargando usuarios...</div>;
}
return (
<div>
<h2>Usuarios</h2>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
export default ListadoUsuarios;
// src/components/ListadoUsuarios.test.jsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import ListadoUsuarios from './ListadoUsuarios';
describe('Componente ListadoUsuarios', () => {
test('muestra la lista de usuarios después de cargar los datos', async () => {
render(<ListadoUsuarios />);
// Antes de la carga, debería mostrar el mensaje de carga
expect(screen.getByText(/Cargando usuarios.../i)).toBeInTheDocument();
// Después de la carga asíncrona, esperamos que aparezca el nombre de un usuario
const aliceElement = await screen.findByText('Alice');
expect(aliceElement).toBeInTheDocument();
// Verificamos que el mensaje de carga desaparece
expect(screen.queryByText(/Cargando usuarios.../i)).not.toBeInTheDocument();
// Verificamos que Bob también esté presente
expect(screen.getByText('Bob')).toBeInTheDocument();
});
});
La Utilidad waitFor Avanzada ⏱️
En algunos casos, findBy* puede no ser suficiente, especialmente cuando necesitamos esperar a que algo desaparezca o a que una condición específica se cumpla que no sea solo la aparición de un elemento. Para esto, usamos waitFor.
waitFor acepta una función de callback que debe contener una aserción. RTL ejecutará esta función repetidamente hasta que la aserción pase o se agote el tiempo de espera. La aserción debe fallar (lanzar un error) si la condición no se cumple.
// Ejemplo usando waitFor para esperar a que un elemento desaparezca
// Suponemos que nuestro componente ListadoUsuarios elimina el mensaje de carga
// automáticamente cuando los datos están listos. Queremos esperar que desaparezca.
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import ListadoUsuarios from './ListadoUsuarios';
describe('Componente ListadoUsuarios con waitFor', () => {
test('el mensaje de carga desaparece después de cargar los usuarios', async () => {
render(<ListadoUsuarios />);
expect(screen.getByText(/Cargando usuarios.../i)).toBeInTheDocument();
await waitFor(() => {
expect(screen.queryByText(/Cargando usuarios.../i)).not.toBeInTheDocument();
}, { timeout: 2000 }); // Opcional: ajustar el timeout
// Ahora podemos hacer aserciones sobre los usuarios cargados
expect(screen.getByText('Alice')).toBeInTheDocument();
});
});
Mocking de APIs y Más Allá: Isolando Componentes 🎭
En la mayoría de las aplicaciones reales, los componentes interactúan con APIs externas. Para que nuestras pruebas sean rápidas, deterministas y aisladas, es esencial mockear (simular) estas llamadas a la red.
¿Por qué Mockear? 🤔
- Velocidad: Las llamadas de red son lentas. Mockearlas acelera las pruebas.
- Determinismo: Las APIs externas pueden devolver datos inconsistentes. Mockear asegura que siempre recibamos los mismos datos esperados.
- Aislamiento: Permite probar el componente en aislamiento, sin depender de la disponibilidad o el estado de un servidor real.
- Control de errores: Podemos simular respuestas de error de la API para probar cómo reacciona el componente.
Mocking Básico con Jest 📖
Jest tiene un potente sistema de mocking. Podemos mockear módulos enteros o funciones específicas. Para las llamadas a la red, a menudo mockeamos fetch o librerías como axios.
// src/components/PerfilUsuario.jsx
import React, { useState, useEffect } from 'react';
function PerfilUsuario({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUserData = async () => {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error('Error al cargar el usuario');
}
const data = await response.json();
setUser(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUserData();
}, [userId]);
if (loading) {
return <div>Cargando perfil...</div>;
}
if (error) {
return <div style={{ color: 'red' }}>Error: {error}</div>;
}
if (!user) {
return <div>Usuario no encontrado.</div>; // Esto puede pasar si fetchUserData resuelve a null
}
return (
<div>
<h2>Perfil de {user.name}</h2>
<p>Email: {user.email}</p>
<p>Edad: {user.age}</p>
</div>
);
}
export default PerfilUsuario;
// src/components/PerfilUsuario.test.jsx
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import PerfilUsuario from './PerfilUsuario';
describe('Componente PerfilUsuario', () => {
// Mockear la API de fetch antes de cada prueba
beforeEach(() => {
jest.spyOn(global, 'fetch').mockImplementation((url) => {
if (url === '/api/users/1') {
return Promise.resolve({
ok: true,
json: () => Promise.resolve({ id: 1, name: 'Carlos', email: 'carlos@example.com', age: 30 }),
});
}
if (url === '/api/users/2') {
return Promise.resolve({
ok: false,
status: 404,
json: () => Promise.resolve({ message: 'Usuario no encontrado' }),
});
}
return Promise.reject(new Error('URL no mockeada'));
});
});
// Limpiar el mock después de cada prueba
afterEach(() => {
jest.restoreAllMocks();
});
test('muestra el perfil del usuario después de una carga exitosa', async () => {
render(<PerfilUsuario userId={1} />);
expect(screen.getByText(/Cargando perfil.../i)).toBeInTheDocument();
const userName = await screen.findByText('Perfil de Carlos');
expect(userName).toBeInTheDocument();
expect(screen.getByText(/Email: carlos@example.com/i)).toBeInTheDocument();
expect(screen.getByText(/Edad: 30/i)).toBeInTheDocument();
expect(screen.queryByText(/Cargando perfil.../i)).not.toBeInTheDocument();
});
test('muestra un mensaje de error si la carga del perfil falla', async () => {
render(<PerfilUsuario userId={2} />); // Usamos un ID que mockea un error
expect(screen.getByText(/Cargando perfil.../i)).toBeInTheDocument();
const errorMessage = await screen.findByText(/Error: Error al cargar el usuario/i);
expect(errorMessage).toBeInTheDocument();
expect(screen.queryByText(/Cargando perfil.../i)).not.toBeInTheDocument();
});
test('muestra el mensaje de usuario no encontrado si la API devuelve un status no ok', async () => {
// Este test es para el caso en que el fetch devuelve un !response.ok y json resuelve a un mensaje
// Este caso ya lo cubre el test anterior, pero podemos ser más específicos si la lógica de PerfilUsuario
// diferenciara entre diferentes tipos de error, por ejemplo, status 404 vs 500
// Para simplificar, la prueba anterior ya verifica el mensaje de error general.
});
});
Mocking de Módulos Completos 📂
Si tienes un módulo con muchas funciones de utilidad, puedes mockearlo completamente.
// src/utils/math.js
export const sum = (a, b) => a + b;
export const multiply = (a, b) => a * b;
// src/components/Calculadora.jsx
import React, { useState } from 'react';
import { sum } from '../utils/math';
function Calculadora() {
const [num1, setNum1] = useState(0);
const [num2, setNum2] = useState(0);
const [result, setResult] = useState(null);
const handleSum = () => {
setResult(sum(parseInt(num1), parseInt(num2)));
};
return (
<div>
<input type="number" value={num1} onChange={(e) => setNum1(e.target.value)} data-testid="num1-input" />
<input type="number" value={num2} onChange={(e) => setNum2(e.target.value)} data-testid="num2-input" />
<button onClick={handleSum}>Sumar</button>
{result !== null && <p data-testid="result">Resultado: {result}</p>}
</div>
);
}
export default Calculadora;
// src/components/Calculadora.test.jsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Calculadora from './Calculadora';
// Mockear el módulo math.js
jest.mock('../utils/math', () => ({
sum: jest.fn((a, b) => a + b + 100), // Simula un bug o un comportamiento diferente para la prueba
multiply: jest.fn(), // No lo usaremos en este test, pero lo mockeamos
}));
describe('Componente Calculadora con mock de módulo', () => {
test('muestra el resultado de la suma con el mock de la función', async () => {
render(<Calculadora />);
await userEvent.type(screen.getByTestId('num1-input'), '5');
await userEvent.type(screen.getByTestId('num2-input'), '3');
await userEvent.click(screen.getByRole('button', { name: /sumar/i }));
// Esperamos 5 + 3 + 100 = 108 debido a nuestro mock
expect(screen.getByTestId('result')).toHaveTextContent('Resultado: 108');
});
});
Mejores Prácticas y Consejos Adicionales ✅
Para escribir pruebas con RTL que sean realmente valiosas y fáciles de mantener, sigue estas mejores prácticas:
Principios Generales
- Prueba el comportamiento, no la implementación: Este es el mantra de RTL. Si cambias el nombre de una variable de estado, tu prueba no debería romperse.
- Escribe pruebas accesibles: Al usar
getByRole,getByLabelText,getByText, etc., estás fomentando una buena accesibilidad en tu aplicación. - Evita
wrapper.find()ywrapper.state(): Si vienes de Enzyme, olvídate de inspeccionar el estado interno o las props de los componentes. Concéntrate en el DOM. - Realiza limpieza después de cada prueba:
renderautomáticamente maneja la limpieza del DOM, pero si estás usandojsdomo mocks manuales, asegúrate de limpiarlos conafterEachocleanup.
Organización de Pruebas 📁
- Archivos
.test.jso.spec.js: Convención para nombrar los archivos de prueba. Colócalos junto al componente que prueban. describeytest(oit): Agrupa tus pruebas lógicamente para una mejor lectura.
Depuración de Pruebas 🐛
Si una prueba falla o no encuentras un elemento, estas utilidades te serán de gran ayuda:
screen.debug(): Imprime el DOM actual en la consola. Útil para ver qué está renderizando exactamente tu componente.
render(<MyComponent />);
screen.debug();
logRoles(): Imprime una lista de todos los roles de accesibilidad presentes en el DOM, junto con sus nombres accesibles. Te ayuda a entender cómo RTL ve tu interfaz.
import { render, screen, logRoles } from '@testing-library/react';
render(<MyComponent />);
logRoles(screen.getByRole('document')); // 'document' es el rol por defecto del body
Tabla Comparativa de Queries y sus Variantes 📊
| Tipo de Query | Descripción | getBy* | queryBy* | findBy* | getAllBy* | queryAllBy* | findAllBy* |
|---|---|---|---|---|---|---|---|
| --- | --- | --- | --- | --- | --- | --- | --- |
| getByRole | Por rol de accesibilidad | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| getByLabelText | Por texto de etiqueta <label> | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| --- | --- | --- | --- | --- | --- | --- | --- |
| getByPlaceholderText | Por texto de placeholder | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| getByText | Por contenido de texto visible | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| --- | --- | --- | --- | --- | --- | --- | --- |
| getByDisplayValue | Por valor de input/textarea | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| getByAltText | Por texto alt de imágenes | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| --- | --- | --- | --- | --- | --- | --- | --- |
| getByTitle | Por atributo title | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| getByTestId | Por atributo data-testid | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Conclusión 🎉
React Testing Library es una herramienta poderosa que te permite escribir pruebas de React que son robustas, fáciles de mantener y, lo más importante, centradas en la experiencia del usuario. Al adoptar un enfoque que imita cómo los usuarios interactúan con tu aplicación, garantizas que tus componentes no solo funcionen, sino que también sean accesibles y usables en el mundo real.
Esperamos que este tutorial te haya proporcionado una base sólida para comenzar a escribir pruebas de alta calidad en tus proyectos React. ¡Felices pruebas!
Tutoriales relacionados
- React Hooks Personalizados: Creando Lógica Reutilizable y Abstraída 🛠️intermediate20 min
- Optimización del Rendimiento en Aplicaciones React: Estrategias Avanzadas con Memoización y Virtualización de Listasadvanced18 min
- React Server Components y Suspense: Renderizado Híbrido y Experiencias de Usuario Avanzadas 🚀advanced20 min
- React Router DOM v6: Navegación Declarativa y Gestión de Rutas Avanzada 🚀intermediate20 min
- Gestión del Estado Global en React con Context API y useReducer: Una Guía Completaintermediate15 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!