critical priority medium complexity testing pending testing specialist Tier 2

Acceptance Criteria

A test with NHF label map asserts that WcagSemanticsLabelResolver for the 'peer_role_label' key produces a SemanticsNode with label 'koordinator'
A test with Blindeforbundet label map asserts the same key produces label 'kontaktperson'
A test with HLF label map asserts the same key produces label 'likeperson'
A test confirms that switching from NHF to HLF label map causes the SemanticsNode label to change from 'koordinator' to 'likeperson' in the next frame
A test with a missing hintKey asserts that the SemanticsNode has no hint property (not empty string) — an empty string hint would cause VoiceOver/TalkBack to announce an awkward pause
A test with a provided hintKey that resolves asserts the correct hint string appears in the SemanticsNode
Tests use `flutter_test` semantics APIs (`tester.getSemantics`, `SemanticsController`) — not manual inspection of widget trees
All tests pass with `flutter test --dart-define=FLUTTER_TEST=true` in CI without a physical device
A test asserts that child widget semantics (e.g., a button's tap action) remain accessible and are not suppressed by the wrapper
Test file is organized with `group('WcagSemanticsLabelResolver WCAG 2.2 AA')` blocks per organization scenario

Technical Requirements

frameworks
Flutter
Riverpod
flutter_test
data models
OrganizationLabelMap
SemanticsNode
OrganizationId
performance requirements
Full test suite for this file must complete in under 10 seconds — use `tester.pump()` not `tester.pumpAndSettle()` to avoid artificial delays
security requirements
Test data (label maps) must use realistic but non-sensitive values — no real user data, personal names, or addresses in test fixtures
ui components
WcagSemanticsLabelResolver (under test)
ProviderScope with overrides (test harness)
GestureDetector or ElevatedButton (child widget for action semantics tests)

Execution Context

Execution Tier
Tier 2

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.

Component
WCAG Semantics Label Resolver
infrastructure low
Epic Risks (3)
high impact medium prob integration

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.

medium impact medium prob technical

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.

medium impact low prob security

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.