Testing and the quality gate
The gate
Section titled “The gate”tool/quality.sh is the local quality gate. The pre-push hook runs it; you
can run it directly:
tool/quality.sh # format, ratchets, tests, coverage, goldenstool/quality.sh full # + the Patrol E2E smoke run (needs a simulator)tool/quality.sh --update # re-record baselines after an improvementExit 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.
Running tests
Section titled “Running tests”fvm flutter test -r failures-only # everything, failures onlyfvm flutter test test/data # one folderfvm flutter test test/path/to/file_test.dart -r failures-onlyfvm flutter test --tags golden --update-goldens # after an intended UI changefvm flutter test | tool/testlog.sh # strips the app's debugPrint noiseTest tags live in dart_test.yaml: golden, contract, slow.
Layout
Section titled “Layout”test/ mirrors lib/ exactly. On top of that:
test/helpers/— shared infrastructure (see below)test/fixtures/api/— real API responses extracted from the Postman collectiontest/contract/— whole-codebase rules (architecture, l10n, schema)test/goldens/— pixel comparisons, taggedgoldentest/injection_container_test.dart— proves the whole DI graph resolvestest/coverage_all_files_test.dart— generated; imports everylib/file so an untested file counts as 0% instead of vanishing from the report
The helpers — use them
Section titled “The helpers — use them”tester.pumpApp(...)— pump a widget with the app’s plumbing.installFakeHttp()— no test ever reaches the network.installPlatformMocks()— platform channels.loadFixture(...)— real API responses fromtest/fixtures/api/.tearDown(resetGlobals)— mandatory in any test touching the globalValueNotifiers.test/helpers/bloc_harness.dart— same API asbloc_test, which cannot be resolved here (the analyzer pinned byhive_generatorandauto_route_generatorexcludes every compatibletestversion).
E2E (Patrol)
Section titled “E2E (Patrol)”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/.