Files
2026-10-20 20:33:35 +11:00

3.0 KiB

TESTING.md

Runner: built-in node:test + node:assert/strict. No Jest/Mocha. Script: "test": "NODE_ENV=test node --test --test-concurrency=1". Do NOT pass a directory or an unquoted glob (node --test tests/ finds nothing on Node 21+; tests/**/*.test.js is expanded by sh and skips top-level files). Plain node --test auto-discovers every *.test.js. Test files MUST be named *.test.js.

Layout

  • tests/unit/ — pure functions in src/game and src/utils. No DB, no HTTP.
  • tests/integration/ — boot app with a temporary SQLite file, run migrations + seeds, call the real HTTP API.

Test DB setup helper (tests/helpers.js)

  • Create temp path via os.tmpdir(); set process.env.DB_PATH BEFORE requiring src/db.
  • Run migrate + seed programmatically.
  • Start the app on port 0 (app.listen(0)), return base URL and a close() fn.
  • Provide registerAndLogin(base) which returns a cookie string to reuse in fetch headers.
  • Delete the temp file in after().

What MUST be tested

Area Cases
energy no time passed; partial tick; full cap; clock went backwards; large gap
leveling exact XP threshold; multi-level jump; max level cap
stats each class; equipment bonuses applied
combat fixed seed → identical log; hero win; hero loss; round cap; min damage 1
rewards level-diff multiplier clamps; loot chance 0% / 100%
auth register ok; duplicate (case-insensitive); weak password; login ok/fail; session persists; logout
hunt spends energy; insufficient energy rejected; HP too low rejected; locked zone rejected; rewards persisted
inventory equip swaps slot; can't equip others' items; use potion consumes 1
shop insufficient gold; level gate; sell equipped rejected; quantities validated
expedition claim before end rejected; claim once only; second start while active rejected
leaderboard sort allowlist; ordering correct

Determinism

Inject RNG: createRng(seed) (mulberry32) in src/utils/rng.js exposing .float(), .int(min,max), .range(min,max). In integration tests, allow overriding the RNG via an app factory option or env seed. Inject time: tests set time.setNow(fn) to fast-forward energy/expeditions instead of sleeping.

Naming

describe('energy.computeEnergy', () => { it('caps at max', ...) }).

Rules

  • Run npm test and check the TOTAL against the sum of tests in all *.test.js files. A bad glob once silently skipped 17 tests.
  • Integration tests use setup() from tests/helpers.js, which clears every src/ module from the require cache so each test gets a fresh app and DB. Never hand-pick modules to clear.
  • Force game outcomes with test-only zones/monsters and the { rng, now } options of services — don't rely on luck, and don't weaken assertions to "winner is hero or monster".
  • A failing test is never deleted to make the suite green. Fix the code or log a Known Issue.
  • New bug → write the failing test first, then fix.
  • Update the Test Summary table in STATUS.md after each phase.