Volver a React Intermedio

Testing de Componentes React

Una aplicación React bien probada detecta regresiones antes de llegar a producción.

Configuración

npm install -D vitest @testing-library/react @testing-library/user-event @testing-library/jest-dom jsdom
// vitest.config.ts import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { environment: 'jsdom', setupFiles: ['./src/test/setup.ts'], }, }); // src/test/setup.ts import '@testing-library/jest-dom';

Testear un Componente

// Contador.test.tsx import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { Contador } from './Contador'; describe('Contador', () => { it('renderiza la cuenta inicial', () => { render(<Contador cuentaInicial={5} />); expect(screen.getByText('Cuenta: 5')).toBeInTheDocument(); }); it('incrementa al hacer clic en el botón', async () => { const usuario = userEvent.setup(); render(<Contador cuentaInicial={0} />); await usuario.click(screen.getByRole('button', { name: /incrementar/i })); expect(screen.getByText('Cuenta: 1')).toBeInTheDocument(); }); it('llama a onCambio cuando la cuenta cambia', async () => { const usuario = userEvent.setup(); const handleCambio = vi.fn(); render(<Contador cuentaInicial={0} onCambio={handleCambio} />); await usuario.click(screen.getByRole('button', { name: /incrementar/i })); expect(handleCambio).toHaveBeenCalledWith(1); }); });

Testear con Llamadas a API

import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; const servidor = setupServer( http.get('/api/usuarios/:id', ({ params }) => { return HttpResponse.json({ id: params.id, nombre: 'Ana', correo: '[email protected]' }); }) ); beforeAll(() => servidor.listen()); afterEach(() => servidor.resetHandlers()); afterAll(() => servidor.close()); describe('PerfilUsuario', () => { it('muestra los datos del usuario tras cargar', async () => { render(<PerfilUsuario id="1" />); // Verificar estado de carga expect(screen.getByText(/cargando/i)).toBeInTheDocument(); // Esperar a que aparezcan los datos const nombre = await screen.findByText('Ana'); expect(nombre).toBeInTheDocument(); expect(screen.queryByText(/cargando/i)).not.toBeInTheDocument(); }); it('muestra error ante fallo de API', async () => { servidor.use( http.get('/api/usuarios/:id', () => HttpResponse.error()) ); render(<PerfilUsuario id="1" />); const error = await screen.findByText(/error/i); expect(error).toBeInTheDocument(); }); });

Testear Hooks Personalizados

import { renderHook, act } from '@testing-library/react'; import { useContador } from './useContador'; describe('useContador', () => { it('inicializa con el valor correcto', () => { const { result } = renderHook(() => useContador(10)); expect(result.current.cuenta).toBe(10); }); it('incrementa correctamente', () => { const { result } = renderHook(() => useContador(0)); act(() => { result.current.incrementar(); }); expect(result.current.cuenta).toBe(1); }); });

Testing de Accesibilidad

import { axe, toHaveNoViolations } from 'jest-axe'; expect.extend(toHaveNoViolations); it('no tiene violaciones de accesibilidad', async () => { const { container } = render(<FormularioLogin />); const resultados = await axe(container); expect(resultados).toHaveNoViolations(); });