Testing
The testing philosophy: test the logic that can be wrong, not framework plumbing. The money math is pure, isolated in src/domain/, and tested exhaustively with no mocks. Thin query/mutation hooks, the Supabase client, and presentation are deliberately not unit-tested.
Commands
npm test # run all unit tests
npm run test:watch # watch mode
npm run test:ci # with coverage (what CI runs)
npm run e2e # Maestro end-to-end flowsUnit tests (Jest)
Tests live next to the code they cover (*.test.ts). Coverage is scoped to the pure modules - domain, application/overview, data/repositories/mappers, and shared/date/clock - with thresholds enforced in CI:
| Metric | Threshold |
|---|---|
| Lines | 85% |
| Statements | 85% |
| Branches | 80% |
| Functions | 80% |
Current coverage sits around 96%. If you add logic to the domain, add a test alongside it or CI will fail on the threshold.
Jest is pinned to v29
Expo SDK 56's jest-expo preset is built on Jest 29 internals. Jest 30 throws clearMocksOnScope is not a function against it, so the project pins Jest to ^29.
End-to-end tests (Maestro)
Flows in e2e/ drive the real UI. They require a built app on a simulator/emulator and a configured Supabase project.
# Install Maestro once
curl -fsSL "https://get.maestro.mobile.dev" | bash
# Run a single flow
maestro test e2e/onboarding.yaml| Flow | Journey |
|---|---|
onboarding.yaml | Create a household from a clean state |
set-budget-and-add-expense.yaml | Set the budget, log an expense, see it on Home |
settle.yaml | The weekly settlement view renders |
Run onboarding.yaml first; the others assume an existing household. The add-expense button is targeted by testID: add-expense.
For the full approach and known gaps, see the Test strategy.