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:

npm install --save-dev @testing-library/react @testing-library/jest-dom 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:

"scripts": {
  "test": "jest"
}

Escribiendo Pruebas Básicas

Estructura de una Prueba

Una prueba básica en React Testing Library sigue esta estructura:

  1. Renderizar el componente: Usamos la función render para montar el componente en un contenedor de prueba.
  2. Seleccionar elementos: Utilizamos selectores para encontrar elementos en el DOM.
  3. Realizar acciones: Simulamos interacciones del usuario, como clics o cambios de entrada.
  4. 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

  1. Renderizar el componente: render(<Button />);

    • Montamos el componente Button en un contenedor de prueba.
  2. Seleccionar elementos: screen.getByText('Click me');

    • Usamos screen.getByText para encontrar el botón por su texto inicial.
  3. Realizar acciones: fireEvent.click(buttonElement);

    • Simulamos un clic en el botón usando fireEvent.click.
  4. 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

  1. Renderizar el componente: render(<AsyncComponent />);

    • Montamos el componente AsyncComponent en un contenedor de prueba.
  2. Afirmar el estado inicial: expect(screen.getByText('Loading...')).toBeInTheDocument();

    • Verificamos que el texto inicial sea "Loading...".
  3. 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".

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

Módulo 2: Componentes de React

Módulo 3: Trabajando con Eventos

Módulo 4: Conceptos Avanzados de Componentes

Módulo 5: Hooks de React

Módulo 6: Enrutamiento en React

Módulo 7: Gestión del Estado

Módulo 8: Optimización del Rendimiento

Módulo 9: Pruebas en React

Módulo 10: Temas Avanzados

Módulo 11: Proyecto: Construyendo una Aplicación Completa

© Copyright 2024. Todos los derechos reservados