Testing guide
Every change starts with a failing test. This page explains the suites, how to run them, and the fakes and goldens that keep them honest. Run the fast suite before you commit:
melos run testThat runs the pure-Dart and Flutter unit tests across the workspace. It excludes goldens and the tagged integration suites, so it is quick. The rest of this page covers the slower suites and how each kind of test is written.
Test first
Section titled “Test first”Write the test, watch it fail for the right reason, then make it pass. No
production .dart file lands before its test exists. Red, green, refactor.
The kinds of test
Section titled “The kinds of test”- Unit tests cover everything pure:
core,timing, services, and math. They are the bulk. No real network and no real filesystem. - Golden tests assert pixels through Alchemist. They carry the
goldentag. - Integration tests need a real resource and carry a tag for it:
ffmpeg,snapshot,wasm, orrender.
A plain melos run test excludes goldens and the tagged suites. CI gates the
tags per platform.
Unit tests with mocktail and Riverpod
Section titled “Unit tests with mocktail and Riverpod”Mock a collaborator with mocktail and inject it through a Riverpod override. A service is an abstract contract plus an implementation, wired by a provider, so a test overrides the provider with a fake:
final container = ProviderContainer( overrides: [frameCaptureServiceProvider.overrideWithValue(fakeCapture)],);Stub the fake’s methods with when(() => fake.method(any())).thenAnswer(...).
Register a fallback value for any non-primitive argument matched with any():
registerFallbackValue(Directory('/tmp')). No test touches the live network or a
real binary; media flows through an injected fake client or local fixtures.
Golden tests with Alchemist
Section titled “Golden tests with Alchemist”Goldens render at a fixed fps, a fixed seed, and DPR 1.0, so a frame is
reproducible. Tag the file @Tags(['golden']) and assert with goldenTest.
There are two flavors:
- CI goldens use the Ahem font and run on every platform.
- Platform goldens use real bundled fonts and run on the Linux baseline only, because font rasterization differs across platforms.
Run them and generate baselines:
melos run test:goldens # run the goldensflutter test --update-goldens --tags golden # regenerate baselinesAlways review the PNG before you commit it. A golden diff is a deliberate decision, not a rubber stamp.
Integration suites
Section titled “Integration suites”Each integration suite names what it needs in its tag, so CI can gate it where the resource exists:
ffmpegneeds the encoder on PATH (the 12-lesson render smoke, encode tests).snapshotneeds a live headless renderer (the deferred Mermaid/WebView/Html transport).renderandwasmneed a full capture path or a web runtime.
These are not part of the fast gate. Run a tagged suite directly with
flutter test --tags ffmpeg.
The web demo smoke test
Section titled “The web demo smoke test”The demo (examples/gallery/) has a headless-Chrome smoke test: it builds the web app,
serves it, and checks that the Flutter app boots, lays out, and logs no runtime
error. It guards the in-browser demo and runs in CI (the web_smoke job).
melos run web:smoke # build, serve, and smoke-test the demo web appIt needs node, python3, and a Chrome binary (set CHROME). Pass SKIP_BUILD=1
to reuse an existing build.
Goldens for visual regression
Section titled “Goldens for visual regression”Lock in how a render looks with an Alchemist golden (the golden tag). Seeded
effects (noise(seed) / random(seed)) keep a golden stable from run to run, so
a diff means the output actually changed. The Linux baseline is authoritative.
Coverage
Section titled “Coverage”The gate enforces 97% line coverage on fluvie, fluvie_lints, and
fluvie_cli. Run it before you commit:
melos run coverage:checkTest behavior; ignore only lines that have none, with a reason on the same line. The full policy is in Coverage and the ignore policy.
Doc snippets are tested too
Section titled “Doc snippets are tested too”Documentation Dart fences come from compiled sources under examples/gallery/lib/. Each
snippet file has a small test that builds it, so a doc never ships dead code.
Check the fences are in sync and free of naked Dart blocks:
melos run docs:snippets:check # fences match their sourcemelos run docs:lint # every dart fence has a code-excerpt directiveWhere to next
Section titled “Where to next”- Coverage and the ignore policy: the 97% floor and when an ignore is allowed.
- Contributing overview: the workflow and the quality gate.