high priority medium complexity testing pending testing specialist Tier 3

Acceptance Criteria

Test file for OrgRateConfigRepository covers: Stream emits updated config when Supabase realtime pushes a change, cache returns stored value on hit without calling Supabase, cache miss triggers a Supabase fetch, Supabase error propagates as a typed domain exception
Test file for MileageClaimRepository covers: insert calls the adapter with correct mapped fields and forces 'pending' status, fetchByUser returns items ordered descending by activity date, fetchByUser with page=2 passes correct range offset, fetchForCoordinator with status filter passes filter to query, fetchForCoordinator without filter fetches all statuses, updateStatus sends correct patch payload, softDelete succeeds when correction window is still open, softDelete throws CorrectionWindowExpiredException when window has expired, softDelete on a non-existent claim propagates a not-found exception
Test file for DistancePrefillService covers: getLastDistance returns null for unknown userId, saveLastDistance then getLastDistance returns correct value, clearOnLogout causes subsequent getLastDistance to return null, two different user IDs have independent stored values, saveLastDistance with distanceKm <= 0 throws ArgumentError
All three test files use fakes (hand-written or mockito-generated) — no real Supabase connections
Each test is independent — no shared mutable state between tests (setUp creates fresh fake instances)
Running flutter test on these files reports 0 failures
Line coverage for each component is >= 90% as measured by flutter test --coverage

Technical Requirements

frameworks
Dart (latest)
Flutter
flutter_test
data models
MileageClaim
MileageClaimStatus
OrgRateConfig
LocalDistanceCache
performance requirements
All tests must complete in under 2 seconds total — no real I/O or network calls
Fake implementations must be simple synchronous or immediately-resolving async
security requirements
Test data must not contain real personnummer, real user IDs, or real organisation data — use clearly fake identifiers (e.g., 'user-test-001')

Execution Context

Execution Tier
Tier 3

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.

Component
Mileage Claim Repository
data medium
Epic Risks (2)
medium impact medium prob integration

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.

medium impact medium prob scope

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.