Write unit tests for AccessDenialService role-block logic
epic-no-access-screen-access-control-task-008 — Write unit tests covering: global admin role returns isBlocked=true, peer mentor role returns isBlocked=false, coordinator role returns isBlocked=false, admin portal URL is correctly retrieved from config repository mock, and service emits correct stream events when role changes. Use flutter_test with mocked dependencies.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
The service under test likely wraps a stream from an auth/role provider and maps role values to `isBlocked` booleans. Ensure the mock repository's `getAdminPortalUrl()` is stubbed to return a test URL string so the assertion is verifiable. When testing stream events, use `expect(service.stateStream, emitsInOrder([...]))` before triggering role changes. Be careful not to leave open `StreamController`s — call `addTearDown(() => service.dispose())` in each test group.
If the service uses Riverpod internally, use `ProviderContainer` with overrides instead of mocking the Riverpod layer.
Testing Requirements
Unit tests only using `flutter_test`. Use `StreamController` or `BehaviorSubject` fakes to simulate role-change events. Use `mocktail` (preferred in Flutter BLoC ecosystem) to mock `NoAccessConfigRepository`. Each role variant must be its own `test()` block.
Use `expectLater` with `emitsInOrder` for stream assertions. Group related tests under `group('AccessDenialService', ...)`. No widget or integration tests in this file.
If the GoRouter redirect callback evaluates the no-access route itself as a blocked destination, it will trigger an infinite redirect loop, crashing the navigator.
Mitigation & Contingency
Mitigation: Add an explicit guard condition in the redirect callback: return null (no redirect) when the current location is already the no-access route or the logout route. Write a dedicated unit test covering this exact scenario.
Contingency: If the redirect loop is detected in production, deploy a hotfix that adds the null-return guard; the feature can be toggled off via the existing feature-flag infrastructure while the fix is prepared.
The access-denial-service may read role state before authentication completes (e.g. during app resume), causing a temporary false-positive block that redirects valid peer-mentor users to the no-access screen.
Mitigation & Contingency
Mitigation: Subscribe to the role-state-manager's loading/ready lifecycle and only evaluate role-based access once the RBAC state is confirmed as loaded. Return a 'pending' state that causes the guard to defer rather than redirect.
Contingency: Add a retry mechanism: if a user lands on the no-access screen but their role subsequently resolves as non-blocked, automatically navigate them to the role-based home screen.