Skip to content

Testing

dxai uses Node’s built-in test runner — no extra test framework. Tests run through scripts/run-tests.mjs, a portable runner that enumerates test/*.test.js explicitly so the suite behaves identically on Node 18–22 across Linux, macOS, and Windows (glob expansion differs per platform).

Terminal window
npm test # full suite (160+ tests, a few seconds)
node --test test/runtime.test.js # single file
npm run smoke # quick --version + --help check
npm run lint # ESLint (flat config)
  • Temp directories for every file operation — no side effects on the dev machine.
  • Mock at system boundaries (filesystem, network via injectable fetchImpl/sleepFn), not between internal modules.
  • Test names describe scenarios: “merges new server into existing config”, not “test mergeJson”.
FileCovers
test/runtime.test.jsOption normalization, ID partitioning
test/select.test.jsFlag → defaults → prompt selection resolution, catalog choice builder
test/profile.test.jsResolve / read / merge / save
test/manifest.test.jsRead / write / round-trip
test/config-writer.test.jsJSON / TOML merge, placeholders, version pinning, backups + pruning, malformed-JSON refusal, skill install paths
test/config-remover.test.jsScan + remove, backup-scan specificity, claude mcp list token matching
test/detect-project.test.jsStack / monorepo / pkg-manager / linter detection
test/registry-loader.test.jsCache-over-bundled resolution, diffRegistry, registryBaseFor
test/registry-schema.test.jsEvery catalog entry validated; transport derivation locked by a golden table
test/validate.test.jsUntrusted-registry validation: command allowlist, shell metacharacters, repo/path traversal, detectCommand, prototype-pollution ids
test/net.test.jsTimeout, retry, backoff, retriable-status logic
test/update.test.jsRegistry refresh + payload rejection
test/auto-update.test.jsTTL logic, skip conditions, offline degradation
test/rollback.test.jsBackup discovery + restore
test/handshake.test.jsJSON-RPC handshake against a fake stdio MCP fixture (ok / garbage / timeout / missing binary)
test/mcp-cmd.e2e.test.jsFast-path add/remove flows
test/cli.e2e.test.jsReal subprocess runs: --version, --help, list --json, doctor --json, cleanup --yes --dry-run --json in an isolated HOME

.github/workflows/ci.yml runs three jobs on every push and PR:

  1. Test matrix — Ubuntu / macOS / Windows × Node 18 / 20 / 22: syntax check of every source file, npm test, smoke run.
  2. Lintnpm run lint on Node 22.
  3. Docs driftnpm run docs:check verifies generated reference docs match the committed ones.

catalog-health.yml additionally validates registry entries on PRs that touch them, and runs a weekly pin/URL drift check that opens a GitHub issue on findings.