Setting Up Jest
// npm install -D jest @jest/globals
// Add to package.json: "test": "jest"
// Write a test:
// math.test.js
import { add, divide } from "./math.js";
describe("Math module", () => {
describe("add()", () => {
test("adds two positive numbers", () => {
expect(add(2, 3)).toBe(5);
});
test("adds negative numbers", () => {
expect(add(-1, -2)).toBe(-3);
});
test("adds zero", () => {
expect(add(5, 0)).toBe(5);
});
});
describe("divide()", () => {
test("divides correctly", () => {
expect(divide(10, 2)).toBe(5);
});
test("throws on division by zero", () => {
expect(() => divide(10, 0)).toThrow("Division by zero");
});
});
});
Jest Matchers
// Common matchers:
expect(value).toBe(5); // strict equality ===
expect(value).toEqual({ a: 1 }); // deep equality
expect(value).toBeTruthy(); // truthy
expect(value).toBeFalsy(); // falsy
expect(value).toBeNull(); // null
expect(value).toBeUndefined(); // undefined
expect(value).toBeDefined(); // not undefined
expect(arr).toContain("item"); // array contains
expect(str).toContain("substr"); // string contains
expect(num).toBeGreaterThan(5); // > 5
expect(num).toBeLessThanOrEqual(10); // <= 10
expect(arr).toHaveLength(3); // array.length === 3
expect(fn).toThrow("error message"); // function throws
expect(fn).toThrowError(TypeError); // throws specific type
// Async tests:
test("fetches user", async () => {
const user = await fetchUser(1);
expect(user).toHaveProperty("name");
expect(user.id).toBe(1);
});
// Before/After hooks:
beforeEach(() => {
// runs before each test
db.clear();
});
afterAll(async () => {
// runs after all tests in file
await db.close();
});
Mocking
// Mock a module:
jest.mock("./db", () => ({
getUser: jest.fn().mockResolvedValue({ id: 1, name: "Alice" }),
saveUser: jest.fn().mockResolvedValue(true)
}));
// Mock a function:
const mockFn = jest.fn();
mockFn.mockReturnValue(42);
mockFn.mockResolvedValue({ data: [] }); // async
// Verify calls:
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(2);
expect(mockFn).toHaveBeenCalledWith("arg1", "arg2");
// Spy on existing methods:
const spy = jest.spyOn(console, "log");
doSomething();
expect(spy).toHaveBeenCalledWith("expected message");
spy.mockRestore();
⚡ Key Takeaways
- Jest: zero-config test runner for JavaScript
- describe() groups related tests; test() or it() defines a test
- expect(value).toBe() for primitives, toEqual() for objects
- Mock external dependencies to test units in isolation
- beforeEach/afterEach for setup/teardown per test
- Test edge cases: empty inputs, null, errors, async failures
🎯 Practice Exercises
EXERCISE 1
Write unit tests for a Calculator class: add, subtract, multiply, divide methods. Achieve 100% coverage including error cases. Use describe/test structure.
EXERCISE 2 — CHALLENGE
Write integration tests for your Express REST API: test each endpoint with supertest. Mock the database. Test success cases and error cases (404, 400, 409).