Validate WCAG 2.2 AA compliance for screen readers
epic-dynamic-terminology-and-labels-ui-and-accessibility-task-007 — Write automated accessibility tests using flutter_test semantics testing APIs to verify that WcagSemanticsLabelResolver produces correct Semantics nodes. Test with organization-specific label maps for NHF ('koordinator'), Blindeforbundet ('kontaktperson'), and HLF ('likeperson') scenarios. Validate that VoiceOver and TalkBack will announce the organization-specific terminology rather than hardcoded strings. Include tests for missing hint keys (must not produce empty semantics).
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Flutter's semantics testing requires calling `tester.ensureSemantics()` before querying the semantics tree — add this in `setUp` or at the start of each test. Use `tester.getSemantics(find.byType(WcagSemanticsLabelResolver))` to get the SemanticsNode for the resolver widget specifically. The `SemanticsNode.label` property corresponds to what VoiceOver/TalkBack will announce as the primary label. The `SemanticsNode.hint` property corresponds to the secondary hint announcement.
To verify hint is absent (not empty string): assert `semanticsNode.hint == null || semanticsNode.hint!.isEmpty == false` — specifically test that an empty string is NOT present, since Flutter may represent 'no hint' differently in different versions. Create a shared test fixture file `test/fixtures/organization_label_maps.dart` with the NHF, Blindeforbundet, and HLF label maps so they can be reused across test files. WCAG 2.2 AA Success Criterion 1.1.1 (Non-text Content) requires that all non-text UI elements have a text alternative — these tests directly verify that requirement for org-specific UI elements. For VoiceOver/TalkBack manual verification checklist: include a comment in the test file listing the manual steps for QA testers to follow on physical devices during the TestFlight release.
Testing Requirements
All tests are widget tests using flutter_test. Required test groups: (1) Organization-specific label rendering — NHF, Blindeforbundet, HLF label map fixtures, assert correct SemanticsNode labels via `tester.getSemantics()`. (2) Reactive label updates — switch org provider, pump, assert updated SemanticsNode. (3) Missing hint key — assert SemanticsNode.hint is null or absent, never empty string.
(4) Present hint key — assert SemanticsNode.hint equals resolved string. (5) Child semantics preservation — wrap a GestureDetector with WcagSemanticsLabelResolver, assert both the wrapper's label and the child's tap action are present in the semantics tree. Use `TestSemantics` matchers where applicable. Enable semantics in tests with `final semantics = tester.ensureSemantics()` and dispose with `semantics.dispose()` in tearDown.
WcagSemanticsLabelResolver's Semantics wrappers may conflict with Semantics nodes already defined by existing accessible widgets (e.g., accessible-bottom-navigation, activity-wizard-semantics), causing duplicate or contradictory screen reader announcements that fail WCAG 2.2 AA criteria.
Mitigation & Contingency
Mitigation: Audit all existing Semantics-annotated widgets in the accessibility feature before implementing WcagSemanticsLabelResolver. Define a clear hierarchy rule: WcagSemanticsLabelResolver always merges with, never replaces, existing Semantics nodes. Use Flutter's debugSemantics output in CI to detect conflicts automatically.
Contingency: If conflicts are discovered in testing, introduce a resolverMode parameter to WcagSemanticsLabelResolver allowing it to operate in 'override' or 'merge' mode per call site; coordinate with the Screen Reader Support feature team to align Semantics strategies.
If TerminologyAwareTextWidget subscribes to the full terminology map provider rather than the per-key labelProvider family, a single label update will trigger a full widget-tree rebuild across all screens simultaneously, causing jank on devices used by older peer mentors.
Mitigation & Contingency
Mitigation: Implement TerminologyAwareTextWidget using ref.watch(labelProvider(key)) on the per-key family provider from TerminologyRiverpodProviders so that only widgets bound to the changed key rebuild. Verify with Flutter DevTools 'rebuild tracking' in widget tests.
Contingency: If full-map subscriptions slip through code review, add a Riverpod lint rule that flags direct organizationLabelsNotifierProvider subscriptions inside widget build methods and enforces the per-key family pattern.
The TerminologyAdminPreviewScreen requires coordinator-level access, but if role checks rely solely on client-side guard logic without matching Supabase RLS policies, a peer mentor could potentially access the admin preview by manipulating navigation state.
Mitigation & Contingency
Mitigation: Protect the admin preview route with a server-validated role guard that re-fetches the user's role from Supabase on screen initialization, not just from local state. Add a Supabase RLS policy that restricts label map read access for the admin preview endpoint to coordinator and admin roles only.
Contingency: If unauthorized access is discovered in testing, immediately add a middleware role assertion that redirects non-coordinators to the no-access screen and logs the unauthorized navigation attempt for audit.