Skip to content

Testing and the quality gate

tool/quality.sh is the local quality gate. The pre-push hook runs it; you can run it directly:

Terminal window
tool/quality.sh # format, ratchets, tests, coverage, goldens
tool/quality.sh full # + the Patrol E2E smoke run (needs a simulator)
tool/quality.sh --update # re-record baselines after an improvement

Exit codes name the failing stage:

Exit Stage
10 format
11 analyzer ratchet (per-rule issue counts must not rise)
12 generated files stale (run tool/gen_coverage_imports.dart)
13 tests
14 coverage (per-tier floors, never drop)
15 goldens
16 e2e
17 design ratchet (untokenised UI values must not rise)

The ratchets are the important idea: the gate never demands perfection, only that you don’t make things worse. After a cleanup that moves a number the right way, record it with --update.

Terminal window
fvm flutter test -r failures-only # everything, failures only
fvm flutter test test/data # one folder
fvm flutter test test/path/to/file_test.dart -r failures-only
fvm flutter test --tags golden --update-goldens # after an intended UI change
fvm flutter test | tool/testlog.sh # strips the app's debugPrint noise

Test tags live in dart_test.yaml: golden, contract, slow.

test/ mirrors lib/ exactly. On top of that:

  • test/helpers/ — shared infrastructure (see below)
  • test/fixtures/api/ — real API responses extracted from the Postman collection
  • test/contract/ — whole-codebase rules (architecture, l10n, schema)
  • test/goldens/ — pixel comparisons, tagged golden
  • test/injection_container_test.dart — proves the whole DI graph resolves
  • test/coverage_all_files_test.dart — generated; imports every lib/ file so an untested file counts as 0% instead of vanishing from the report
  • tester.pumpApp(...) — pump a widget with the app’s plumbing.
  • installFakeHttp() — no test ever reaches the network.
  • installPlatformMocks() — platform channels.
  • loadFixture(...) — real API responses from test/fixtures/api/.
  • tearDown(resetGlobals) — mandatory in any test touching the global ValueNotifiers.
  • test/helpers/bloc_harness.dart — same API as bloc_test, which cannot be resolved here (the analyzer pinned by hive_generator and auto_route_generator excludes every compatible test version).

patrol is deliberately not a dev dependency — it must not ship inside the App Store build. Drive it only through e2e/scripts/with_patrol.sh, which adds it temporarily and restores pubspec.yaml / pubspec.lock afterwards. flutter analyze skips patrol_test/.