Write unit and integration tests for consent lifecycle
epic-geographic-peer-mentor-map-consent-privacy-task-010 — Implement comprehensive tests covering: grantConsent happy path, double-grant idempotency, revokeConsent atomicity with location data deletion, checkConsent returning correct status for each state (granted, denied, revoked, re-consent-required), RLS policy enforcement for all roles, and dialog widget rendering with both Opt In and Opt Out interactions. Achieve minimum 90% branch coverage on location-consent-service.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 6 - 158 tasks
Can start after Tier 5 completes
Implementation Notes
The atomicity test for revokeConsent requires careful mock design: inject a SupabaseException after the consent status update but before the location row deletion, then assert that the service either rolls both back or surfaces a CascadeDeleteFailure. Since Supabase RLS cannot be exercised in a real unit test, create a RlsPolicySimulator class that mirrors the policy logic in Dart so it can be tested in-process. For widget tests, use pumpWidget with a BlocProvider wrapping a fake ConsentBloc stub — do not spin up the real BLoC. Coverage gaps most likely hide in error paths (network timeout, malformed JSON from Supabase); ensure each failure class has at least one test.
Keep test file names mirroring the source file they cover to simplify navigation.
Testing Requirements
Use flutter_test for all unit and widget tests. Create a FakeSupabaseClient or use mocktail to stub all Supabase calls — no live Supabase connection in tests. Organize tests in three files: location_consent_service_test.dart (unit), consent_rls_policy_test.dart (integration-style with mocked RLS), and consent_dialog_widget_test.dart (widget). Use setUp/tearDown to reset state between cases.
Run coverage with `flutter test --coverage` and enforce the 90% branch threshold in CI via lcov. Test all four ConsentStatus enum values explicitly. For the atomicity test, inject a fault into the mock after the first DB write and assert rollback behavior.
If the privacy policy text or consent terms change after mentors have already opted in, existing consent records may become legally insufficient, requiring re-consent from all opted-in mentors which could temporarily reduce map coverage.
Mitigation & Contingency
Mitigation: Store a consent_version field on every consent record. Implement a consent version check in location-consent-service that compares the stored version against the current policy version from location-privacy-config and flags stale consents for re-consent prompting.
Contingency: If a policy update invalidates existing consents, suppress affected mentors from the map, queue them for re-consent notification via the existing in-app notification system, and restore map visibility only after new consent is recorded.
A poorly designed consent dialog may lead to low opt-in rates, reducing map utility for coordinators to the point where the feature delivers insufficient value to justify maintenance cost.
Mitigation & Contingency
Mitigation: Follow plain-language writing guidelines from the cognitive accessibility feature. User-test the dialog with 2-3 peer mentors from Blindeforbundet before implementation is finalised. Ensure the dialog explains the benefit to the mentor, not just the data collection facts.
Contingency: If opt-in rate after launch is below 40%, conduct a targeted usability study and iterate on dialog copy and layout. The coordinator can also send a bulk opt-in invitation notification (per the user story) to non-consenting mentors.