high priority low complexity testing pending testing specialist Tier 2

Acceptance Criteria

MapMarkerWidget renders the correct colour for each availability state: available (green-equivalent design token), unavailable (grey design token), paused (amber design token) — verified via widget test colour assertions
MapMarkerWidget exposes a Semantics label that reads '{mentor name}, {availability state}' — verified via semantic tree finder
MapMarkerWidget semantics label updates when the BLoC emits a new availability state without full widget rebuild
ViewToggleButton displays label 'Map view' when in map mode and 'List view' when in list mode — verified via text finder
ViewToggleButton tap emits the correct ViewToggled event and does not emit any FilterChanged or FilterReset events — verified via bloc_test mock
ViewToggleButton retains current filter state after toggle — filter BLoC state snapshot before and after toggle must be equal
MapMarkerWidget touch target is at minimum 48×48 logical pixels — verified via tester.getSize()
ViewToggleButton touch target is at minimum 48×48 logical pixels
All tests pass with flutter_test and produce zero semantic warnings in the test output
No network calls are made during any widget test — all BLoC state is injected via MockBloc or FakeBloc

Technical Requirements

frameworks
Flutter
flutter_test
BLoC
bloc_test
data models
PeerMentor
AvailabilityState
MapFilterState
performance requirements
Each individual test must complete in under 2 seconds
Widget pump must not require more than 2 pumpAndSettle cycles per interaction
security requirements
No real user data in test fixtures — use anonymised or synthetic mentor data only
ui components
MapMarkerWidget
ViewToggleButton

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use bloc_test's whenListen helper to stream state sequences into the widget under test. Resolve design token colours from the app's ThemeData rather than comparing hex literals — this keeps tests resilient to token value changes. For semantics label tests, call tester.ensureSemantics() at the top of the test to activate the semantics tree. Touch target tests should wrap the widget in a MediaQuery with default device pixel ratio to avoid DPI-related false negatives.

Group tests by widget using Flutter's group() function and use setUp() to instantiate fresh BLoC mocks for each test case to prevent state leakage.

Testing Requirements

Unit-level widget tests using flutter_test. Use MockBloc/FakeBloc (bloc_test package) to inject controlled state without network or database calls. Semantic tree assertions via find.bySemanticsLabel and tester.getSemantics(). Colour assertions via Theme.of(context) resolved tokens, not hardcoded hex values.

Touch target size assertions via tester.getSize(). Achieve 100% branch coverage across all availability state variants. Tests must run headlessly in CI on both iOS and Android targets.

Component
Mentor Map Marker Widget
ui medium
Epic Risks (3)
high impact high prob technical

Flutter's map canvas (flutter_map) does not natively support semantic focus traversal for screen readers, meaning map markers may be entirely invisible to VoiceOver/TalkBack users. If the accessible list fallback is not treated as a first-class view, screen reader users will have no access to the feature.

Mitigation & Contingency

Mitigation: From sprint 1, treat mentor-list-fallback as a fully featured primary view, not an afterthought. Implement and test it in parallel with the map canvas. Make the view-toggle-button keyboard focusable and announced on every screen state. Conduct VoiceOver testing on device before submitting each PR touching UI components.

Contingency: If map canvas accessibility cannot be achieved for marker focus traversal, make the view-toggle-button the default focus target on screen load for VoiceOver users (detected via screen-reader-detection-service) so they are immediately directed to the list fallback without needing to discover the toggle.

medium impact medium prob technical

The mentor-info-popup must occupy no more than 40% of visible map area on small screens. On devices with screen heights under 667px (iPhone SE), overlapping with the filter panel or obscuring most of the map could severely degrade usability.

Mitigation & Contingency

Mitigation: Implement the popup as a bottom sheet capped at 40% of screen height with a ScrollView for overflow content. Test on iPhone SE (375x667pt) and the smallest commonly used Android form factor in the device lab. Define max-height as a percentage constant in location-privacy-config or design tokens.

Contingency: If the popup cannot fit all required fields within 40% height on smallest targets, truncate assigned contact count and certification badge to icons-only in the compact view, with a 'View Profile' button always visible at the bottom of the popup regardless of scroll position.

medium impact medium prob integration

Filter state must remain perfectly synchronised between the map view and the list fallback. If the filter panel emits state that is not consumed identically by both views, coordinators switching between views will see inconsistent mentor sets, eroding trust in the feature.

Mitigation & Contingency

Mitigation: Store active filter criteria in a single shared Riverpod provider owned by the map-view-screen and consumed by both map-marker-widget (via mentor-location-service) and mentor-list-fallback. Write integration tests that apply a filter, switch views, and assert identical mentor counts in both views.

Contingency: If filter sync proves brittle, simplify to a single filter state object passed explicitly as a constructor argument to both views on each rebuild, eliminating indirect state sharing.