Write unit tests for all three repository and service components
epic-mileage-reimbursement-entry-data-layer-task-009 — Write unit tests covering OrgRateConfigRepository (Stream emission on config change, cache hit/miss, error propagation), MileageClaimRepository (insert, fetchByUser ordering, coordinator fetch filtering, softDelete correction window guard, status update), and DistancePrefillService (null for first-time user, read after write, clear on logout). Use fakes for Supabase adapter and LocalDistanceCache. Achieve 90%+ line coverage on all three components.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Organise test files to mirror the source tree: test/data/mileage_claim/supabase_mileage_claim_repository_test.dart, test/data/mileage_claim/distance_prefill_service_test.dart, test/data/org_rate_config/org_rate_config_repository_test.dart. For Stream-based tests on OrgRateConfigRepository, use StreamController in the fake adapter and verify emissions with expectLater(..., emitsInOrder(...)). For the correction window test, construct a MileageClaim with correctionWindowEnd set to DateTime.now().subtract(Duration(hours: 1)) to simulate an expired window. For the valid window test, set correctionWindowEnd to DateTime.now().add(Duration(hours: 24)).
Avoid using DateTime.now() directly in production code being tested — accept a clock parameter or use a testable time abstraction if strict determinism is required.
Testing Requirements
All tests are unit tests using flutter_test. Use fake (hand-implemented) collaborators rather than mockito mocks where the fake logic is simple (e.g., a Map-backed fake for LocalDistanceCache, a List-backed fake for the Supabase adapter that records calls). Use mockito or mocktail only where the collaborator interface is complex and a full fake would be verbose. Group tests with group() blocks per component and per method.
Use setUp() to reinitialise fakes before each test. Run with flutter test test/data/ and confirm coverage with flutter test --coverage followed by lcov report generation.
If OrgRateConfigRepository caches the per-km rate aggressively and an admin updates the rate mid-session, ongoing form interactions will show the old rate until the Stream emits. This could result in the UI showing a rate that differs from what is stored when the claim is submitted, causing confusion or disputes.
Mitigation & Contingency
Mitigation: Subscribe to a Supabase Realtime channel for the org_configuration table so config changes propagate within seconds. Document the eventual-consistency window in code comments.
Contingency: If Realtime subscription proves unreliable in test, add a polling fallback with a configurable interval (default 5 minutes) and display a 'rate updated' toast when the stream emits a changed value.
The correction window within which a claim can be deleted or voided is not explicitly specified in the feature documentation. Implementing the wrong window (e.g. 24 hours vs 7 days) could lock users out of corrections or allow inappropriate post-approval modifications.
Mitigation & Contingency
Mitigation: Raise the correction window definition as a blocking question to the HLF product owner before implementing the delete/void path in MileageClaimRepository. Implement the window duration as an org-level configuration value rather than a hardcoded constant.
Contingency: If the question cannot be resolved before implementation, default to 24 hours as the most conservative option and flag the value for review in the first user-acceptance test.