high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

Test suite passes with `flutter test` in CI with zero failures
Line coverage for BufdirPreviewRepository >= 85% (measured via `flutter test --coverage`)
Line coverage for BufdirReportStructureMapper >= 85%
Line coverage for BufdirAccessibilityUtils >= 85%
Repository tests cover: initial loading state, successful data emission, Supabase error propagation, cache hit (no second network call), prior-period stream correctness, delta computation accuracy
Structure mapper tests cover: full ordered list output length matches canonical field count, unknown category ID returns null without throwing, empty BufdirReportData produces full-length empty-sentinel list, partial data produces mixed isEmpty flags
Accessibility tests cover: all WCAG color token pairs assert contrast ratio >= 4.5:1 (normal) and >= 3.0:1 (large), all label builder functions for standard/empty/delta inputs, announceValueChange invokes SemanticsService with correct message
No test uses `sleep()` or `Future.delayed()` for synchronisation — use `pump()` / `pumpAndSettle()` or stream expectations

Technical Requirements

frameworks
Flutter
Dart
flutter_test
apis
Supabase (mocked via mocktail or manual mock)
Flutter SemanticsService (mocked)
data models
BufdirReportData
BufdirPeriodComparisonData
BufdirFieldEntry
BufdirAccessibilityColorTokens
performance requirements
Full test suite must complete in under 60 seconds in CI
No real network calls — all Supabase interactions mocked
security requirements
No real Supabase credentials or API keys in test fixtures — use mock/stub data only

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Use `mocktail` for mocking the Supabase client — create a `MockSupabaseClient` that returns controlled stream data. For stream tests, use `expectLater(stream, emitsInOrder([...]))` rather than manual await chains. For color contrast unit tests, implement a local `_contrastRatio(Color fg, Color bg)` helper using the WCAG relative luminance formula — this makes the assertion self-contained without external tools. Group tests by component using `group()` blocks.

Add a coverage step to the CI pipeline (`genhtml` or `lcov`) so coverage regressions are caught automatically. Keep test fixtures in a `test/fixtures/` directory, not inline in test files.

Testing Requirements

Unit tests for all pure functions in BufdirReportStructureMapper and BufdirAccessibilityUtils. Stream tests for BufdirPreviewRepository using ProviderContainer with overridden Supabase dependency. Widget tests for announceValueChange using a mock SemanticsBinding. Parametrised tests for all known category IDs and all color token pairs.

Test helper factory methods to create fixture BufdirReportData instances with controlled field values. Coverage report generated and checked in CI — build fails if any component drops below 85%.

Component
Bufdir Preview Repository
data medium
Dependencies (3)
Add a second Riverpod stream to BufdirPreviewRepository that fetches the equivalent aggregated data for the prior reporting period, enabling diff/comparison views. Re-use the existing query layer with a shifted date range parameter. Cache prior-period results independently. Return a BufdirPeriodComparisonData model containing both current and prior snapshots alongside delta values. epic-bufdir-report-preview-foundation-task-004 Extend BufdirReportStructureMapper so that when the aggregated data has no value for a required field, the field is still represented in the output structure with an explicit zero or null sentinel — never omitted. Implement `buildOrderedFieldList(BufdirReportData data) -> List<BufdirFieldEntry>` that iterates all canonical fields in order, populates each with its data value or the empty sentinel, and returns the complete ordered list ready for rendering. epic-bufdir-report-preview-foundation-task-007 Build BufdirAccessibilityUtils with three capabilities: (1) a set of WCAG 2.2 AA compliant color tokens (foreground/background pairs that meet the 4.5:1 contrast ratio for normal text and 3:1 for large text) for use in the preview UI; (2) semantic label builder functions that generate descriptive Semantics labels for field rows — e.g., `buildFieldSemanticLabel(String section, String field, String value) -> String` that produces screen-reader-friendly strings; (3) live-region helpers wrapping Flutter's SemanticsService.announce for announcing dynamic value changes to VoiceOver/TalkBack users. epic-bufdir-report-preview-foundation-task-008
Epic Risks (2)
high impact medium prob integration

The preview repository depends on aggregated data produced by the Bufdir Data Aggregation feature. If the aggregation RPC schema or Supabase view columns change during parallel development, the repository's typed Dart models will break, causing compile errors or runtime null-dereference failures.

Mitigation & Contingency

Mitigation: Define a shared Dart interface (abstract class) for the aggregated data contract early and have both features code against it. Use Supabase typed generated clients so schema mismatches surface at code generation time rather than runtime.

Contingency: If the aggregation schema changes after the repository is complete, run `supabase gen types dart` immediately, update the repository model, and run repository unit tests before unblocking UI development. Keep a mock data fixture so UI work can continue during the fix.

high impact medium prob scope

The BufdirReportStructureMapper must map internal activity category IDs to the exact label strings used on the official Bufdir reporting form. If the mapping is incomplete or uses outdated labels, coordinators will see mismatches when cross-referencing the preview with the paper form, potentially leading to incorrect submissions.

Mitigation & Contingency

Mitigation: Obtain the current Bufdir reporting form PDF directly from Bufdir (Norse Digital Products has an existing Bufdir dialogue). Extract all field labels and section names into a static constants file reviewed by at least one coordinator from NHF or HLF before implementation begins.

Contingency: If incorrect labels are discovered during UAT on TestFlight, update the static constants file and redeploy. Because the mapper is a pure Dart class with no database storage, corrections require no migration — only a new build.