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.