Technology · Next.js

Next.js Testing

Test Next.js apps with Jest, React Testing Library, and E2E testing with Playwright or Cypress.

TL;DR
  1. 01Use Jest for unit and integration tests of functions and components.
  2. 02Use React Testing Library to test components from the user perspective.
  3. 03Use Playwright or Cypress for end-to-end testing full user workflows.

Setup and Jest Basics

  • Jest is pre-configured in Next.js, so start testing immediately.
    npm test
  • Create test files with .test.js or .spec.js extensions.
    // utils.test.js
    import { add } from "./utils";
    
    describe("add function", () => {
      it("adds two numbers", () => {
        expect(add(2, 3)).toBe(5);
      });
    });
  • Run tests in watch mode to re-run on file changes.
    npm test -- --watch
  • Use describe to group related tests and it for individual test cases.
  • Jest runs tests in parallel by default for speed.

Testing Components

  • Import React Testing Library to test components from user perspective.
    import { render, screen } from "@testing-library/react";
    import Button from "./Button";
    
    it("renders a button", () => {
      render(<Button>Click me</Button>);
      const btn = screen.getByRole("button", { name: /click me/i });
      expect(btn).toBeInTheDocument();
    });
  • Query elements using semantic methods like getByRole, getByText.
    screen.getByRole("button", { name: /submit/i });
    screen.getByLabelText("Email");
    screen.getByText("Welcome");
  • Test user interactions with userEvent instead of fireEvent.
    import userEvent from "@testing-library/user-event";
    const user = userEvent.setup();
    await user.click(button);
  • Avoid testing implementation details, focus on what users see and do.

Testing API Routes

  • Create separate test files for API route handlers.
    import { createMocks } from "node-mocks-http";
    import handler from "./api/hello";
    
    it("returns a greeting", async () => {
      const { req, res } = createMocks({
        method: "GET"
      });
      
      await handler(req, res);
      expect(res._getStatusCode()).toBe(200);
      expect(JSON.parse(res._getData())).toHaveProperty("message");
    });
  • Use a library like node-mocks-http to mock request and response.
  • Test different HTTP methods and status codes.
  • Mock dependencies like databases or external APIs.

Mocking and Fixtures

  • Mock external API calls to keep tests fast and isolated.
    jest.mock("./api", () => ({
      fetchUser: jest.fn(() => Promise.resolve({ id: 1, name: "Alice" }))
    }));
  • Use fixtures to provide consistent test data.
    const mockUser = { id: 1, name: "Alice", email: "alice@example.com" };
    
    it("displays user info", () => {
      render(<Profile user={mockUser} />);
      expect(screen.getByText("Alice")).toBeInTheDocument();
    });
  • Mock Next.js router for navigation testing.
    jest.mock("next/router", () => ({
      useRouter: jest.fn(() => ({ push: jest.fn() }))
    }));
  • Mocking prevents external dependencies from slowing tests.

E2E Testing

  • Use Playwright or Cypress for end-to-end testing of full workflows.
    // playwright.spec.ts
    import { test, expect } from "@playwright/test";
    
    test("user can sign up", async ({ page }) => {
      await page.goto("http://localhost:3000");
      await page.fill("input[name=email]", "test@example.com");
      await page.click("button:has-text('Sign Up')");
      await expect(page).toHaveURL("/dashboard");
    });
  • E2E tests run in a real browser and test the entire application.
  • Run E2E tests against a deployed environment before releasing.
  • E2E tests are slower but catch integration issues that unit tests miss.
    npx playwright test
  • Use E2E tests for critical user paths like checkout or login.

Tip: Aim for a test pyramid: many unit tests, some integration tests, and a few critical E2E tests to balance speed and confidence.

Warning: Avoid testing implementation details and focus on user behavior, since refactored code will break tests that depend on internal structure.

Next.js Server ComponentsNext.js Analytics and Monitoring