Smart contract tests
177 Foundry tests across 4 files, organized by domain:Test structure
All test contracts inherit from
BaseTest.sol, which sets up a fork-like environment with a mock USDC token, deploys the factory via UUPS proxy, and provides shared helpers (_createPvPBet, _createOpenBet, _opponentDeposit, _resolve, etc.).
Coverage
Branch coverage numbers appear low (~47% / ~12%) but this is an artifact of
--ir-minimum generating imprecise source mappings. The --ir-minimum flag is required because the contracts hit “stack too deep” errors with standard coverage compilation.Backend tests
The backend uses integration tests that exercise the full HTTP request lifecycle: routing, middleware, input validation, permission checks, state transitions, and database queries. Tests run against the real PostgreSQL database — only external services that cannot be automated (Privy OAuth, Base blockchain) are mocked.What the tests cover
Auth (auth.test.ts — 11 tests)
Bets (bets.test.ts — 33 tests)
Users (users.test.ts — 8 tests)
Leaderboard (leaderboard.test.ts — 4 tests)
What is mocked
External services that require real credentials, OAuth flows, or cost real money are replaced with mock functions:
Mocks are defined in
src/__tests__/setup.ts and reset before each test via vi.clearAllMocks().
What is real
- PostgreSQL database — all INSERT, SELECT, UPDATE, DELETE queries hit the real Neon DB
- Hono app — full middleware chain (CORS, logger, auth middleware)
- Route handlers — all validation logic, permission checks, SQL queries, state transitions
- Drizzle ORM — real query building and execution
What the tests do NOT cover
How test data is isolated
Tests never delete existing data. Each test helper (createTestUser, createTestBet, createTestActivity) tracks the IDs of records it creates. At the end of each test file, cleanupTestData() deletes only those tracked records:
fileParallelism: false) to avoid race conditions on the shared database.
File structure
The
app.ts / index.ts split exists specifically for testing. app.ts exports the Hono app without calling serve() or starting cron jobs, so tests can import it cleanly via app.request().