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();
});