Write unit tests for RoleAccessValidator
epic-coordinator-statistics-dashboard-foundation-task-009 — Create comprehensive unit tests for the RoleAccessValidator covering coordinator-scoped access approval, coordinator cross-chapter access denial, org-admin cross-coordinator access approval, and access denial exception types and messages. Use flutter_test and mock Supabase auth context. Target 100% branch coverage on access decision paths.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Create a test helper buildFakeAuthState({required String userId, required String orgId, required String role}) that returns a fake Supabase User/Session object with the correct app_metadata structure. This avoids duplicating JWT fixture setup across every test. Structure the test file as: roleAccessValidatorTest.dart in test/unit/validators/. Import RoleAccessValidator directly — no integration wiring needed.
If RoleAccessValidator depends on a Supabase client to resolve role claims, inject a mock via the constructor. Prefer testing the public contract (exception type + message prefix) over implementation details (which private method was called). After 100% branch coverage is confirmed, add a test for the boundary case where coordinator_id is passed as org_id (transposed parameters) — this is a common integration bug.
Testing Requirements
Use flutter_test group() blocks to organise by scenario: 'coordinator access', 'org-admin access', 'unauthenticated access', 'cross-org access'. Each group has positive (allowed) and negative (denied) test cases. Mock the Supabase auth context using a fake AuthState object with preset user.id and app_metadata claims. Use expect(..., throwsA(isA
After running tests, verify coverage with: flutter test --coverage && genhtml coverage/lcov.info -o coverage/html. The RoleAccessValidator source file must show 100% branch coverage in the HTML report.
Pre-aggregated Supabase views may still be slow for orgs with very large activity datasets (NHF with 1,400 chapters). If the view query plan performs sequential scans, dashboard load times could exceed acceptable thresholds and degrade the perceived value of the feature.
Mitigation & Contingency
Mitigation: Design views with composite indexes on (org_id, coordinator_id, month) from the start. Run EXPLAIN ANALYZE during development against a seeded dataset of realistic scale. Add materialized view refresh strategy if needed.
Contingency: If live view performance is insufficient, convert to materialized views refreshed on a schedule or on activity-write triggers. Expose the refresh delay transparently in the UI with a 'last updated' timestamp.
Supabase RLS policies for the stats views may not be configured correctly during initial migration, potentially allowing cross-coordinator data leakage before the RoleAccessValidator layer is reached. This is a security and compliance risk.
Mitigation & Contingency
Mitigation: Write RLS integration tests as part of this epic that explicitly verify a coordinator JWT cannot read another coordinator's stats rows. Apply RLS policies in the migration script itself, not as a manual step.
Contingency: If an RLS gap is discovered post-deployment, immediately disable the stats screen via a feature flag, apply the corrected RLS migration, and re-enable after verification. Log and audit all queries that ran during the gap window.
Cache invalidation logic may not be triggered correctly when a new activity is registered by a peer mentor or when an expense approval is granted. Stale data could cause coordinators to make decisions based on outdated KPIs, undermining trust in the dashboard.
Mitigation & Contingency
Mitigation: Define explicit invalidation event contracts with the activity registration and expense approval pipelines. Implement an event bus subscription within StatsCacheManager. Document the invalidation contract in code.
Contingency: If event-driven invalidation proves unreliable, add a manual 'Refresh' pull-to-refresh gesture on the dashboard and reduce TTL to 5 minutes as a fallback degradation strategy.