high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

All five step components have at least one widget test file under test/widgets/wizard/
ActivityTypeStep tests: default chip is pre-selected on mount; tapping a different chip emits the correct Cubit event; Semantics labels on chips are verified
DateStep tests: calendar shows current date highlighted by default; tapping a future date calls the expected Cubit event with the correct DateTime; invalid past dates are not selectable (if restricted)
DurationStep tests: preset duration chips render and are selectable; tapping 'Other' shows a free-entry TextField; entering a non-numeric value shows a validation error and does not advance; entering a valid numeric value emits the correct event
NotesStep tests: tapping 'Skip' without entering text emits an event with null/empty notes and does not show an error; entering text and tapping 'Next' emits the event with the text value
RegistrationConfirmationView tests: summary displays the activity type, date, duration, and notes values from the provided mock state; auto-dismiss fires after 3 seconds in fakeAsync; manual close button is present and tappable
All tests use MockCubit (bloc_test/mocktail) or BlocProvider with a fake state — no real Supabase or network calls in any test
Test suite runs with flutter test and all tests pass with zero failures
Test code coverage for the five step widgets is at or above 80% branch coverage

Technical Requirements

frameworks
Flutter
BLoC
flutter_test
bloc_test
data models
ActivityRegistration
ActivityType
DurationOption
performance requirements
Each individual test must complete in under 2 seconds
ui components
ActivityTypeStep
DateStep
DurationStep
NotesStep
RegistrationConfirmationView

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Create test helper functions (e.g., pumpActivityTypeStep(tester, {ActivityRegistrationCubit cubit})) to reduce boilerplate across test files. Give interactive widgets explicit Keys (e.g., Key('chip-activity-type-visit')) to make finders reliable and independent of label text changes. For the calendar picker (likely showDatePicker or a custom widget), prefer testing the custom widget directly with a fixed initialDate rather than testing the platform date picker dialog (which is hard to drive in widget tests). For DurationStep free-entry fallback, use tester.enterText(find.byType(TextField), '45') and then tester.testTextInput.receiveAction(TextInputAction.done).

Document all Cubit event classes that each test verifies so reviewers can confirm coverage.

Testing Requirements

All tests are widget (unit-level) tests using flutter_test's WidgetTester. Use bloc_test's MockBloc/MockCubit pattern with mocktail for state stubbing. Group tests per component in separate test files. Each test should: (1) pump the widget wrapped in a BlocProvider, (2) stub the cubit's state via whenListen or seed, (3) find widgets by key or semantic label, (4) perform taps/text entry, (5) verify emitted events via verify().

Use fakeAsync for timer-based tests in RegistrationConfirmationView. Run flutter test --coverage and confirm branch coverage >= 80% for each step widget file.

Epic Risks (4)
high impact medium prob scope

As wizard steps accumulate additional features (duplicate warning, retroactive date chips, custom duration entry), the two-tap happy path may inadvertently require extra interactions. A step that previously auto-advanced may start requiring a confirmation tap, breaking the core promise of the feature and increasing friction for high-frequency users like HLF's 380-registration peer mentor.

Mitigation & Contingency

Mitigation: Define and automate a regression test that performs the complete two-tap happy path (open bottom sheet → confirm → confirm) and asserts the confirmation view is reached in exactly two tap events. Run this test in CI on every PR touching the wizard. Treat any failure as a blocking defect.

Contingency: If a new feature unavoidably adds a tap to the happy path, provide a 'quick mode' toggle in user settings that collapses the wizard to a single-confirmation screen for users who never change defaults.

medium impact medium prob technical

Flutter bottom sheets are dismissed on back-button press or background tap by default. If the wizard state is not preserved, a peer mentor who accidentally dismisses mid-flow loses all their entered data and must start over — a significant frustration for users with cognitive disabilities or motor impairments who take longer to fill each step.

Mitigation & Contingency

Mitigation: Implement the wizard state as a persistent Cubit that outlives the bottom sheet widget's lifecycle, scoped to the registration feature route. On re-open, the Cubit restores the previous step and field values. Add a 'discard changes?' confirmation dialog when the user explicitly dismisses a partially filled wizard.

Contingency: If persistent state proves difficult to implement with the chosen routing strategy, implement draft auto-save to a local draft repository every time a field value changes, and restore from draft on the next open.

high impact high prob technical

Multi-step wizard bottom sheets are among the most complex accessibility scenarios in Flutter. Screen readers (TalkBack, VoiceOver) may not announce step transitions, focus may land on the wrong element after advancing, and animated transitions can interfere with the accessibility tree update cycle — making the feature unusable for Blindeforbundet users who rely on screen readers.

Mitigation & Contingency

Mitigation: Assign each wizard step a unique Semantics container with a live region announcement on mount. Use ExcludeSemantics on inactive steps during transition animations. Test each step transition manually with TalkBack and VoiceOver as part of the definition of done for each step component.

Contingency: If animated transitions cause accessibility tree corruption, disable step transition animations entirely in accessibility mode (detected via MediaQuery.accessibleNavigation) and use instant step replacement instead.

medium impact medium prob dependency

The NotesStep relies on the OS keyboard's built-in dictation button for speech-to-text input. This button's availability, position, and behaviour varies significantly between iOS (reliable, visible dictation key) and Android (varies by keyboard, OEM skin, and language settings). HLF and Blindeforbundet specifically requested this capability; if it is unreliable on Android, it fails a SHOULD HAVE requirement for a significant portion of users.

Mitigation & Contingency

Mitigation: Document that the notes dictation feature depends on the device's native keyboard dictation and requires no in-app microphone permission. Add explicit placeholder copy informing users they can use their keyboard's dictation button. Test on a minimum of three Android OEM keyboards (Gboard, Samsung, Swiftkey) and two iOS versions.

Contingency: If native keyboard dictation is too unreliable on Android, implement a fallback in-app microphone button in the NotesStep that triggers the platform's SpeechRecognition API directly via a method channel, scoped only to the notes field with no session recording capability.