Write widget tests for search UI accessibility
epic-contact-search-accessible-ui-task-009 — Write Flutter widget tests covering: Semantics tree correctness for AccessibleSearchInputField (label, hint, textField role), live region announcement after result load, empty state text rendering, offline banner visibility, and touch target sizes. Use flutter_test and the accessibility-test-harness component. Aim for full coverage of WCAG 2.2 AA requirements implemented in this epic.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Import 'package:flutter_test/flutter_test.dart' and enable semantics with ensureSemantics() at the top of each test. Wrap widgets in a ProviderScope (Riverpod) or BlocProvider (BLoC) depending on the state management used by the search UI components. For live region tests, use SemanticsFlag.isLiveRegion on the target semantics node. For touch target tests, retrieve the render object with tester.renderObject
Group tests logically: one group per WCAG criterion covered (e.g., group('1.3.1 Info and Relationships', ...), group('2.5.8 Target Size', ...)). Use setUp() to reduce boilerplate for common widget tree construction. Do not mock platform channels for this task — pure widget tests are sufficient.
Testing Requirements
Use flutter_test widget testing exclusively (no integration_test package for this task). Each test should call tester.pumpWidget() with the target widget wrapped in a MaterialApp and any required BLoC/Riverpod providers. Use tester.getSemantics() and the SemanticsController to assert tree structure. Use tester.tap() and tester.pump() to simulate interactions.
Assert touch target sizes by checking the RenderBox size of each interactive element via tester.getSize(). Include negative tests: assert that the live region does NOT announce when results have not yet loaded. Use expect(tester.takeException(), isNull) after each interaction to catch unexpected errors. Target 100% statement coverage of the accessibility-specific code paths.
Flutter's Semantics live region support for announcing dynamic result count changes may behave inconsistently between VoiceOver (iOS) and TalkBack (Android), particularly regarding announcement throttling and focus management, causing the feature to pass testing on one platform and fail on the other.
Mitigation & Contingency
Mitigation: Test live region announcements on both iOS (VoiceOver) and Android (TalkBack) early in development using the existing accessibility test harness. Reference the existing LiveRegionAnnouncer component (608-live-region-announcer) patterns used elsewhere in the app.
Contingency: If cross-platform consistency cannot be achieved, implement a platform-specific announcement strategy using the SemanticsService.announce API with platform-conditional announcement timing to work around OS-specific throttling behaviour.
Voice-to-text progressive enhancement for Blindeforbundet may not be available or may behave unpredictably on all device/OS combinations, particularly older Android devices, potentially causing crashes or silent failures that degrade the search experience.
Mitigation & Contingency
Mitigation: Implement voice-to-text as a strictly optional enhancement: detect availability at runtime, show the microphone button only when the platform speech API reports availability, and wrap all voice invocations in try/catch with graceful degradation to standard text input.
Contingency: If voice-to-text causes instability on a subset of devices discovered during TestFlight/beta, disable the feature flag for that platform version while a fix is investigated, without impacting the core text-based search functionality.