Skip to content

test(coverage): drive mcp to >=95% line + branch coverage#24

Merged
mastermanas805 merged 3 commits into
masterfrom
coverage/push-to-95
May 22, 2026
Merged

test(coverage): drive mcp to >=95% line + branch coverage#24
mastermanas805 merged 3 commits into
masterfrom
coverage/push-to-95

Conversation

@mastermanas805
Copy link
Copy Markdown
Member

@mastermanas805 mastermanas805 commented May 21, 2026

Summary

Drives src/ to >=95% line + branch coverage via 161 new unit-level tests across three new/extended files.

Coverage (via dist-test/src/, measured by node --test --experimental-test-coverage)

File Lines Branches
src/client.ts 100.00% 95.04%
src/index.ts 99.70% 95.00%
src/name_schema.ts 100.00% 100.00%
All files 99.81% 95.03%

The 3 uncovered lines on src/index.ts (995-997) are the production await server.connect(transport) path — unreachable from unit tests by design (guarded by INSTANODE_MCP_NO_LISTEN).

What the tests cover

  • Every InstantClient method (each create_*, listResources, listDeployments, getDeployment, deleteDeployment, claimToken, getApiToken, redeploy) — success + error envelope + AuthRequired
  • Every tool handler (create_postgres → delete_deployment) — success path, catch-formatError path, optional-field absent branches
  • Every formatError cascade arm — 401, 403/paid_tier_only, 403/PAT (via code + message + name-of-message detection), 429, code+message, no-code, plain Error coercion, non-Error coercion
  • Every empty-2xx-body sentinel path — both request<T> and requestMultipart
  • Every requireAuth gate — list_resources / get_deployment / delete_* / redeploy / get_api_token without INSTANODE_TOKEN
  • Edge cases: empty-string token → AuthRequired; non-Error throw → String(err) branch; mock returns no name → arg fallback; result.dimensions precedence chain; multipart non-OK with empty body vs {} body vs JSON error envelope vs HTML body

Source refactor (minimal, all backward-compatible)

src/index.ts:

  • Exports formatError, formatLimits, appendUpgradeBlock, textResult (were module-private; integration tests still exercise them via the spawned subprocess, unchanged)
  • Exports the McpServer server instance so unit tests can drive registered tool callbacks in-process via _registeredTools
  • Guards the top-level await server.connect(transport) behind INSTANODE_MCP_NO_LISTEN — production binary + integration tests never set this var, so prod behavior is unchanged
  • Wraps the package.json version read in a try/catch with a "dev" fallback (mirrors client.ts's User-Agent resolver) so unit tests importing from a non-canonical build path don't crash before any test code runs

Test counts

  • Before: 87 tests (integration only)
  • After: 248 tests (87 integration + 161 unit, all passing)

Files

  • test/client-unit.test.ts — extended from 25 to 73 tests
  • test/index-unit.test.tsnew, 35 tests (pure helper coverage)
  • test/tools-unit.test.tsnew, 79 tests (every tool handler)
  • src/index.ts — refactor for testability (export helpers + server, guard connect)
  • package.jsontest script now includes --experimental-test-coverage + the two new files

Test plan

  • npm test passes with all 248 tests green
  • Coverage report shows src/ >=95% on both lines + branches
  • Existing 87 integration tests still pass (verified, untouched)
  • Production binary path (node dist/index.js) behavior unchanged (only the unit-test path sets INSTANODE_MCP_NO_LISTEN)

🤖 Generated with Claude Code


CI fix (2026-05-22)

The build + coverage jobs were failing because the test script uses --test-coverage-exclude (Node 22.5.0+) while both workflows pinned node-version: 20 (errored bad option: --test-coverage-exclude). Bumped both to Node 22 and dropped the || true mask on the coverage job per CLAUDE.md rule 12 (no test-masking).

mastermanas805 pushed a commit that referenced this pull request May 22, 2026
The test script uses --test-coverage-exclude (added in Node 22.5.0).
On the existing Node 20 runners it errored `bad option:
--test-coverage-exclude`, hard-failing the build + coverage jobs. Bump
both workflows to Node 22 and drop the `|| true` mask on the coverage
job now that the run is real (CLAUDE.md rule 12: no test-masking).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude added 3 commits May 22, 2026 07:39
Adds 1 test file with 25 unit tests covering src/client.ts edge branches:
  - fetch network-error path (ApiError(0))
  - non-JSON 2xx + non-2xx response body coercion
  - empty-2xx safe sentinel (redeploy + multipart)
  - requireAuth gating without INSTANODE_TOKEN
  - createDeploy client-side validation (oversized tarball, allowed_ips
    without private=true, private without allowed_ips)
  - ApiError envelope field bubbling (agent_action, upgrade_url, claim_url)
  - dashboardURL / apiBaseURL env-var-fresh reads
  - createVector dimensions hint passthrough
  - getApiToken default + supplied name handling

Coverage (measured on the test-compiled copy at dist-test/src/client.js,
since the test compile tree is what the unit tests import — node's coverage
reporter does not cross-link the two compile outputs):
  client.js: 93.71% lines / 76.77% branches / 68.97% funcs

The production-built dist/client.js (exercised separately by the
integration suite) remains at 90.47% lines / 62.96% branches — these
unit tests increase the *logical* coverage to ~94% but the dist/ count
will need test/integration.test.ts to import the unit-level paths to
reflect in the canonical report.

Test count: 62 → 87 (all passing).

Remaining gap: src/index.ts is at 92.29% lines — uncovered lines are
mostly tool-handler error-formatting branches that fire only on rare
API error envelopes (PAT-creating-PAT 403, anonymous-recycle 429, etc.)
and are caught structurally by the existing mock-api integration tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds tests for every src/* surface: the InstantClient HTTP client (error
envelope branches, requestMultipart edges, empty-2xx sentinel), the
index.ts tool handlers (every create_*/lifecycle handler's success +
catch + optional-field branch), and the pure-helper exports
(formatError's every cascade arm, formatLimits typed-limit branches,
appendUpgradeBlock's 4 truth combinations).

To unit-test the tool handlers and helpers directly, src/index.ts now:
- exports `formatError`, `formatLimits`, `appendUpgradeBlock`, `textResult`
  (was module-private; integration tests still exercise them via the
  spawned subprocess, unchanged)
- exports the `server` instance so unit tests can pluck registered tool
  callbacks out of its `_registeredTools` map and call them in-process
- guards the top-level `await server.connect(transport)` behind
  INSTANODE_MCP_NO_LISTEN — the production binary path and the
  integration tests' `node dist/index.js` invocation never set this var,
  so prod behavior is unchanged
- wraps the package.json version read in a try/catch with a "dev"
  fallback (mirrors client.ts's User-Agent resolver) so unit tests
  importing from a non-canonical build path don't crash before any
  test code runs

Coverage on src/ (via dist-test/src/, where `npm test` measures
--experimental-test-coverage):

  Before: client 93.71% / 76.77%, index 92.29% / 30.77%
  After:  client 100.00% / 95.04%, index 99.70% / 95.00%
          (index uncovered lines 995-997 = the production
           `await server.connect()` path, unreachable in unit tests)
  All files: 99.81% lines / 95.03% branches

Test count: 87 -> 248 passing (161 new unit-level tests across three
new/extended files):
- test/client-unit.test.ts (extended; was 25 tests, now 73)
- test/index-unit.test.ts (new; 35 tests for the pure helpers)
- test/tools-unit.test.ts (new; 79 tests for every tool handler,
  including error-injection paths via stubbed globalThis.fetch)

Integration suite (87 tests) unchanged and still passing — the
new unit-level coverage is additive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The test script uses --test-coverage-exclude (added in Node 22.5.0).
On the existing Node 20 runners it errored `bad option:
--test-coverage-exclude`, hard-failing the build + coverage jobs. Bump
both workflows to Node 22 and drop the `|| true` mask on the coverage
job now that the run is real (CLAUDE.md rule 12: no test-masking).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastermanas805 mastermanas805 merged commit 63f2718 into master May 22, 2026
7 checks passed
@mastermanas805 mastermanas805 deleted the coverage/push-to-95 branch May 22, 2026 02:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants