high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

Tests verify that a static label is correctly assigned to the semantics node (SemanticsNode.label)
Tests verify each SemanticRole enum value maps to the correct SemanticsFlags in the semantics node
Tests verify SemanticState fields (enabled, checked, selected, expanded, readOnly) map to corresponding SemanticsFlags
Tests verify that excludeSemantics: true results in no semantics node for the child (verified via SemanticsController)
Tests verify that labelBuilder callback overrides static label and receives a valid BuildContext
Tests verify that liveRegion: true sets the liveRegion property on the semantics node
Tests verify widget renders correct semantics when screen reader is active (mocked via Riverpod override)
Tests verify widget skips semantics wrapping when screen reader is inactive (direct child return)
Tests verify interaction with AccessibilitySettingsRepository for simplified label preference
All tests use ProviderScope with provider overrides for deterministic mock injection
Test coverage for SemanticsWrapperWidget is at or above 90%
All tests pass in CI with flutter test --reporter=compact

Technical Requirements

frameworks
Flutter
flutter_test
Riverpod
apis
SemanticsController (tester.semantics)
tester.ensureSemantics()
SemanticsNode
ProviderScope
ProviderContainer
data models
SemanticRole
SemanticState
AccessibilitySettings
ScreenReaderState
performance requirements
Full widget test suite completes within 10 seconds
No golden file tests required for semantics; use semantics tree assertions only
security requirements
Test data must not include real user PII; use placeholder strings only
ui components
SemanticsWrapperWidget
Test stub widgets for child rendering

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

When asserting that no semantics node exists (excludeSemantics case), use expect(tester.getSemantics(find.byType(YourChild)), isNull) or assert the semantics node has no label/actions. Be aware that SemanticsController.dispose() must be called after each test to avoid state leakage between tests. For role mapping, create a parametrised test using for-loop or test.each pattern to reduce boilerplate. For Riverpod overrides, define reusable mock provider factories at the top of the test file.

If mocktail is used, define mocks for AccessibilitySettingsRepository and ScreenReaderDetectionService once and reuse across test groups.

Testing Requirements

All tests are widget tests using testWidgets(). Enable semantics tree with final semantics = tester.ensureSemantics() at the start of each test, and call semantics.dispose() in tearDown. Use tester.getSemantics(find.byType(SemanticsWrapperWidget)) or tester.getSemantics(find.byWidget(child)) to get the SemanticsNode. Assert on SemanticsNode.label, SemanticsNode.hint, SemanticsNode.hasFlag(SemanticsFlag.isButton), etc.

For Riverpod injection, wrap the widget under test in ProviderScope(overrides: [...]) in each testWidgets call. Organise tests in groups: 'static label and hint', 'role mapping', 'state flags', 'decorative exclusion', 'dynamic label builder', 'live region', 'screen reader inactive short-circuit', 'accessibility settings integration'.

Component
Semantics Wrapper Widget
ui medium
Epic Risks (2)
high impact medium prob technical

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.

medium impact medium prob scope

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.