Desarrollo Orientado a Pruebas (TDD) en React paso a paso

Clase 6 de 20Curso de React Testing Library

Contenido del curso

Resumen

Escribir pruebas antes de crear el componente suena contradictorio, pero es exactamente lo que propone Test-Driven Development (TDD). Esta metodología invierte el flujo habitual de desarrollo: primero defines qué debe hacer tu código a través de tests y después construyes el componente que los satisfaga. El resultado es un código más seguro ante refactorizaciones y con menor probabilidad de introducir errores inesperados.

¿Qué es el ciclo Red-Green-Refactor en TDD?

El corazón de TDD se compone de tres fases que se repiten de forma iterativa [0:27]:

  • Red: escribes el test antes de que exista el componente. Como no hay nada implementado, el test falla. Ese fallo es esperado y confirma que la prueba detecta la ausencia de funcionalidad.
  • Green: creas el componente mínimo necesario para que el test pase. No buscas perfección, solo cumplir con lo que la prueba exige.
  • Refactor: con los tests ya en verde, puedes reorganizar y mejorar el código interno con la confianza de que cualquier error será detectado de inmediato.

Este ciclo te protege especialmente al momento de hacer refactorizaciones. Si introduces un cambio que rompe el comportamiento esperado, el test falla y te avisa antes de que el bug llegue a producción.

¿Cuándo conviene aplicar TDD?

TDD brilla cuando trabajas sobre un software robusto con casos de uso bien definidos [1:06]. Si el proyecto está en una fase experimental donde los requerimientos cambian constantemente, los casos de prueba se volverán obsoletos con cada iteración y la metodología pierde su ventaja.

¿Cómo implementar TDD en un componente contador con React?

El ejemplo práctico consiste en crear un componente Contador que muestre un valor inicial en cero y lo incremente al hacer clic en un botón. Todo comienza por el archivo de test.

¿Cómo se escriben los tests antes del componente?

Dentro de una carpeta Contador, se crea el archivo Contador.test.tsx [1:27]. Los imports necesarios son:

tsx import { describe, it, expect } from 'vitest'; import { render, screen, fireEvent, act } from '@testing-library/react'; import Contador from './Contador';

La suite de tests define dos casos de prueba [1:50]:

tsx describe('Contador', () => { it('debería mostrar el valor inicial', () => { render(<Contador />); const contador = screen.getByText('Contador: 0'); expect(contador).toBeInTheDocument(); });

it('debería incrementar el contador', async () => { render(<Contador />); const boton = screen.getByText('Incrementar'); await act(async () => { fireEvent.click(boton); }); const contador = screen.getByText('Contador: 1'); expect(contador).toBeInTheDocument(); }); });

El matcher toBeInTheDocument verifica que el elemento existe en el DOM. La función fireEvent.click simula la interacción del usuario, y act envuelve la acción asíncrona para que React procese la actualización de estado antes de la aserción [3:08].

¿Cómo se construye el componente para pasar los tests?

Con los tests en rojo, se crea Contador.tsx [4:06]:

tsx import { useState } from 'react';

export const Contador = () => { const [contador, setContador] = useState(0);

const handleIncrementar = () => { setContador(contador + 1); };

return ( <div> Contador: {contador} <button onClick={handleIncrementar}>Incrementar</button> </div> ); };

Al guardar e importar el componente en el archivo de test, ambas pruebas pasan y se alcanza la fase green [5:06].

¿Cómo protege TDD durante un refactor?

Originalmente el setContador estaba directamente en el onClick [5:20]. Al extraerlo a una función handleIncrementar, los tests siguen pasando sin modificar una sola línea de prueba. Eso confirma que el comportamiento se mantiene intacto.

Si por accidente introduces un cambio que altera la lógica, por ejemplo cambiar el incremento de uno a dos, el test que espera Contador: 1 fallará inmediatamente. TDD actúa como una red de seguridad permanente.

Como práctica complementaria, puedes aplicar esta misma metodología creando un to-do list donde los elementos aparezcan en una lista al agregarlos, o un temporizador que muestre el tiempo al iniciar y la palabra "pausa" al detenerse [6:09]. Comparte tu solución en los aportes y sigue fortaleciendo tu dominio del testing en React.