high priority low complexity testing pending testing specialist Tier 2

Acceptance Criteria

All test cases pass with `flutter test` in CI with zero skipped tests
Successful pause flow: blocTest verifies state sequence [MentorStatusInitial, MentorStatusLoading, MentorStatusSuccess(isPaused: true)]
Successful reactivation flow: blocTest verifies state sequence [MentorStatusLoading, MentorStatusSuccess(isPaused: false)]
Network error flow: blocTest verifies state sequence [MentorStatusLoading, MentorStatusError(message: <non-empty string>)] when service throws a network exception
Invalid-transition error: blocTest verifies MentorStatusError is emitted with isInvalidTransition == true when service throws InvalidTransitionException
Event ordering: two rapid PauseMentorEvents dispatched sequentially result in only one completed flow — the second event is dropped or queued, not processed concurrently
MentorStatusService mock is set up with Mocktail — no real HTTP or Supabase calls in any test
Each test is fully isolated: setUp creates a fresh BLoC and mock instance
Test file follows project naming convention: mentor_status_bloc_test.dart in test/bloc/
Code coverage for MentorStatusBLoC logic reaches 100% branch coverage

Technical Requirements

frameworks
Flutter
BLoC
bloc_test
Mocktail
data models
MentorStatusState
MentorStatusEvent
PauseMentorEvent
ReactivateMentorEvent
MentorStatusService
performance requirements
Full test suite for this BLoC completes in under 5 seconds

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use blocTest() for every test case — do not use raw StreamController or manual bloc.add() + expectLater() chains. Register Mocktail fallbacks for any custom types used in service method signatures (registerFallbackValue). Define a shared MockMentorStatusService and create a new instance in setUp() to prevent state leak between tests. If the BLoC uses droppable() or restartable() event transformers, test event-ordering explicitly by adding two events with tester.pump() in between.

Keep test descriptions in English and descriptive: 'emits [Loading, Success] when PauseMentorEvent is added and service call succeeds'.

Testing Requirements

Pure unit tests using bloc_test's blocTest() helper. No widget tree, no Flutter binding needed. Use fake async timers where the BLoC uses debounce or delays. Verify both the exact state sequence (expect:) and that no extra states are emitted (no additional states after the final expected state).

Use verify() from Mocktail to assert service methods are called exactly once per valid event. Test invalid-transition by having the mock throw a custom InvalidTransitionException. Test event ordering by using a custom EventTransformer or by asserting the BLoC uses sequential (droppable/restartable) transformer.

Component
Mentor Status BLoC
infrastructure low
Epic Risks (3)
medium impact medium prob technical

PauseConfirmationDialog must meet WCAG 2.2 AA focus trap requirements: when the dialog opens, focus must move to the first interactive element; when it closes, focus must return to the triggering toggle. Flutter's default showDialog does not always guarantee correct focus restoration on Android, which could trap screen-reader users.

Mitigation & Contingency

Mitigation: Use a custom modal implementation wrapping Flutter's Dialog with explicit FocusScope management and test with TalkBack on Android and VoiceOver on iOS during development, not just in final QA. Reference the accessible-modal-sheet pattern already used elsewhere in the codebase.

Contingency: If full WCAG focus management cannot be achieved within the sprint, ship the feature with a documented accessibility defect and schedule a dedicated accessibility remediation task. Communicate the known gap to the accessibility stakeholder at HLF/NHF.

low impact medium prob technical

If the user taps the PauseReactivateToggle rapidly before the BLoC emits a loading state, multiple PauseMentorEvents could be added to the BLoC stream, resulting in duplicate service calls and inconsistent UI state (toggle flickering between states).

Mitigation & Contingency

Mitigation: Disable the toggle widget immediately on first tap by emitting MentorStatusLoading synchronously before the async service call begins. Use BLoC's event transformer with droppable() to discard subsequent events while a transition is in progress.

Contingency: If BLoC event deduplication is not sufficient, add a debounce at the widget level (300 ms) and a server-side idempotency check in MentorStatusService that no-ops if the requested transition is already in progress.

low impact low prob security

PauseStatusBanner must conditionally render the reactivate shortcut only for users with coordinator permission. If the permission check relies on a stale role state in the Riverpod provider, a peer mentor could briefly see a reactivate action they are not authorised to use, which could cause a confusing permission-denied error if tapped.

Mitigation & Contingency

Mitigation: Source the permission check directly from the role-resolution Riverpod provider (which is kept in sync with Supabase auth) rather than from local component state. Add a widget test asserting the shortcut is absent when the user role is peer_mentor.

Contingency: If the shortcut is accidentally shown to an unauthorised user, the underlying MentorStatusService enforces role validation server-side, so the worst outcome is a visible error message rather than an actual unauthorised state change.