Unit and integration tests for all three foundation components
epic-bufdir-report-preview-foundation-task-009 — Write comprehensive tests covering: BufdirPreviewRepository stream emissions for loaded/error/cache-hit states using a mocked Supabase client; prior-period comparison data correctness; BufdirReportStructureMapper ordering, unknown category handling, and empty field sentinels; BufdirAccessibilityUtils color contrast ratios (assert each token pair meets WCAG 4.5:1), semantic label output strings, and live-region announcement invocations. Achieve minimum 85% line coverage across all three components.
Acceptance Criteria
Technical Requirements
Execution Context
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%.
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.
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.