2.9 KiB
Testing
NexusAI has a lightweight regression suite built on Node's built-in test
runner (node:test) and assertions (node:assert) — no external test
dependencies. It runs offline on any node in the homelab.
npm test # = node --test (discovers test/*.test.js at the repo root)
What's covered
| File | Subject | Imports the real… |
|---|---|---|
test/fusion.test.js |
RRF ranking math | fuseEpisodeResults (orchestration) |
test/fts-query.test.js |
Keyword tokenizer + FTS5 matching | buildFtsQuery (memory-service) |
test/llamacpp-stream.test.js |
SSE stream reassembly across chunks | completeStream (inference) |
test/summarization.test.js |
Summarization decision logic | maybeSummarize (orchestration) |
test/entity-extraction.test.js |
Greeting + regurgitation guards | mentionedIn, isIgnoredName (memory-service) |
test/schema.test.js |
Fresh-DB schema completeness | schema.js string (memory-service) |
test/trivial-turn.test.js |
Greeting/trivial-turn detection | isTrivialTurn (shared) |
test/migrations.test.js |
Migration version-stepping | migrate (memory-service) |
Tests import the real functions rather than reimplementing logic — the
functions are exported for this purpose. External calls (Ollama, Qdrant, the
memory service) are mocked via global.fetch; SQLite-backed tests use the
built-in node:sqlite module against a throwaway in-memory database.
node:sqlite and skips
test/schema.test.js and three cases in test/fts-query.test.js need
node:sqlite, which requires Node ≥ 22.5. On older Node they skip
themselves cleanly (guarded by { skip: !DatabaseSync }) rather than failing,
so the suite stays green everywhere — but those checks only verify anything on
a node new enough to run them. A dev machine on current Node is the source of
truth for the schema and FTS matching tests.
node:sqlite is still marked experimental, so runs print a one-line
ExperimentalWarning. It's harmless; node --test --no-warnings suppresses it.
Adding tests
Keep the pattern: export the real function, import it, mock I/O at the boundary
(global.fetch) or use node:sqlite for DB behaviour. Prefer testing pure
logic (ranking, tokenizing, version-stepping, decision branches) over wiring.
Several of these tests were written after a bug slipped through — each new
class of mistake is worth a case so it can't recur silently.
When a mocked service call changes shape (e.g. the utilityInference refactor
moving summarization from Ollama's /api/generate to the inference service's
/utility/complete), the mock URL router must move with it — an "unexpected
fetch" throw in these tests usually means the code under test evolved, not
broke. Runner-contract tests (migrations) inject stub no-op migration arrays
rather than letting the real SQL-bearing migrations hit the minimal fake db.