-
Notifications
You must be signed in to change notification settings - Fork 0
Testing
Tests run with Vitest (npm test → vitest run). Configuration: vitest.config.ts includes tests/**/*.test.ts with a 30-second timeout and .ts extension priority.
There is no tests/helpers/mock-server.test.ts — the helpers are support code consumed by the integration tests.
There is also a standalone regression suite at test/stream-log.test.ts (singular test/, not tests/). It drives .omp/stream-log.py as a Python subprocess and guards the log-formatter regressions that broke the OMP CI pipeline in issue #76. It is not picked up by the default npm test because vitest.config.ts only includes tests/**/*.test.ts; run it explicitly with npx vitest test/stream-log.test.ts if you change the OMP log formatter.
The suite covers:
- Canonical event flow (
agent_start,turn_start,tool_execution_start/end,message_end,agent_end) formatting without crashing. -
tool_execution_endtextfields that arenull, numeric, lists, or dicts — all coerced safely instead of raisingTypeErrorduring string joins. -
tool_execution_startargspayloads that are strings,null, lists, or dicts — still producing a tool invocation line so the CI log shows the call was attempted. - Non-string
textinmessage_endandagent_endevents. - Malformed JSON lines skipped without aborting the formatter.
tests/
├── helpers/
│ └── mock-server.ts # fetch mock + MCP-over-HTTP test harness
└── integration/
├── config.test.ts # resolveConfig resolution ladder
├── errors.test.ts # status/network mappers
├── server.test.ts # /health, initialize, tools/list, invalid session
└── tools.test.ts # all four tools: success + 401 paths
There are no unit tests per tool file and no stdio entrypoint tests — coverage is integration-level, exercising tools through the real HTTP transport.
Provides two layers of fakes:
Monkeypatches globalThis.fetch with a vi.fn that matches request URLs against registered handlers (string includes or RegExp). Supports:
-
respond(pattern, response)— persistent handler. -
respondOnce(pattern, response)— one-shot (setsconsumed = true). -
restore()— restores the originalfetch. -
callCount()— number of intercepted fetch calls.
Responses are wrapped in a real Response with Content-Type: application/json plus any extra headers (used to test the 429 Retry-After path in errors.test.ts).
startMcpTestServer(app) spins the Express app up on an ephemeral port and exposes:
-
request(mcpReq)— POSTs a JSON-RPC request to/mcpwithAccept: application/json, text/event-streamand tracksmcp-session-id. Parses SSEdata:lines viaparseSse. -
initSession(server)— sendsinitialize(protocolVersion2025-03-26) thennotifications/initialized. -
callTool(server, name, args)— sendstools/calland returnsresult, throwing onres.error.
This lets tests drive the server exactly as a real MCP client would, without spawning a process.
Integration tests use a fixed TEST_CONFIG:
{ apiKey: "test-api-key", apiUrl: "https://chronova.test/api/v1", port: 3001, configSource: "env" }and call createApp(TEST_CONFIG) directly (bypassing resolveConfig), so tests are deterministic regardless of the host's ~/.chronova.cfg.
-
server.test.ts—/healthreturns{ status: "ok", version: VERSION };initializereturnsserverInfo.name = "chronova-mcp"andversion = VERSION;tools/listreturns exactly 4 tools with the expected sorted names; every tool hasannotations.readOnlyHint: trueand aninputSchema.type = "object"; an unknownMcp-Session-Idyields HTTP 400 with "Invalid or expired session ID".Note:
server.test.tsimportsVERSIONfromsrc/version.js, which readspackage.json#versionat import time. This keeps the test assertions in sync with the published package version automatically and avoids the previous drift caused by a hard-coded version string. -
stream-log.test.ts—.omp/stream-log.pyexits 0 when fed the canonical OMP JSONL event flow and does not crash on malformed toolargs, non-string tooltext, malformed message/agent text, or invalid JSON lines. -
tools.test.ts— for each tool: a happy path asserting parsed JSON content, a 401 path assertingisError: trueand the "Unauthorized" message; plus parameter-passthrough checks (e.g.get_productivity_summarywithproject,get_recent_activitywith filters/pagination). -
config.test.ts—resolveConfigpriority: env wins over~/.chronova.cfg, which wins over~/.wakatime.cfg, which wins overnone; uses injectedreadFile/getHomeDir/envso no real filesystem access. -
errors.test.ts—mapHttpStatusToErrorfor 401/404/429/5xx/generic; 429retryAfterfromRetry-Afterand fromX-RateLimit-Reset;mapNetworkErrorproducesCONNECTION_ERROR.
npm test # vitest run (CI mode, tests/ only)
npx vitest # watch mode
npx vitest test/stream-log.test.ts # OMP log-formatter regression suite
npm run type-check # tsc --noEmit, no testsNo test runner script is needed beyond vitest run; there is no separate e2e suite or coverage threshold configured. The stream-log.test.ts path is in the separate test/ directory, not tests/integration/, and must be invoked explicitly.