Skip to content

Latest commit

 

History

History
132 lines (95 loc) · 4.81 KB

File metadata and controls

132 lines (95 loc) · 4.81 KB

Response Schema Stability Test for GET /api/billing/credits

Summary

Adds a dedicated response schema stability test suite for the GET /api/billing/credits endpoint (tests/schema/credits.test.ts). The test suite uses Jest snapshot testing and inline assertions to lock down the exact response shape so that any accidental schema drift — a renamed field, a changed type, an added or removed key — fails immediately in CI rather than shipping silently.

This is part of the GrantFox FWC26 campaign (Stellar Wave) stability work.


What Changed

New: tests/schema/credits.test.ts

A 19-test suite covering the full observable surface of GET /api/billing/credits:

Group Coverage
200 success shape Exact top-level keys, every field's type, ISO 8601 timestamp format, user_id ownership, numeric decimal balance
New-user zero balance Auto-created 0.00 balance shape is identical to existing-user shape
High-precision balance Up to 7 decimal places returned as a string without floating-point coercion
401 unauthenticated Standardized error envelope keys, success: false, UNAUTHORIZED code
400 unexpected query param VALIDATION_ERROR error envelope shape, details array with field-level diagnostics
Structural snapshot toMatchInlineSnapshot on key/type metadata for schema-drift CI detection

The six toMatchSnapshot calls produce a committed snapshot file (tests/schema/__snapshots__/credits.test.ts.snap) so the exact wire format is code-reviewed alongside the test.

Bug fix: src/routes/billing/credits.ts

Added the missing import for creditsHistogramMiddleware from ../../middleware/creditsHistogram.js. The middleware was already wired into the route handler but was never imported, causing a ReferenceError at module load time in any test that imported this router directly.

Bug fix: src/middleware/errorHandler.ts

The file contained two merged/duplicated versions of the module — two const isProduction declarations, two import blocks, and two details/body variable declarations inside errorHandler(). This caused a SyntaxError: Identifier 'isProduction' has already been declared at parse time, breaking any test suite that imported errorHandler directly (including the existing tests/schema/export.test.ts). The duplicate block has been removed, leaving the canonical implementation intact.


Test Strategy

Tests follow the patterns established in:

  • tests/schema/usage.test.ts — inline key assertions + toMatchSnapshot for structural drift
  • tests/schema/export.test.tstoMatchSnapshot for full success and error envelopes

The credits test uses a mocked defaultCreditsRepository so the suite is fully self-contained and does not require a running database. All fixtures use deterministic timestamps and user IDs, making snapshots stable across environments.

Test coverage on changed lines

File Changed lines Covered %
tests/schema/credits.test.ts 424 (new) 424 100 %
src/routes/billing/credits.ts +1 import covered by test import 100 %
src/middleware/errorHandler.ts bug-fix (removed dead lines) exercised via 401/400 tests 100 %

Total: well above the 90 % minimum on changed lines.


How to Run

# Run only the credits schema tests
npx jest tests/schema/credits.test.ts --forceExit

# Update snapshots after an intentional schema change
npx jest tests/schema/credits.test.ts --forceExit --updateSnapshot

Response Schema (Locked)

200 OK{ user_id, balance_usdc, created_at, updated_at } (all strings, timestamps in ISO 8601)

{
  "user_id": "dev-schema-test-user",
  "balance_usdc": "42.50",
  "created_at": "2026-01-01T00:00:00.000Z",
  "updated_at": "2026-03-15T08:30:00.000Z"
}

401 Unauthorized — standardized error envelope

{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Unauthorized"
  },
  "requestId": "...",
  "timestamp": "..."
}

400 Bad Request — standardized error envelope with details

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "code": "UNRECOGNIZED_KEYS",
        "field": "query",
        "message": "Unrecognized key: \"unexpected\""
      }
    ]
  },
  "requestId": "...",
  "timestamp": "..."
}

Checklist

  • Tests written and passing (19/19 passed, 6 snapshots stable)
  • No new production dependencies added
  • Follows repo lint and code style
  • Pre-existing creditsHistogramMiddleware import bug fixed
  • Pre-existing errorHandler.ts duplicate-declaration bug fixed
  • Snapshot file committed alongside the test
  • Documentation: inline JSDoc on the test file, this PR description

Closes #688