Skip to main content

Testing

Philosophy

  • Black-box. Assert on inputs and outputs, not internals. A refactor that doesn't change behavior shouldn't break tests.
  • No mocks unless necessary. Prefer real implementations (real DB via vitest-pool-workers, real HTTP). Only mock external services we don't control (Bridge).
  • Focus on I/O boundaries. API request/response, function I/O, component render + interaction. Don't test private functions or intermediate state.
  • Non-brittle assertions. Don't snapshot markup or match exact error strings.

What runs where

Running tests

# All packages
pnpm test

# One package
pnpm --filter @gringo-pay/api test
pnpm --filter @gringo-pay/mobile test

# Coverage
pnpm test:coverage

# Mobile E2E (needs a running dev build + Maestro CLI)
pnpm test:e2e

API tests

  • Runner: Vitest + @cloudflare/vitest-pool-workers.
  • Fixtures in apps/api/src/test/:
    • app.tscreateTestApp() returns the Hono app + a scoped DB.
    • client.tsTestClient wraps requests with the required Privy JWT header.
    • factories.tsseedUser(), seedWallet(), etc.
    • bridge-mock.ts — mock Bridge API responses.
  • Requires TEST_NEON_DB_URL to be set (see setup). CI hard-fails if it's unset.

Colocation: apps/api/src/pix/routes.test.ts lives next to apps/api/src/pix/routes.ts.

Mobile tests

  • Runner: Jest with jest-expo preset + @testing-library/react-native.
  • Metro's blockList excludes *.test.* from bundles.

E2E (Maestro)

  • Scenarios in maestro/*.yaml (e.g. maestro/smoke.yaml).
  • Run against a running dev build (iOS simulator or Android emulator).
  • Not currently blocking in CI — runs as part of the CD mobile preview build.

Coverage

Coverage reports (Istanbul for API, V8 elsewhere) are written to <pkg>/coverage/ and uploaded as a CI artifact (coverage-reports, 14-day retention).