Skip to content

fix(ci): resolve three test-coverage gaps — integration tests, golden isolation, fatal-infos (MOB-047) - #104

Open
CelestinaBeing wants to merge 7 commits into
Nodus-protocol:mainfrom
CelestinaBeing:fix/mob-047-ci-test-gaps
Open

fix(ci): resolve three test-coverage gaps — integration tests, golden isolation, fatal-infos (MOB-047)#104
CelestinaBeing wants to merge 7 commits into
Nodus-protocol:mainfrom
CelestinaBeing:fix/mob-047-ci-test-gaps

Conversation

@CelestinaBeing

Copy link
Copy Markdown

Summary

Closes #91.

The CI workflow had three gaps that allowed test failures to go undetected or produce confusing output. This PR addresses all three root causes independently.


Problem 1 — No integration test step

integration_test was declared in dev_dependencies but never executed in CI. Unit tests (flutter test) and integration tests use incompatible test runners — integration tests require a physical device or Android emulator.

Fix:

  • Add .github/workflows/integration.yml — a separate job that boots an Android API-33 emulator via reactivecircus/android-emulator-runner@v2 and runs flutter test integration_test/.
  • Add integration_test/app_test.dart with four smoke tests covering the core navigation flows (pools → liquidity → swap → wallet), so the new workflow has meaningful coverage from day one.

The integration job is kept separate from ci.yml intentionally: unit-test failures are reported in ~2 minutes while the emulator boots; integration failures don't block the fast feedback loop.


Problem 2 — No golden test isolation

All tests ran in a single flutter test --coverage call. A pixel-level divergence in any golden baseline (caused by a Flutter version bump or font-rendering difference) would:

  1. Fail the entire run with an unhelpful error unrelated to the actual test logic.
  2. Suppress the coverage report (lcov.info) for the whole run.

Fix — split into two steps in ci.yml:

- name: Unit Tests
  run: flutter test --exclude-tags golden --coverage

- name: Golden Tests
  run: flutter test --tags golden

Coverage is always generated from the unit step regardless of golden baseline state. A golden failure is now clearly attributable to baseline drift, not a logic regression.

Supporting change: Add dart_test.yaml to declare the golden tag with a description. Without this declaration, flutter test --tags golden prints a warning about an undefined tag. The file also documents the @Tags(['golden']) annotation convention for authors writing new golden tests.


Problem 3 — --fatal-infos breaks CI on lint updates

flutter analyze --fatal-infos treats every advisory info-level diagnostic as a build failure. When flutter_lints adds a new info rule in a patch release, CI breaks on unchanged code with no obvious cause.

Fix:

- name: Analyze
  run: flutter analyze --fatal-warnings

Warnings indicate real code problems and should fail CI. Infos are style hints — they appear in the analyze output for visibility but should not block builds.


Additional hardening

Change Reason
Pin flutter-version: '3.16.3' (was '3.x') A floating 3.x constraint means golden rendering, linter rules, or test behaviour can change between two runs of the same commit. The pinned version is bumped via a dedicated PR so changes are intentional and reviewed.
Add timeout-minutes: 20 to the CI job Prevents a hung flutter test process from consuming runner minutes until GitHub's 6-hour job limit.

Files changed

File Change
.github/workflows/ci.yml Pin Flutter version, --fatal-warnings, split unit/golden test steps, add timeout
.github/workflows/integration.yml New — Android emulator job for integration tests
integration_test/app_test.dart New — Four navigation smoke tests
dart_test.yaml New — Declares golden tag to suppress --tags golden warning

Test plan

  • flutter test --exclude-tags golden --coverage runs without the golden step; coverage/lcov.info is generated
  • flutter test --tags golden exits 0 (no golden tests yet → zero tests, not a failure)
  • flutter analyze --fatal-warnings passes on current codebase
  • Integration workflow triggers on push to main; emulator boots and runs integration_test/app_test.dart
  • Adding a mismatched golden baseline causes only the Golden Tests step to fail, not Unit Tests

Closes #91.

**Problem 1 — No integration test step**
`integration_test` was declared in dev_dependencies but never executed in CI
because unit tests and integration tests share incompatible runners (unit
tests run on the host JVM; integration tests require an emulator or device).

Fix: Add `.github/workflows/integration.yml` — a separate job that boots an
Android API-33 emulator via `reactivecircus/android-emulator-runner@v2` and
runs `flutter test integration_test/`. Also add `integration_test/app_test.dart`
with smoke tests covering the four core navigation flows (pools → liquidity →
swap → wallet), giving the new workflow meaningful coverage to run from day one.

**Problem 2 — No golden test isolation**
Golden file tests (those using `matchesGoldenFile()`) were mixed into the
single `flutter test --coverage` call. Any pixel-level divergence caused by a
Flutter version bump or font-rendering change would (a) fail the entire run
with a non-obvious error, and (b) suppress the coverage report.

Fix: Split the Test step into two:
  - `flutter test --exclude-tags golden --coverage` — unit tests; coverage
    report is always generated regardless of golden state.
  - `flutter test --tags golden` — golden tests in isolation; failures are
    clearly attributable to baseline drift, not logic regressions.

Add `dart_test.yaml` declaring the `golden` tag with a description so that
`flutter test --tags golden` does not warn about an undefined tag, and so that
authors know which annotation (`@Tags(['golden'])`) to apply to new golden
test files.

**Problem 3 — `--fatal-infos` breaks CI on lint updates**
`flutter analyze --fatal-infos` means any info-level diagnostic from an
updated `flutter_lints` rule set silently breaks CI with no indication of
what changed. Info messages are advisory by definition and should not block a
build.

Fix: Change to `flutter analyze --fatal-warnings`. Warnings indicate real
code problems; infos are style hints that should be addressed at the author's
discretion, not in an emergency CI fix.

**Additional hardening**
- Pin `flutter-version` to `3.16.3` (was `3.x`). A floating `3.x` constraint
  means a minor Flutter release can change golden rendering, analysis rules,
  or test output between two CI runs on the same commit, making failures
  non-reproducible. The pinned version can be bumped intentionally via a
  dedicated PR.
- Add `timeout-minutes: 20` to the main CI job to prevent hung processes
  from consuming runner minutes indefinitely.
CelestinaBeing and others added 4 commits June 20, 2026 14:34
local_auth >=2.2.0 (declared in pubspec.yaml) requires Flutter SDK >=3.16.6.
The previously pinned version 3.16.3 was below this minimum, causing
`flutter pub get` to fail on both the ci and integration jobs.

Bump to 3.44.2 (the version pub suggested) in both workflows so that
dependency resolution succeeds.
… failure

**CI (flutter analyze) — unused_local_variable warnings**
`--fatal-warnings` (our fix for problem 3) correctly flags the 3 unused
constants declared in test/providers/wallet_provider_test.dart:

  testAddress, testAccessToken, testSecretKey — declared in the group
  setUp scope but never referenced in any test body.

Fix: remove the three unused constants. The tests never needed them — they
use inline literals where values are relevant, or assert on provider state
directly. Also fix the directives_ordering info by sorting the two package
imports alphabetically (flutter_test before nodus_protocol; shared_preferences
after nodus_protocol per lexicographic order).

**Integration job — Android build fails with Flutter 3.44.2**
stellar_flutter_sdk 1.8.1 (via eventsource.dart) references encodingForCharset,
and pinenacl 0.5.1 references UnmodifiableUint8ListView — both APIs were
removed from the Dart SDK in version 3.5. Flutter 3.44.2 bundles Dart >>3.5,
so the Android compilation step (assembleDebug via Gradle) fails with:

  Error: Method not found: 'encodingForCharset'
  Error: Method not found: 'UnmodifiableUint8ListView'

Fix: pin the integration workflow to Flutter 3.22.3 (Dart 3.4.x), the
highest stable release that:
  • still compiles stellar_flutter_sdk 1.8.1 and pinenacl 0.5.1, AND
  • satisfies local_auth >=2.2.0's Flutter SDK >=3.16.6 constraint.

The comment in integration.yml documents why the pin is lower than ci.yml
and what to do when these packages ship Dart 3.5+ fixes.
…tter pin

Two issues introduced by the upstream sync merge:

**test/providers/wallet_provider_test.dart — merge collision**
Git auto-merged our earlier rewrite (which stripped secureStorageChannel to fix
unused_local_variable warnings) with the upstream version that added proper
FlutterSecureStorage mocking. The result was a structurally broken file: two
setUp() blocks, secureStorageChannel referenced but never declared, and missing
closing braces — producing 5 analyzer errors including undefined_identifier and
expected_token.

Fix: write the correct single version that combines both concerns:
- TestWidgetsFlutterBinding.ensureInitialized() at the top of main()
- secureStorageChannel const declared before setUp/tearDown
- proper mock lifecycle via setMockMethodCallHandler in setUp/tearDown
- all unused variable declarations removed

**.github/workflows/integration.yml — wrong Flutter version**
3.22.3 was pinned to avoid stellar_flutter_sdk 1.8.1 compile errors, but the
upstream sync brought stellar_flutter_sdk ^3.2.0 into pubspec.yaml. The API
incompatibilities (encodingForCharset, UnmodifiableUint8ListView) are resolved
in 3.2.0. Meanwhile the pubspec environment constraint is sdk: ">=3.8.0 <4.0.0"
which Flutter 3.22.3 (Dart 3.4.4) does not satisfy — causing pub get to fail.

Fix: restore flutter-version to 3.44.2, matching ci.yml. All dependency
constraints are satisfied and the packages compile cleanly with this version.
… failures

Golden Tests step (ci.yml):
- `flutter test --tags golden` exits 79 when no test file declares @tags(['golden']),
  causing the CI step to fail even though no test actually regressed.
- Wrap the step in a shell block that treats exit 79 as success so CI stays
  green while baselines are being established; real test failures (any other
  non-zero exit) still break the build.
- Add test/golden/widget_golden_test.dart with @tags(['golden']) and two
  widget tests (PoolCard, BottomNavigationBar) pre-wired to matchesGoldenFile.
  Tests are marked skip until PNG baselines are generated and committed via
  `flutter test --update-goldens --tags golden`.

Integration Tests step (integration.yml):
- biometric_storage 5.0.1 declares compileSdkVersion=31 in its own
  build.gradle, but its transitive AndroidX dependencies (androidx.biometric,
  androidx.fragment, androidx.core, etc.) require compileSdk ≥ 34, causing
  assembleDebug to fail with checkAarMetadata errors on all 26 affected deps.
- Inject a Gradle init script into ~/.gradle/init.d/ immediately after the
  `flutter create . --platforms android` step.  The init script runs before
  any build task and overrides compileSdkVersion=34 for every subproject that
  applies the com.android.library plugin, without modifying upstream plugin
  sources or requiring a pubspec version bump.
- widget_golden_test.dart: skip parameter is bool?, not String — passing a
  string literal caused an argument_type_not_assignable error that failed
  flutter analyze --fatal-warnings; changed to `skip: true`
- integration.yml: bump Gradle init-script override from compileSdkVersion 34
  to 35; connectivity_plus 7.1.1 references VERSION_CODES.VANILLA_ICE_CREAM
  and NetworkCapabilities.TRANSPORT_SATELLITE which only exist at API 35
  (Android 15 / "Vanilla Ice Cream") and were not resolvable at sdk 34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants