WeCodeAcademy

Step 8: Test it

Tests prove that the API behaves, and keep proving it as the code changes. Each test makes a request and uses assert to check the status and body. This runnable example tests a tiny API; in your project, put the same checks in todos.test.js and run them with node --test.

ExampleNode.js
const assert = require("assert");
const http = require("http");

// the app under test: a tiny in-memory counter API
const items = [];
const server = http.createServer((req, res) => {
  if (req.method === "POST" && req.url === "/items") {
    let raw = "";
    req.on("data", (c) => (raw += c));
    req.on("end", () => {
      const body = JSON.parse(raw);
      if (!body.name) {
        res.writeHead(400);
        return res.end(JSON.stringify({ error: "name is required" }));
      }
      items.push(body.name);
      res.writeHead(201);
      res.end(JSON.stringify({ count: items.length }));
    });
  } else {
    res.writeHead(404);
    res.end("{}");
  }
});

const tests = [];
const test = (name, fn) => tests.push({ name, fn });

test("creating an item returns 201 and the new count", async (base) => {
  const res = await fetch(base + "/items", { method: "POST", body: JSON.stringify({ name: "a" }) });
  assert.strictEqual(res.status, 201);
  assert.deepStrictEqual(await res.json(), { count: 1 });
});

test("a missing name is rejected with 400", async (base) => {
  const res = await fetch(base + "/items", { method: "POST", body: JSON.stringify({}) });
  assert.strictEqual(res.status, 400);
});

test("unknown routes give 404", async (base) => {
  const res = await fetch(base + "/nope");
  assert.strictEqual(res.status, 404);
});

server.listen(0, async () => {
  const base = `http://localhost:${server.address().port}`;
  let failed = 0;
  for (const t of tests) {
    try {
      await t.fn(base);
      console.log("ok  ", t.name);
    } catch (err) {
      failed++;
      console.log("FAIL", t.name, "-", err.message);
    }
  }
  console.log(failed === 0 ? "all tests passed" : failed + " failed");
  server.close();
});
Output
ok   creating an item returns 201 and the new count
ok   a missing name is rejected with 400
ok   unknown routes give 404
all tests passed

The three kinds of test above are the ones to write first for any endpoint: the happy path (it works), bad input (it refuses politely) and not found (unknown things give 404).

You have built a complete REST API: planned routes, JSON bodies, validation, status codes, persistence, a database design and tests. Where next: add authentication (a login route that returns a token), use the express package to cut boilerplate, and deploy it to a hosting service.

Quick check

Which three cases should you test first for an endpoint?

Finish the quick check (and any code exercise) to complete this lesson, or mark it done yourself.

Tip: use the left and right arrow keys to move between lessons.