Types of Tests
Three levels
Tests operate at different levels of abstraction:
Unit tests test one function in isolation. No database, no HTTP, no external services. Fast — hundreds per second.
test("formatBookV2 formats ratings correctly", () => {
const result = formatBookV2(bookRow);
expect(result.ratings.average).toBe(4.5);
}); Integration tests test multiple components working together. A route handler that queries the database, validates input, and returns a response.
test("GET /v2/books returns books with authors", async () => {
const response = await app.fetch(new Request("http://localhost/v2/books"));
const data = await response.json();
expect(response.status).toBe(200);
expect(data[0].author.name).toBeDefined();
}); End-to-end (E2E) tests test the entire system — a running server, real HTTP requests, real database. The slowest but most realistic.
test("full order flow", async () => {
const loginRes = await fetch("http://localhost:3000/login", { method: "POST", body: loginData });
const token = (await loginRes.json()).token;
const orderRes = await fetch("http://localhost:3000/orders", {
method: "POST",
headers: { Authorization: `Bearer ${token}` },
body: orderData,
});
expect(orderRes.status).toBe(201);
}); The testing pyramid
/ E2E \ Few — slow, expensive, realistic
/ Integ \ Some — moderate speed, test component interaction
/ Unit \ Many — fast, cheap, test individual functions Many unit tests: Fast, cheap, test individual pieces. Catch most bugs.
Some integration tests: Test that pieces work together. Catch wiring bugs.
Few E2E tests: Test critical user flows. Catch system-level bugs.
This course focuses on unit and integration tests — the two levels that give the most value for API development. E2E tests for APIs are essentially integration tests that use a running server, which is rarely necessary with Hectoday HTTP’s app.fetch().
Which level for what
| What to test | Level | Why |
|---|---|---|
| Transformers (formatBookV2) | Unit | Pure function, no dependencies |
| Zod schemas | Unit | Schema in, result out |
| Database queries | Integration | Needs a database |
| Route handlers | Integration | Needs routing + database |
| Auth flows | Integration | Needs multiple routes + state |
| Background jobs | Unit + Integration | Handler logic (unit), enqueue behavior (integration) |
Exercises
Exercise 1: Classify these as unit, integration, or E2E: testing a password hash function, testing a login endpoint, testing a full checkout flow.
Exercise 2: Write a unit test for a pure function (e.g., a helper that formats a date). No database, no HTTP.
Exercise 3: Describe one test at each level for the book catalog API.
Why should you write more unit tests than integration tests?