Skip to content

Latest commit

 

History

History
352 lines (269 loc) · 11.1 KB

File metadata and controls

352 lines (269 loc) · 11.1 KB

Controller Tests Implementation Summary

Overview

Successfully implemented comprehensive controller-level tests for all required endpoints per issue #19, following the supertest-based testing pattern established in the codebase.

Test Files Created

1. remittanceController.test.ts

Location: src/__tests__/remittanceController.test.ts Coverage:

  • ✅ POST /api/remittances - Create remittance
    • Unauthorized rejection (401)
    • Happy path creation with auth (201)
    • Validation (missing recipientAddress, amount)
  • ✅ GET /api/remittances - List user's remittances
    • Unauthorized rejection (401)
    • Empty list response
    • Full list with pagination
    • Status filtering
  • ✅ GET /api/remittances/:id - Get single remittance
    • Unauthorized rejection (401)
    • Forbidden access for non-owner (403)
    • Happy path retrieval
    • 404 handling
  • ✅ POST /api/remittances/:id/submit - Submit signed transaction
    • Unauthorized rejection (401)
    • Forbidden access for non-owner (403)
    • Rejection for non-pending status
    • Happy path submission with status transitions
    • Error handling with failed status update

Authorization & Ownership Tests:

  • ✅ Wallet ownership enforcement on create
  • ✅ Wallet ownership enforcement on get
  • ✅ Wallet ownership enforcement on submit

Test Count: 20 tests covering unauthorized, forbidden, and happy-path cases


2. scoreController.test.ts

Location: src/__tests__/scoreController.test.ts Coverage:

  • ✅ GET /api/score/:userId - Get user's score
    • Unauthorized rejection (401)
    • Forbidden access when userId ≠ JWT wallet (403)
    • Happy path score retrieval
    • Default score (500) when no score exists
    • Credit band classification (Excellent, Good, Fair, Poor)
    • Score factors in response
  • ✅ POST /api/score/update - Update score (API key protected)
    • Missing/invalid API key rejection (401)
    • On-time repayment (+15 delta)
    • Late repayment (-30 delta)
    • Score clamping (300-850 range)
    • New user score creation
    • Cache invalidation
    • Validation (missing userId, onTime)
  • ✅ GET /api/score/:userId/breakdown - Score breakdown
    • Unauthorized rejection (401)
    • Forbidden access when userId ≠ JWT wallet (403)
    • Full breakdown response
    • Zero-loan scenarios
    • Payment history timeline inclusion

Authorization & Ownership Tests:

  • ✅ Wallet-param-matches-JWT enforcement on getScore
  • ✅ Wallet-param-matches-JWT enforcement on getScoreBreakdown
  • ✅ API key requirement for updateScore (not JWT)

Credit Band Classification Tests:

  • ✅ 8 parameterized test cases covering all bands and boundaries

Test Count: 30+ tests covering unauthorized, forbidden, happy-path, and credit band scenarios


3. adminDisputeController.test.ts

Location: src/__tests__/adminDisputeController.test.ts Coverage:

  • ✅ GET /api/admin/disputes - List disputes
    • Unauthorized rejection (401)
    • Admin role enforcement (403 for non-admin)
    • List disputes response
    • Empty list handling
    • Status filtering
    • Invalid status rejection
  • ✅ GET /api/admin/disputes/:disputeId - Get dispute
    • Unauthorized rejection (401)
    • Admin role enforcement (403)
    • Dispute details retrieval
    • 404 for nonexistent dispute
  • ✅ POST /api/admin/disputes/:disputeId/resolve - Resolve dispute
    • Unauthorized rejection (401)
    • Admin role enforcement (403)
    • Resolve with "confirm" action
    • Resolve with "reverse" action
    • Invalid action rejection
    • Resolution reason validation (min 5 chars)
    • Already-resolved dispute rejection (404)
    • Event logging verification
  • ✅ POST /api/admin/disputes/:disputeId/reject - Reject dispute
    • Unauthorized rejection (401)
    • Admin role enforcement (403)
    • Reject with optional admin note
    • Reject without note
    • Already-processed dispute rejection (404)
    • Status update to "rejected" verification

Authorization Tests:

  • ✅ Admin role enforcement on all endpoints
  • ✅ Non-admin user rejection (borrower role)

Happy Path Scenarios:

  • ✅ Complete flow: open → resolve (confirm)
  • ✅ Complete flow: open → resolve (reverse)
  • ✅ Complete flow: open → reject

Test Count: 28 tests covering unauthorized, forbidden, authorization, and happy-path cases


4. notificationController.test.ts

Location: src/__tests__/notificationController.test.ts Coverage:

  • ✅ GET /api/notifications - Get notifications
    • Unauthorized rejection (401)
    • Notifications for authenticated user
    • Empty notification list
    • Limit parameter handling
    • Limit capping at 100
    • Unread count inclusion
  • ✅ POST /api/notifications/mark-read - Mark specific as read
    • Unauthorized rejection (401)
    • Mark multiple notifications
    • Mark single notification
    • Empty ids array rejection
    • Non-numeric ids rejection
    • Non-array ids rejection
    • Missing ids rejection
    • User ownership enforcement
  • ✅ POST /api/notifications/mark-all-read - Mark all as read
    • Unauthorized rejection (401)
    • Mark all as read
    • User ownership enforcement
    • Empty unread list handling
  • ✅ GET /api/notifications/stream - SSE stream
    • Unauthorized rejection (401)
    • SSE connection establishment
    • Unread notifications on connect
    • Correct SSE headers (text/event-stream, no-cache, keep-alive)
    • User subscription verification
    • Empty notification list handling

Authorization & Ownership Tests:

  • ✅ User isolation on get notifications
  • ✅ User isolation on mark-read
  • ✅ User isolation on mark-all-read
  • ✅ User isolation on stream

Happy Path Scenarios:

  • ✅ Complete flow: get → mark-read → mark-all-read
  • ✅ Stream with initial unread notifications

Test Count: 28+ tests covering unauthorized, happy-path, and user isolation cases


5. authController.test.ts

Location: src/__tests__/authController.test.ts Coverage:

  • ✅ POST /api/auth/challenge - Request challenge
    • Valid public key generates challenge
    • Challenge includes message, nonce, timestamp
    • Missing publicKey rejection
    • Invalid public key format rejection
    • Non-string publicKey rejection
    • Empty publicKey rejection
    • Unique nonces on multiple requests
    • Expiration in milliseconds (5 minutes)
  • ✅ POST /api/auth/login - Exchange signature for JWT
    • Missing publicKey rejection
    • Missing message rejection
    • Missing signature rejection
    • Invalid challenge message format rejection
    • Expired challenge rejection (5+ min old)
    • Invalid signature rejection
    • Wrong signature length rejection
    • Successful login with valid signature
    • JWT token generation and format (3 parts)
    • Secure cookie with HttpOnly/Max-Age
    • Signature from different keypair rejection
    • Signature with altered message rejection
    • Invalid public key format rejection

Authorization Tests:

  • ✅ Challenge endpoint accessible without auth (public)
  • ✅ Login endpoint accessible without auth (public)

Happy Path Scenarios:

  • ✅ Complete flow: challenge → login
  • ✅ Rejection of stale messages (>5 min old)
  • ✅ Multiple independent auth flows for different users

Test Count: 28+ tests covering validation, rejection, and happy-path cases


Test Framework & Patterns

Mocking Strategy

All tests follow the established pattern in the codebase:

  • Jest unstable_mockModule for service/connection mocking
  • Direct mock function types with jest.fn()
  • MockedFunction types for accurate type safety

Authentication Testing

  • ✅ JWT token generation with public keys
  • ✅ Bearer header format testing
  • ✅ Admin role verification with ADMIN_WALLETS env var
  • ✅ API key header testing (x-api-key)

Authorization Patterns

  • ✅ Ownership checks (wallet address matching)
  • ✅ Role-based access control (admin role)
  • ✅ Scope requirements (read:score, write:remittances, etc.)
  • ✅ Parameter-JWT matching (requireWalletParamMatchesJwt)

Error Response Testing

  • ✅ 401 Unauthorized
  • ✅ 403 Forbidden
  • ✅ 404 Not Found
  • ✅ 400 Bad Request
  • ✅ 201 Created (for resource creation)

Acceptance Criteria Compliance

Add supertest-based tests for remittance

  • Create/submit ownership and status checks: 7 tests
  • Covers unauthorized, forbidden, happy-path cases

Add tests for score endpoints

  • Wallet-param-matches-JWT enforcement: 6 tests
  • Score update with API key: 8 tests
  • Credit band classification: 8 parameterized tests
  • Covers unauthorized, forbidden, happy-path cases

Add tests for admin dispute

  • Resolve/reject authorization paths: 12 tests
  • Resolve confirm/reverse actions: 6 tests
  • List and get disputes: 6 tests
  • Covers unauthorized, forbidden, happy-path cases

Cover at least unauthorized, forbidden, happy-path per controller

  • Remittance: 20 tests ✓
  • Score: 30+ tests ✓
  • Admin Dispute: 28 tests ✓
  • Notification: 28+ tests ✓
  • Auth: 28+ tests ✓

Files Not Requiring Tests (Per Scope)

indexerController - Out of scope for this issue ❌ E2E browser tests - Out of scope ❌ Load testing - Out of scope


Total Test Statistics

Controller Tests Unauthorized Forbidden Happy-Path
Remittance 20
Score 30+
Admin Dispute 28
Notification 28+
Auth 28+
TOTAL 134+

How to Run Tests

# Run all controller tests
npm test -- --testNamePattern="Controller" --maxWorkers=1

# Run specific controller tests
npm test -- --testNamePattern="remittanceController" --maxWorkers=1
npm test -- --testNamePattern="scoreController" --maxWorkers=1
npm test -- --testNamePattern="adminDisputeController" --maxWorkers=1
npm test -- --testNamePattern="notificationController" --maxWorkers=1
npm test -- --testNamePattern="authController" --maxWorkers=1

# Run all tests
npm test

Implementation Notes

  1. Mocking: All external services (database, cache, Soroban, notifications) are properly mocked to isolate controller logic
  2. Auth Simulation: Real JWT tokens are generated using the production authService for authentic testing
  3. Ownership Verification: Controllers correctly enforce wallet ownership and role-based access
  4. Status Transitions: Tests verify proper state changes (pending → processing → completed/failed)
  5. Error Handling: All error paths are tested with appropriate HTTP status codes
  6. Validation: Input validation for all required fields is tested

Notes for Code Review

  • All tests follow the pattern established in loanEndpoints.test.ts
  • Tests are isolated with beforeEach/afterAll cleanup
  • Mock functions are reset between tests to prevent cross-test contamination
  • Environment variables (JWT_SECRET, ADMIN_WALLETS, INTERNAL_API_KEY) are properly set and cleaned up
  • Bearer token format follows RFC 6750 standard
  • API key format follows x-api-key header convention