my-library
Testing
Eight tests against a real Postgres that lives inside the test process, plus a Postman collection that doubles as a deployment check.
The harness
Tests run against pglite — Postgres compiled to WebAssembly, running in-process. Not a mock, not SQLite pretending: the actual engine, with the real migrations applied, and no server or network anywhere.
const pg = new PGlite(); // in memory
const db = drizzle(pg, { schema, casing: "snake_case" });
await migrate(db, { migrationsFolder: "db/migrations" }); // the real SQL
setDatabase(db as unknown as Database); // injectThat last line is the whole trick, and it is what the lazy proxy in db/client.ts exists for (see Database). Because no connection opens until first use, a test can substitute the database before route handlers ever run — so the handlers are tested unmodified, importing the same db they use in production.
Why this matters more than the count
Eight tests is not many. But they exercise real SQL: identity columns, the ownership WHERE clauses, timestamp defaults, RETURNING. A mocked Drizzle would have passed while the actual queries were wrong. The migrations are also under test — if a generated migration is broken, every test fails at setup.
What is covered
| Test | Guards |
|---|---|
| POST accepts a single book | The one-or-many normalisation. |
| POST accepts an array | Batch insert in one statement. |
| GET lists the caller's books | Scoping and ordering. |
| GET /:id, unknown id is 404 | That a missing row is not an exception. |
| PUT updates and bumps updatedAt | Partial update, and that the timestamp moves. |
| DELETE removes, re-fetch is 404 | Hard delete really deletes. |
| No token is 401 | The auth gate, on the handler rather than in theory. |
| mapDoc maps OpenLibrary fields | The import's field mapping — pure, so no database needed. |
npm test # node --import tsx --test tests/*.test.ts
npm run typecheckThe gaps, stated plainly
- No tests on
lib/queries.ts. Paging, search and the Bayesian rating order are all untested. That is the largest hole: the rating expression is hand-written SQL and exactly the kind of thing that should be pinned by a test. - No component tests. The web pages are verified by looking at them.
- No test for the enrichment scripts beyond
mapDoc. The resumability logic — the part most likely to be subtly wrong — is covered only by having been run.
CI
typecheck + test, on every push and pull requestIt needs no secrets, because pglite means the suite has no external dependency. Deployment is Vercel’s Git integration and is independent of this workflow — CI reports, it does not gate.
Postman as a smoke test
postman/ holds a collection of 12 requests with 51 assertions. It is git-ignored — it is local tooling, not part of the app — but it is the fastest way to check a real deployment, because every request carries tests:
npx newman run postman/my-library.postman_collection.json \
--env-var "baseUrl=https://mylibrary.mblrc.me" \
--env-var "apiToken=$TOKEN"The Books folder runs as a flow: create captures the new id into a variable, the following requests reuse it, and delete removes it. The batch-create request deletes its own two rows in a test script. A full run against production leaves the library exactly as it found it, which is what makes it safe to point at a live deployment.
The error folder covers 401 (no token and bad token), 404, and 422 for both invalid fields and malformed JSON — the failure modes the clients map onto typed errors.