conduit-full — testing strategy
testUtils/testDb.ts spins up a genuine SQLite Sequelize
instance running the real models for every controller/route test —
controllers touch too many Sequelize methods for per-method mocking to stay
maintainable, and a mock can't catch a wrong foreign key the way a real
query against a real schema does. See
Data Model for the associations these tests
actually exercise.
userId/articleId FK columns before they ever
shipped.
testUtils/testDb.ts, not
hand-stubbed mocks — 214 tests total across every controller and
route.
backend/index.test.ts drives a full register → login →
create-article → list-articles journey through the real, fully-wired
Express app.
Every meaningful fix, proven twice
The pattern used for essentially every real bug in this repo: revert the
fix, watch the test fail for the right reason, restore the fix, watch it
pass again. Applied to the JWT expiration fix, the double-next()
bug, the wrong FK association, and — on the frontend —
errorHandler.test.ts's mock rewrite.
Not every failure is an app bug
The TypeScript retrofit surfaced a case where a static top-level import
and a dynamic
import() after vi.resetModules() ended up in
different module "epochs" with different class identities, so
instanceof silently failed — a real bug, but in the tests,
not the app. Logged as exactly that in todo.md, not folded
into the app-bug count.
The same discipline carries into the frontend:
errorHandler.test.ts's original mock built
error.response from the Fetch API's
Response class, which has no .data field — its
assertion was passing because of an unrelated crash, not the code path it
claimed to test. Caught by actually reading what the mock produced, not by
trusting a green checkmark.