Testing
Running Tests
npm test # all tests, 12 suites
npm run test:watch # watch mode with re-run on change
Test Suites
| Suite | Tests | What It Covers |
|---|---|---|
config.test.ts | 14 | Config loading, validation, env var resolution, defaults |
airs-client.test.ts | 10 | executeScan seam: SDK init, circuit breaker, per-direction profiles |
scanner.test.ts | 19 | Observe/enforce/bypass modes, content limits, UX messages, fail-open |
tool-routing.test.ts | 11 | postToolUse routing by tool type, normalize() |
code-extractor.test.ts | 10 | Fenced, indented, heuristic extraction, mixed content |
circuit-breaker.test.ts | 7 | State transitions, cooldown, probe success/failure |
content-limits.test.ts | 6 | Skip/truncate thresholds |
tool-name-parser.test.ts | 7 | MCP:server:tool parsing |
dlp-masking.test.ts | 5 | Enforcement priority |
logger.test.ts | 6 | JSON Lines output, content stripping, directory creation, rotation on first write |
log-rotation.test.ts | 5 | Size threshold, forced rotation, missing file handling |
hooks-integration.test.ts | 17 | End-to-end Cursor JSON contract (tsx + compiled JS) |
Integration Tests
The hooks-integration.test.ts suite runs actual hook scripts with piped JSON:
// Runs: echo '{"prompt":"..."}' | npx tsx src/hooks/before-submit-prompt.ts
// And: echo '{"prompt":"..."}' | node dist/hooks/before-submit-prompt.js
These verify the real Cursor contract end-to-end, including JSON parsing, config loading, fail-open behavior, and correct output format.
Mocking
- AIRS API: Not mocked in integration tests -- hooks fail-open when the API is unreachable, which validates the fail-open design
- SDK: Mocked via
vi.mock("@cdot65/prisma-airs-sdk")in unit tests (airs-client.test.ts) - Scanner: Mocked via
vi.mock("../src/scanner.js")intool-routing.test.tsto isolate routing logic from scan behavior - File system: Tests use temporary directories (
test/.tmp-*) cleaned up inafterEach
Adding Tests
- Create
test/<module>.test.tsmatching the source file - Use vitest's
describe/it/expectAPI - Clean up any temp files in
afterEach - For integration tests, use
execSyncto run hooks with piped JSON