# Testing, Frameworks and Logging

Companion to the Node.js backend skill: how to test a service built from an app factory, and how the common frameworks differ.

## Testing with node:test

```ts
// orders/orders.test.ts
import { describe, it, before, after } from "node:test";
import assert from "node:assert/strict";
import { buildApp } from "../app.ts";
import { fakeDeps } from "../test/fakes.ts";

describe("POST /orders", () => {
  let app: Awaited<ReturnType<typeof buildApp>>;
  before(async () => { app = await buildApp(testConfig, fakeDeps()); });
  after(() => app.close());

  it("rejects a zero quantity", async () => {
    const res = await app.inject({
      method: "POST", url: "/orders",
      payload: { productId: "p_812abc", quantity: 0 },
    });
    assert.equal(res.statusCode, 400);
    assert.equal(res.json().type.endsWith("/validation"), true);
  });
});
```

- `node --test` discovers `*.test.*` files; `--test-concurrency`, `--watch`,
  mocking via `t.mock.fn()` and `t.mock.timers`, and coverage via
  `--experimental-test-coverage` are built in.
- Use `app.inject()` (Fastify) or `supertest` (Express) for HTTP tests without
  opening a port.
- Integration tests against a real Postgres or Redis in Testcontainers catch
  what fakes cannot; keep them in a separate script.

## Framework notes

- **Fastify 5:** schema-first routes with JSON Schema or a type provider (Zod,
  TypeBox), encapsulated plugins, fast serialisation. A strong default.
- **Express 5:** now forwards rejected promises from async handlers to the error
  middleware; still bring your own validation and structure.
- **NestJS:** modules, DI and decorators suit large teams that want imposed
  structure; keep business logic in plain services so it is not tied to the
  framework.
- **Hono:** small and runtime-portable (Node, Bun, Deno, edge workers).

## Logging and observability

- Structured JSON logs via `pino` (Fastify's default). Include `requestId`,
  route, status, duration; redact `authorization`, cookies and secrets with
  `redact` paths.
- Log levels mean something: `error` pages someone, `warn` is looked at daily,
  `info` records state changes, `debug` is off in production.
- OpenTelemetry auto-instrumentation for HTTP, database and queue clients gives
  traces with little code; export RED metrics (rate, errors, duration) per route.
