Why Testing Matters

  • Prevents regressions after code changes
  • Improves confidence in releases
  • Saves debugging time in production

Testing Pyramid

   E2E Tests (few, slow, high coverage)
   -------------------------------
   Integration Tests (some, medium)
   -------------------------------
   Unit Tests (many, fast, cheap)

Unit Testing

  • Focus: Smallest pieces (functions, components).
  • Tools: Jest, Vitest, Mocha.

Example (React utility):

// utils/calc.js
export function add(a, b) {
  return a + b;
}

// calc.test.js
import { add } from "./calc";

test("adds numbers", () => {
  expect(add(2, 3)).toBe(5);
});

✅ Fast, reliable, run often.

Integration Testing

  • Focus: Interaction between multiple units.
  • Tools: React Testing Library, Supertest (Node APIs).

Example (API + DB integration):

import request from "supertest";
import app from "../server";

describe("GET /users", () => {
  it("returns users list", async () => {
    const res = await request(app).get("/users");
    expect(res.status).toBe(200);
    expect(res.body).toHaveLength(3);
  });
});

End-to-End (E2E) Testing

  • Focus: Simulates real user flow.
  • Tools: Cypress, Playwright.

Example (Cypress test for login):

describe("Login flow", () => {
  it("logs in a user", () => {
    cy.visit("/login");
    cy.get("input[name=email]").type("test@example.com");
    cy.get("input[name=password]").type("password123");
    cy.get("button[type=submit]").click();
    cy.contains("Welcome back");
  });
});

✅ Slow, but ensures full system works.

Best Practices

  • Use more unit tests, fewer E2E.
  • Keep E2E scenarios critical-path only (auth, checkout).
  • Run unit tests on every commit, E2E nightly or before release.