critical priority medium complexity testing pending testing specialist Tier 6

Acceptance Criteria

Unit tests cover grantConsent happy path: status transitions from null/denied/revoked to granted, audit log entry created, location_consent field updated in Supabase
Double-grant idempotency test: calling grantConsent twice for the same mentor results in a single audit log entry and no duplicate DB writes
revokeConsent atomicity test: a simulated mid-transaction failure leaves both consent status and location data in a consistent state (both rolled back or both committed)
revokeConsent cascade test: after revocation, all rows in mentor_locations table for the affected mentor are deleted and checkConsent returns 'revoked'
checkConsent returns correct typed status for each of the four states: granted, denied, revoked, re-consent-required — tested with mocked Supabase responses
RLS policy enforcement tests: peer mentor can only read/write their own consent row; coordinator read-only; admin can read all but not write consent on behalf of mentors
Widget test: ConsentDialog renders with 'Opt In' and 'Opt Out' buttons, tapping 'Opt In' calls grantConsent, tapping 'Opt Out' calls revokeConsent, loading and error states render correctly
Minimum 90% branch coverage on location-consent-service as reported by flutter_test --coverage
All tests pass in CI without network calls — Supabase client is fully mocked/faked
No test relies on global state; each test case sets up and tears down its own fixtures

Technical Requirements

frameworks
Flutter
flutter_test
BLoC
mocktail or mockito for mocking
apis
Supabase PostgREST (mocked)
Supabase RLS policy simulation via mock
data models
MentorConsent
ConsentAuditLog
MentorLocation
performance requirements
Full test suite completes in under 60 seconds on CI
No real network calls — all Supabase interactions mocked
security requirements
Test fixtures must not contain real PII — use synthetic mentor IDs only
RLS enforcement tests must explicitly assert that cross-user data access returns empty or throws Forbidden
ui components
ConsentDialog widget
ConsentStatusBadge widget

Execution Context

Execution Tier
Tier 6

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.

Component
Location Consent Service
service medium
Epic Risks (2)
medium impact medium prob scope

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.

medium impact medium prob scope

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.