high priority medium complexity testing pending testing specialist Tier 5

Acceptance Criteria

Test group `MentorLocationService - consent enforcement`: opted-out mentors (consent_expires_at in the past or privacy_level == 'hidden') are excluded from results returned by `getMentorsInBounds()`
Test group `MentorLocationService - bounding box delegation`: `getMentorsInBounds()` calls repository mock exactly once with the correct `BoundingBox` parameters and returns the transformed list
Test group `MentorLocationService - filter integration`: when `MentorFilterService` mock returns a non-empty `FilterCriteria`, the service passes it to the repository query; when filter returns empty criteria, no filter is appended
Test group `MentorLocationService - offline cache`: cache hit returns stored list without calling repository; cache miss calls repository and stores result; stale cache (TTL exceeded) triggers a fresh repository call
Test group `MentorLocationService - haversine sort`: given a user coordinate and a list of mentor locations with known distances, results are sorted ascending by haversine distance with correct ordering verified against precomputed expected values
Test group `MentorMapBloc - state transitions`: `LoadMap` event transitions from `MentorMapInitial` → `MentorMapLoading` → `MentorMapLoaded`; `FilterMentors` event triggers filter application and emits updated `MentorMapLoaded`; `RefreshMap` event re-fetches and emits new `MentorMapLoaded`; any repository exception emits `MentorMapError`
All mocks created with mocktail; no real Supabase calls made in any test
`flutter test --coverage` reports ≥ 90% line coverage on `mentor_location_service.dart` and `mentor_map_bloc.dart`
All tests pass in CI with zero flakiness on three consecutive runs

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
flutter_test
data models
MentorLocationService
MentorMapBloc
MentorLocationRepository
MentorFilterService
BoundingBox
FilterCriteria
MentorLocation
performance requirements
Each test must complete in under 500 ms
No real async delays — use fake async or mock timers for TTL-based cache tests
security requirements
No real user PII or coordinates in test fixtures — use synthetic lat/lng values outside Norway
No API keys or Supabase URLs hardcoded in test files

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Use `mocktail` `registerFallbackValue` for any custom value objects (e.g., `BoundingBox`, `FilterCriteria`) that are passed to mocked methods. For haversine sort tests, pre-calculate expected distances manually for 3–5 known coordinate pairs and assert ordering. For cache tests, inject a fake clock (via a `Clock` abstraction or `DateTime` factory override) rather than using `Future.delayed`. BLoC tests should use `blocTest` from the `bloc_test` package to keep assertions readable.

Ensure each `group` block has a `setUp` that creates fresh mock instances to prevent test pollution. Add a `tearDown` that verifies no unexpected mock interactions occurred (`verifyNoMoreInteractions`).

Testing Requirements

Pure unit tests using `flutter_test` and `mocktail`. Use `bloc_test` package for BLoC state transition assertions (`blocTest`). Use `fake_async` for TTL cache expiry tests. Structure test file with nested `group()` blocks matching each scenario group listed in acceptance criteria.

Create a shared `fixtures/mentor_location_fixtures.dart` file with reusable test data to avoid duplication. Run `flutter test --coverage` and verify lcov report. No widget tests in this task — pure logic only.

Component
Mentor Location Service
service high
Epic Risks (2)
medium impact medium prob technical

The dual BLoC state machines (map view state + filter state) may introduce subtle synchronisation bugs where filter changes do not correctly re-trigger viewport queries, causing stale data to appear on the map.

Mitigation & Contingency

Mitigation: Define all BLoC state transitions in a state diagram before implementation. Use flutter_bloc's BlocObserver in development mode to log every state transition. Write explicit unit tests for filter-change → re-query transitions.

Contingency: If state synchronisation bugs appear in integration testing, refactor to a single unified BLoC that owns both map viewport state and filter state, eliminating cross-BLoC dependencies.

low impact medium prob scope

Cached mentor location data may become stale (mentors move, pause, or revoke consent) and coordinators in offline mode could be shown incorrect mentor information, leading to wasted outreach.

Mitigation & Contingency

Mitigation: Display a clear timestamp on cached data indicating when it was last synced. Set cache TTL to 24 hours and show an 'offline — data from [date]' banner. Revoked consent removes the mentor from the cache on next successful sync via contact-cache-sync-repository.

Contingency: If cache staleness causes user complaints, reduce TTL to 4 hours and implement background sync on app foreground. Accept that very-recently-revoked mentors may appear briefly in offline mode — document this as a known limitation in the privacy policy.