Integration test: full foundation stack wiring
epic-screen-reader-support-foundation-task-012 — Write integration tests verifying that all five foundation components are correctly wired via Riverpod: SensitiveFieldConfigurationRegistry is accessible, AccessibilitySettingsRepository streams settings, SemanticsServiceFacade is injectable, ScreenReaderDetectionService streams state, and SemanticsWrapperWidget reads from both settings and detection service correctly in a mounted widget tree.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
The key challenge in this integration test is isolating Flutter's WidgetsBinding while still testing real provider wiring. Use TestWidgetsFlutterBinding (automatically set by flutter_test) and create a FakeAccessibilityFeatures helper that allows toggling screen reader state in tests. For Supabase, inject a FakeSupabaseClient that returns empty streams and no-op operations. For ScreenReaderDetectionService, the service should be wired through its Riverpod provider so the test verifies the actual provider graph, not just the service in isolation.
The integration test should be the single authoritative test confirming 'all five components work together correctly', forming a regression baseline for future epics that build on this foundation.
Testing Requirements
Use flutter_test with testWidgets() for widget-mounted integration tests. Create a TestApp widget that wraps content in ProviderScope with the real provider graph (no overrides except WidgetsBinding and Supabase). Use a ProviderObserver to detect any unhandled provider errors during the test. For stream assertions, use tester.pump() to advance the frame and then read the provider's current value using ProviderContainer.read().
For wiring verification, use ProviderContainer.listen() to subscribe to each provider's stream and assert at least one emission. For the SemanticsWrapperWidget wiring test, use tester.ensureSemantics() and assert semantics node presence/absence based on screen reader state changes. Organise tests as individual testWidgets() blocks, one per foundation component, plus one end-to-end wiring test.
Flutter's SemanticsService behaves differently between iOS (VoiceOver) and Android (TalkBack) in edge cases — e.g., announcement queuing, focus-gain timing, and attribute support. If the facade does not correctly abstract these differences, announcements may be silent or misfired on one platform, causing regression on the other platform to go unnoticed until device testing.
Mitigation & Contingency
Mitigation: Write platform-divergence unit tests early using SemanticsServiceFacade mocks. Validate announcement delivery on a physical iPhone (VoiceOver) and Android device (TalkBack) at the end of each sprint. Document known platform differences in the facade's inline API comments.
Contingency: If a platform difference cannot be abstracted cleanly, expose a platform-specific override path in the facade and implement targeted workarounds per platform, accepting the added complexity in exchange for correct behaviour.
Accessibility preferences stored in local storage may need new fields as higher-tier epics are implemented (e.g., announcement verbosity, sensitive-field guard toggle). Schema changes to an already-persisted store risk data migration failures or silent defaults on existing installs, breaking user preferences.
Mitigation & Contingency
Mitigation: Design the AccessibilitySettingsRepository with a versioned JSON schema from the start, using merge-with-defaults on read so new fields fall back gracefully. Define the full expected field list upfront based on all downstream epic requirements before writing the first record.
Contingency: If migration fails on a live install, fall back to full reset-to-defaults with a one-time in-app notification informing the user that accessibility preferences have been reset and inviting them to reconfigure.