Write widget tests for all three UI components
epic-bufdir-report-preview-ui-components-task-011 — Write flutter_test widget tests covering: BufdirFieldRowWidget rendering in all three validation states with correct icon and tooltip semantics; BufdirReportSectionWidget expand/collapse behavior and heading semantics; BufdirValidationSummaryBanner auto-hide when issue count is zero, filter toggle behavior, and live-region announcement triggers. Use golden tests for visual regression on validation state colors to enforce WCAG token compliance.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 6 - 158 tasks
Can start after Tier 5 completes
Implementation Notes
Organize test files mirroring source structure: test/features/bufdir/widgets/bufdir_field_row_widget_test.dart, bufdir_report_section_widget_test.dart, bufdir_validation_summary_banner_test.dart. Use a shared test_helpers.dart file for common fixtures: buildTestApp() wrapper with ProviderScope + MaterialApp + Directionality, sampleValidationSummaryData() factory, sampleSectionData() factory. For golden tests, set window.physicalSize and window.devicePixelRatio explicitly before pumping to ensure consistent output. Place golden files in test/goldens/bufdir/ and commit them.
For SemanticsService announcement testing, subclass SemanticsService and inject via a Riverpod override or use Flutter's test binding's SemanticsBinding. Document any known TalkBack/VoiceOver behavior differences in a test README.
Testing Requirements
This task IS the testing task. Structure: (1) Unit tests for model classes (task-006 models) — pure Dart, no widget tree; (2) Widget tests for each component in isolation using pumpWidget + ProviderScope with overrides; (3) Golden tests using matchesGoldenFile — run flutter test --update-goldens once to generate baselines, then CI runs without --update-goldens flag; (4) Semantics tests using tester.getSemantics() to assert label and heading level; (5) Interaction tests using tester.tap() and tester.pump() for expand/collapse and filter toggles; (6) Announce tests using a fake SemanticsService injected via Riverpod override. Target: 100% branch coverage on all three widget classes.
Implementing the tap-to-scroll-and-focus behavior from the validation banner to a specific field row in a long scrollable list is complex in Flutter. If focus management is incorrectly implemented, VoiceOver users who navigate to the banner and select an issue will not be moved to the relevant field row, breaking the accessibility workflow and violating WCAG 2.4.3 (Focus Order).
Mitigation & Contingency
Mitigation: Use BufdirAccessibilityUtils focus management utilities (built in the foundation epic) with explicit GlobalKey-based scroll anchors on each field row. Test with a real iOS device running VoiceOver during widget development, not only in the Flutter accessibility inspector.
Contingency: If programmatic scroll-to-focus cannot be reliably achieved before the TestFlight deadline, fall back to a navigation approach where tapping a banner issue opens a modal detail sheet for that field row rather than scrolling in place, and file a follow-up ticket for the inline scroll implementation.
The validation summary banner must reactively update its issue count as underlying aggregated data changes (e.g., if the coordinator has navigated away and data was refreshed). If the banner's Riverpod provider is not correctly scoped, it may display stale issue counts or fail to disappear when all issues are resolved, eroding coordinator trust in the validation system.
Mitigation & Contingency
Mitigation: Drive the banner exclusively from the same Riverpod provider that powers the full preview model — do not maintain a separate local state for issue counts. Write a widget test that simulates a data refresh mid-review and asserts the banner updates within one frame.
Contingency: If stale state reaches production, add a manual refresh button to the banner as a short-term workaround while the provider scoping is corrected in the next release cycle.