Skip to content

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

bash
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 flows

Unit 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:

MetricThreshold
Lines85%
Statements85%
Branches80%
Functions80%

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.

bash
# Install Maestro once
curl -fsSL "https://get.maestro.mobile.dev" | bash

# Run a single flow
maestro test e2e/onboarding.yaml
FlowJourney
onboarding.yamlCreate a household from a clean state
set-budget-and-add-expense.yamlSet the budget, log an expense, see it on Home
settle.yamlThe 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.

Spend together, settle simply.