R
Rishtaara
Next.js: Zero to Full-Stack
Lesson 36 of 42Article18 min

Testing: Jest, Vitest, Cypress & Playwright

Unit tests check small pieces: a price formatter, a Zod schema, a pure helper. They run fast and catch regressions early.

Unit testing overview

Unit tests check small pieces: a price formatter, a Zod schema, a pure helper. They run fast and catch regressions early.

Integration tests check a few units together. End-to-end (e2e) tests drive a real browser like a user.

Real-life example: Unit tests are tasting the sauce alone; e2e is eating the full plate at the restaurant table.

  • Unit — functions and components in isolation
  • Integration — page + mocked API
  • E2E — full browser flows (login, checkout)
Tip: Start with pure helpers and critical Server Action validation. Do not chase 100% coverage on every presentational component.

Jest and Vitest

Vitest is popular with Vite-style speed and Jest-compatible APIs. Jest remains common in many Next.js templates. Both work with React Testing Library.

Real-life example: Jest and Vitest are two brands of kitchen scale — same job (measure), slightly different buttons.

Pure function unit test (Vitest/Jest style)
// lib/formatDuration.ts
export function formatDuration(mins: number) {
  if (mins < 60) return `${mins} min`;
  const h = Math.floor(mins / 60);
  const m = mins % 60;
  return m ? `${h}h ${m}m` : `${h}h`;
}

// formatDuration.test.ts
import { describe, it, expect } from "vitest";
import { formatDuration } from "./formatDuration";

describe("formatDuration", () => {
  it("formats under one hour", () => {
    expect(formatDuration(18)).toBe("18 min");
  });
  it("formats hours and minutes", () => {
    expect(formatDuration(90)).toBe("1h 30m");
  });
});
Component test with Testing Library
import { render, screen } from "@testing-library/react";
import { CourseCard } from "./CourseCard";

it("shows the course title", () => {
  render(<CourseCard title="Next.js Auth" duration="20 min" />);
  expect(screen.getByText("Next.js Auth")).toBeInTheDocument();
});

Cypress and Playwright (e2e)

Playwright and Cypress click through your running app. Prefer Playwright for modern multi-browser CI; Cypress is still widely taught.

Test happy paths first: home loads, login redirects, lesson page shows heading.

Real-life example: E2E tests are a dress rehearsal — lights, costume, full stage — before opening night (production).

Playwright smoke test
import { test, expect } from "@playwright/test";

test("home page shows brand", async ({ page }) => {
  await page.goto("/");
  await expect(page.getByRole("heading", { level: 1 })).toBeVisible();
});

test("learn page lists courses", async ({ page }) => {
  await page.goto("/learn");
  await expect(page.getByText(/Next\.js/i)).toBeVisible();
});
Cypress smoke (brief)
describe("home", () => {
  it("loads", () => {
    cy.visit("/");
    cy.get("h1").should("be.visible");
  });
});