high priority medium complexity testing pending testing specialist Tier 5

Acceptance Criteria

Test file exists at test/widgets/expense_type_picker_widget_test.dart
Test group 'rendering' verifies all four expense type cards are present in the widget tree by their label text
Test group 'interaction' verifies that tapping an unselected, enabled card emits the correct ExpenseTypeSelected event to the BLoC
Test group 'interaction' verifies that tapping a disabled card does not emit any BLoC event
Test group 'semantics' verifies selected card has Semantics with selected: true
Test group 'semantics' verifies unselected card has Semantics with selected: false
Test group 'semantics' verifies disabled card has Semantics with enabled: false
Golden test 'golden_picker_default.png' captures all four cards in default (nothing selected) state
Golden test 'golden_picker_disabled.png' captures at least one disabled card state
All tests pass with flutter test --update-goldens false (goldens pre-committed)
Test coverage for ExpenseTypePickerWidget reaches 100% line coverage

Technical Requirements

frameworks
Flutter
flutter_test
BLoC
data models
ExpenseType (enum or class with id, label, isDisabled)
ExpenseTypeSelected (BLoC event)
ExpenseSelectionState
performance requirements
Full test suite for this file completes in under 10 seconds
ui components
MockExpenseSelectionBLoC (using bloc_test or manual mock)
ExpenseTypePickerWidget under test

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Structure the test file with describe-style group() blocks: 'rendering', 'interaction — enabled cards', 'interaction — disabled cards', 'semantics', 'golden snapshots'. For golden tests, run on a fixed screen size (e.g., 390x844 iPhone 14 viewport) using tester.binding.setSurfaceSize() to ensure reproducibility across machines and CI. Use bloc_test's MockBloc to verify that whenListen emits the correct stream state and that add() is called with the right event. For disabled card tests, wrap the IgnorePointer or AbsorbPointer assertion by checking that no event was added to the BLoC mock after tapping.

Goldens should be committed alongside the test file and regenerated only intentionally.

Testing Requirements

100% widget test coverage using flutter_test. Use blocTest from the bloc_test package for BLoC interaction verification. Use tester.tap() + tester.pump() for interaction tests. Use tester.ensureSemantics() and tester.getSemantics(find.byType(...)) for accessibility assertions.

Use matchesGoldenFile() for golden snapshot tests. Mock the BLoC using MockBloc from bloc_test or a manual StreamController-based fake. Do not rely on a real BLoC or Supabase calls in any of these tests.

Component
Expense Type Picker Widget
ui medium
Epic Risks (2)
medium impact medium prob technical

If the expense calculation preview subscribes to the full BLoC state stream, every unrelated state property change (e.g. a loading flag toggle) triggers a widget rebuild. With complex card animations for the disabled-state transition, this could cause frame drops on low-end Android devices used by some peer mentors.

Mitigation & Contingency

Mitigation: Use select() on the Riverpod provider to subscribe only to the specific state slice each widget needs; write a performance test asserting rebuild count on a rapid sequence of toggle events.

Contingency: If jank is detected in device testing, replace animated disabled-state transitions with instant opacity changes and defer animation polish to a follow-up sprint.

medium impact low prob integration

The disabled card state requires a specific contrast-safe colour combination that communicates unavailability without relying solely on colour (WCAG 1.4.1). If the current design token palette does not include a disabled-state token with sufficient contrast for text on the disabled background, the widget will either fail WCAG AA or require a last-minute design token addition that could break other components.

Mitigation & Contingency

Mitigation: Audit the existing design token manifest for disabled-state tokens at the start of the epic; if missing, raise with the design lead and add a contrast-validated token before widget implementation begins.

Contingency: If no design review is available, use the established --color-text-disabled and --color-surface-disabled tokens with an added strikethrough or lock icon to satisfy WCAG 1.4.1 non-colour requirement, and document the deviation for design review.