Next.js
Testing de aplicaciones Next.js
Explica cómo probar lógica, Client y Server Components, Actions, Route Handlers, caché, base de datos, routing y flujos E2E de Next.js.
- Última actualización
- Actualizada
- Nivel
- Aplicación
Next.js
Explica cómo probar lógica, Client y Server Components, Actions, Route Handlers, caché, base de datos, routing y flujos E2E de Next.js.
Testing en Next.js debe proteger comportamiento en varias fronteras: lógica pura, Client Components, Server Components, Actions, Route Handlers, routing, caché y deployment. Una suite útil no intenta simular todo el framework; usa la prueba más pequeña que pueda detectar el fallo real y reserva E2E para recorridos críticos.
many unit tests
→ domain rules, parsers, policies
integration tests
→ DB, Actions, Handlers, cache contracts
component tests
→ client interaction and accessibility
few E2E tests
→ browser + Next.js + session + dataLa cantidad depende del riesgo. Un cálculo puro no necesita navegador; un redirect tras login sí.
Prueba funciones sin infraestructura:
describe("canCancelOrder", () => {
it("allows a manager for a pending order in the same tenant", () => {
expect(canCancelOrder(manager, pendingOrder)).toBe(true);
});
it("denies another tenant", () => {
expect(canCancelOrder(otherTenantManager, pendingOrder)).toBe(false);
});
});Son rápidas y deben cubrir matrices, límites y estados. No mockees una función pura.
Con React Testing Library prueba como usuario:
const user = userEvent.setup();
render(<QuantityPicker />);
await user.click(screen.getByRole("button", { name: /aumentar/i }));
expect(screen.getByRole("spinbutton")).toHaveValue(2);Prioriza role, label y texto visible. Evita seleccionar por clases o estructura interna.
Prueba pending, error, teclado, focus y disabled.
Un async Server Component puede probarse a través de:
No fuerces una herramienta de DOM cliente a ejecutar toda la semántica RSC si no la soporta. Extrae decisiones a funciones y prueba el resultado en producción/E2E.
La lógica debería vivir en servicios testeables:
Action
→ parse FormData
→ require session
→ call service
→ invalidate
→ return UI statePrueba:
No dependas del botón oculto como protección.
Invoca el handler con Request real o prueba mediante HTTP:
const request = new Request("http://localhost/api/orders", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(input),
});
const response = await POST(request);
expect(response.status).toBe(201);Verifica status, headers, schema, auth, idempotencia, tamaño y content type.
Para reglas SQL, constraints y transacciones usa una DB aislada real. Mocks no detectan:
Usa fixtures mínimas, transacciones por test o reset reproducible. Nunca production.
Prueba explícitamente:
cold read → source called
warm read → reused
mutation commit → tag invalidated
next read → new valueUsa dos usuarios/tenants para detectar fuga. Verifica stale policy y fallo durante revalidation.
E2E o integración debe cubrir:
Playwright ejemplo:
test("creates an order", async ({ page }) => {
await loginAs(page, "manager");
await page.goto("/orders/new");
await page.getByLabel("Cliente").fill("Ana");
await page.getByRole("button", { name: "Crear pedido" }).click();
await expect(page.getByRole("heading", { name: /pedido/i })).toBeVisible();
await expect(page).toHaveURL(/\/orders\//);
});Prueba pocos flujos de alto valor: login, compra, permisos, recuperación y publicación.
Mockea fronteras externas:
No mockees router, DB, sesión y servicio en el mismo test: solo probarías que tus mocks coinciden.
Usa contract tests para proveedores y webhooks.
Controla reloj para expiraciones. Prueba doble submit, dos requests con misma versión e idempotency key repetida.
La concurrencia real necesita DB/integration, no dos llamadas mock secuenciales.
axe para reglas automáticas.Un test que encuentra un botón por role ya incentiva markup correcto.
Ejecuta contra next build y servidor de producción. Dev tiene Fast Refresh, errores y orden diferentes.
CI típico:
install locked dependencies
→ lint
→ typecheck
→ unit/integration
→ next build
→ start production server
→ E2ENo confíes en next build para ejecutar lint en versiones actuales; llama herramientas explícitamente.
Usa factories con defaults válidos y overrides claros. Evita fixtures gigantes compartidas que hacen tests dependientes del orden.
Para E2E, crea datos por test y limpia por namespace/run ID.
Causas:
Espera condiciones observables, no waitForTimeout. Conserva trace, screenshot y video al fallar.
useState.Protege tu contrato y decisiones.
Lento y frágil.
No detecta wiring, rutas ni DB.
Oculta vulnerabilidades.
No representan build/SSR.
Se rompen al refactor visual.
Tests se contaminan.
Acepta cambios sin comprenderlos.
waitForTimeout?Debugging en Next.js localiza la fase y boundary donde la prueba o producción falla.