guias·8 min de lectura

Testing en Next.js con Vitest y Playwright

Configura testing en tu proyecto Next.js. Unit tests con Vitest, E2E con Playwright, y como integrarlos en tu pipeline de CI/CD.

Testing en Next.js con Vitest y Playwright

Testing en Next.js se divide en dos: Vitest para unit tests rapidos (funciones, componentes, logica) y Playwright para E2E que simulan usuarios reales en un navegador. Con ambos cubres lo que importa sin complicarte.

Esta guia cubre el setup de los dos, ejemplos practicos, y como integrarlos en CI/CD.

Vitest: setup y unit tests

bash
npm install -D vitest @vitejs/plugin-react @testing-library/react @testing-library/jest-dom jsdom

Configuracion minima:

typescript
// vitest.config.ts
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import path from "path";
 
export default defineConfig({
  plugins: [react()],
  test: {
    environment: "jsdom",
    setupFiles: "./vitest.setup.ts",
    globals: true,
  },
  resolve: {
    alias: { "@": path.resolve(__dirname, ".") },
  },
});
typescript
// vitest.setup.ts
import "@testing-library/jest-dom/vitest";

Agrega el script en package.json:

json
{
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run"
  }
}

Test de una funcion

typescript
// lib/__tests__/format.test.ts
import { describe, it, expect } from "vitest";
 
function formatPrice(cents: number): string {
  return `$${(cents / 100).toFixed(2)}`;
}
 
describe("formatPrice", () => {
  it("formatea centavos a dolares", () => {
    expect(formatPrice(1999)).toBe("$19.99");
  });
 
  it("maneja cero", () => {
    expect(formatPrice(0)).toBe("$0.00");
  });
});

Test de un componente

typescript
// components/__tests__/Button.test.tsx
import { render, screen, fireEvent } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
 
function Button({ onClick, children }: {
  onClick: () => void;
  children: React.ReactNode;
}) {
  return <button onClick={onClick}>{children}</button>;
}
 
describe("Button", () => {
  it("renderiza el texto", () => {
    render(<Button onClick={() => {}}>Enviar</Button>);
    expect(screen.getByText("Enviar")).toBeInTheDocument();
  });
 
  it("llama onClick al hacer clic", () => {
    const handleClick = vi.fn();
    render(<Button onClick={handleClick}>Enviar</Button>);
    fireEvent.click(screen.getByText("Enviar"));
    expect(handleClick).toHaveBeenCalledOnce();
  });
});

Test de un schema Zod

typescript
// lib/__tests__/schemas.test.ts
import { describe, it, expect } from "vitest";
import { z } from "zod";
 
const userSchema = z.object({
  email: z.string().email(),
  name: z.string().min(2),
});
 
describe("userSchema", () => {
  it("acepta datos validos", () => {
    const result = userSchema.safeParse({
      email: "rod@ejemplo.com",
      name: "Rod",
    });
    expect(result.success).toBe(true);
  });
 
  it("rechaza email invalido", () => {
    const result = userSchema.safeParse({
      email: "no-es-email",
      name: "Rod",
    });
    expect(result.success).toBe(false);
  });
});

Playwright: tests E2E

bash
npm init playwright@latest

Esto crea la config y descarga los navegadores. Configuracion basica:

typescript
// playwright.config.ts
import { defineConfig } from "@playwright/test";
 
export default defineConfig({
  testDir: "./e2e",
  webServer: {
    command: "npm run dev",
    url: "http://localhost:3000",
    reuseExistingServer: !process.env.CI,
  },
  use: {
    baseURL: "http://localhost:3000",
  },
});

Test de navegacion

typescript
// e2e/navigation.spec.ts
import { test, expect } from "@playwright/test";
 
test("la pagina de inicio carga correctamente", async ({ page }) => {
  await page.goto("/");
  await expect(page).toHaveTitle(/Rod Alexanderson/);
});
 
test("navegar al blog muestra posts", async ({ page }) => {
  await page.goto("/blog");
  const posts = page.locator("article");
  await expect(posts.first()).toBeVisible();
});

Test de formulario

typescript
// e2e/contacto.spec.ts
import { test, expect } from "@playwright/test";
 
test("enviar formulario de contacto", async ({ page }) => {
  await page.goto("/contacto");
 
  await page.fill('input[name="nombre"]', "Rod");
  await page.fill('input[name="email"]', "rod@ejemplo.com");
  await page.fill('textarea[name="mensaje"]', "Hola, esto es un test");
  await page.click('button[type="submit"]');
 
  await expect(page.locator("text=Mensaje enviado")).toBeVisible();
});

Integrar en CI/CD

Agrega los tests a tu GitHub Actions workflow:

yaml
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
 
jobs:
  unit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci
      - run: npm run test:run
 
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test

Si ya tienes CI/CD configurado, revisa la guia de GitHub Actions para Next.js para integrar los tests en tu pipeline existente.

Que testear (y que no)

TestearNo testear
Logica de negocio (validaciones, transformaciones)Estilos CSS
Componentes con logica condicionalComponentes que solo renderizan props
Flujos criticos E2E (login, checkout)Cada pagina individualmente
Schemas de ZodConfiguracion de Next.js
API routes con logica complejaLibrerias de terceros

Siguiente paso

Los tests son parte clave de tu pipeline de CI/CD. La guia de CI/CD con GitHub Actions cubre como automatizar todo: lint, tests, build y deploy con cada push.

#testing#vitest#playwright#nextjs#ci-cd

Preguntas frecuentes

Vitest o Jest para Next.js?

Vitest. Es mas rapido, compatible con ESM nativamente, y la configuracion es minima si ya usas Vite o Next.js. Jest funciona pero requiere mas config con TypeScript y ESM.

Que son tests E2E y por que necesito Playwright?

Tests end-to-end (E2E) simulan un usuario real: abren el navegador, hacen clic, llenan formularios y verifican que todo funcione. Playwright es la herramienta mas rapida y confiable para esto. Soporta Chrome, Firefox y Safari.

Cuantos tests necesito?

Depende del proyecto. Como minimo: unit tests para tu logica de negocio (validaciones, transformaciones) y E2E para los flujos criticos (login, checkout, formularios principales). No necesitas 100% de coverage para empezar.

Como corro tests en CI/CD?

Agrega un step en tu GitHub Actions workflow que corra npm test para Vitest y npx playwright test para E2E. La guia de CI/CD con GitHub Actions cubre el setup completo.