high priority low complexity testing pending testing specialist Tier 4

Acceptance Criteria

Test `empty filter passthrough`: calling `applyFilter(criteria: FilterCriteria.empty(), mentors: list)` returns the original list unchanged (no mentors removed, order preserved)
Test `availability-only filter`: providing a `FilterCriteria` with availability slots and no specialisation filters returns only mentors whose availability overlaps the requested slots
Test `specialisation-only filter`: providing a `FilterCriteria` with specialisation IDs and no availability filter returns only mentors whose specialisations include at least one of the requested IDs
Test `combined filter`: availability + specialisation criteria applied together returns only mentors satisfying both conditions (intersection, not union)
Test `validation rejection`: passing a `FilterCriteria` with an empty string specialisation ID or a null availability slot throws `FilterValidationException` before any filtering occurs
Test `paused mentor exclusion`: mentors with `status == 'paused'` are excluded from all filter results regardless of other criteria, including the empty filter passthrough
Test `Supabase query serialisation`: `FilterCriteria.toQueryParameters()` produces the correct Supabase PostgREST query parameter map for availability and specialisation filters, verified against expected string representations
`flutter test --coverage` reports ≥ 90% line coverage on `mentor_filter_service.dart` and `filter_criteria.dart`
All tests are deterministic and pass on three consecutive CI runs without flakiness

Technical Requirements

frameworks
Flutter
flutter_test
apis
Supabase PostgREST query parameter format
data models
MentorFilterService
FilterCriteria
MentorLocation
performance requirements
All tests complete in under 200 ms each — no async I/O in filter logic tests
security requirements
No real Supabase credentials in test files
Test fixtures must not contain real user identifiers

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

The filter service should be a pure Dart class with no Flutter or BLoC dependencies, making it easy to test without `flutter_test` widget infrastructure. Serialisation tests are the highest-value tests here — ensure the Supabase `eq`, `in_`, and `overlaps` parameter names match what the repository actually passes to the Supabase client. For the paused mentor exclusion test, confirm whether exclusion happens in the filter service or the location service — it should be documented clearly and tested at the authoritative layer. If `FilterCriteria` uses `freezed`, generated equality simplifies assertion; otherwise override `==` and `hashCode`.

Keep fixture data minimal: 5–8 mentor objects covering all status and specialisation combinations is sufficient.

Testing Requirements

Pure unit tests with `flutter_test`. No BLoC or widget testing in this task — filter service is a plain Dart class. Use parameterised tests (`test.each` equivalent via a loop with `test()` calls) for serialisation assertions covering multiple filter combinations. Group tests with `group()` blocks per scenario.

Create a `fixtures/filter_criteria_fixtures.dart` with reusable `FilterCriteria` instances. Assert exact exception types for validation rejection tests using `expect(() => ..., throwsA(isA()))`. Run coverage and verify ≥ 90%.

Component
Mentor Filter Service
service low
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.