critical priority high complexity testing pending testing specialist Tier 5

Acceptance Criteria

Scenario 1 — Activity registration announcement order: simulated screen reader session records exactly three announcements in order: (a) loading state message, (b) success confirmation message, (c) no error announcement on success path; on the error path: (a) loading, (b) error message with actionable instruction
Scenario 1 — No announcements are dropped or duplicated when the loading→success transition happens within 300ms
Scenario 2 — Sensitive field dialog trigger: navigating to the sensitive contact field and activating it causes SensitiveFieldWarningDialog to appear with correct field label before the value is revealed
Scenario 2 — Confirm path focus: after confirming the dialog, keyboard focus returns to the sensitive field widget (verified via FocusManagementService focus trace captured by harness)
Scenario 2 — Cancel path focus: after cancelling the dialog, focus returns to the field widget without revealing the value
Both scenarios pass when run headlessly in CI via flutter test integration_test/
AccessibilityTestHarness.getAnnouncementLog() returns a typed list that tests can assert against without string parsing
Both test scenarios are documented with inline comments linking them to the Blindeforbundet pilot requirements in likeperson.md

Technical Requirements

frameworks
flutter_test
integration_test
AccessibilityTestHarness (internal)
mocktail
apis
AccessibilityTestHarness.simulateScreenReaderSession()
AccessibilityTestHarness.getAnnouncementLog()
LiveRegionAnnouncer
FocusManagementService
SensitiveFieldWarningDialog
Supabase (mocked for activity submission)
data models
ActivityRegistration
SensitiveFieldConfig
AnnouncementLogEntry
performance requirements
Each integration test scenario completes within 60 seconds in CI
Supabase calls must be intercepted and mocked — no real network calls in CI
security requirements
All contact data used in scenario 2 must be synthetic — no real personal information
Supabase mock must not log request payloads to console in CI output
ui components
ActivityWizard
SensitiveFieldWarningDialog
ContactDetailScreen

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

The two pilot scenarios map directly to the Blindeforbundet requirements in the source documentation: screen reader support is listed as particularly critical for Blindeforbundet and the activity registration flow is the #1 priority across all organisations. Structure the integration test file so each scenario can run independently (no shared mutable state between tests). For scenario 1, create a mock Supabase activity repository that returns a delayed Future (200ms) then a success result; repeat with an error result for the error path branch. For scenario 2, use a real widget tree fragment (ContactDetailScreen or equivalent) rather than a stub, to catch real focus management edge cases.

Document the harness interaction model with a short comment block at the top of the file explaining how AccessibilityTestHarness wraps the standard widget tree and intercepts semantics calls.

Testing Requirements

Integration tests under integration_test/ using flutter_test's IntegrationTestWidgetsFlutterBinding. Mock Supabase at the repository layer using mocktail so scenario 1 can simulate loading, success, and error responses deterministically. Use AccessibilityTestHarness to capture the announcement log and focus trace. Assert announcement content, order, and count using typed matchers (avoid fragile substring matching).

Each scenario should be a separate test() with a descriptive name that matches the Blindeforbundet pilot use case. Run the suite in CI on both iOS simulator and Android emulator targets. Target zero flaky tests — if timing is involved, use FakeAsync or explicit pump sequences.

Component
Accessibility Test Harness
infrastructure medium
Dependencies (4)
Use the AccessibilityTestHarness to write comprehensive unit and widget tests for FocusManagementService. Cover: focus lands on correct element after route push, focus restores after route pop, focus moves to dialog on open, focus restores to trigger on dialog close, and moveFocusTo handles unmounted targets gracefully. Achieve ≥90% branch coverage on the service. epic-screen-reader-support-core-services-task-012 Write flutter_test widget tests using AccessibilityTestHarness for AccessibilityAuditService. Create test widget trees with known violations (unlabelled button, missing role, small touch target) and assert the audit report contains the expected violation entries. Also test clean trees produce zero violations. Verify report structure fields are correctly populated. epic-screen-reader-support-core-services-task-013 Write flutter_test widget tests for LiveRegionAnnouncer covering: polite announcements queue in order, assertive announcements interrupt the queue, rapid announcements do not drop messages, and state observer mixin correctly maps BLoC states to announcements. Mock SemanticsService.announce() to capture calls and verify message content and priority. epic-screen-reader-support-core-services-task-014 Write flutter_test widget tests for SensitiveFieldWarningDialog covering: dialog renders with correct field type label and privacy warning text, Confirm action reveals field and restores focus, Cancel action hides field and restores focus, per-session confirmation suppresses re-prompting for the same field, and FocusManagementService integration correctly receives the trigger GlobalKey. epic-screen-reader-support-core-services-task-015
Epic Risks (3)
high impact high prob technical

Flutter's build pipeline and SemanticsService.announce() operate asynchronously. Announcements triggered too early (before the semantic tree settles) may be swallowed silently on both platforms, causing acceptance criteria around the 500ms window to fail intermittently in CI and on device, which would block pilot launch.

Mitigation & Contingency

Mitigation: Implement the LiveRegionAnnouncer with a post-frame callback delay and an internal timing guard. Write integration tests using WidgetTester.pump() sequences that verify announcement delivery across multiple frame boundaries. Validate on physical devices at each sprint boundary, not only in CI.

Contingency: If consistent announcement timing cannot be achieved within Flutter's semantic pipeline, switch to a platform channel approach that calls native UIAccessibility.post (iOS) and AccessibilityManager.announce (Android) directly, bypassing Flutter's intermediary.

high impact medium prob technical

Flutter does not natively emit a focus-gain event to Dart code when VoiceOver or TalkBack moves focus to a specific widget. If the intercept mechanism for the SensitiveFieldWarningDialog relies on an unsupported or undocumented hook in the semantics tree, it may miss focus events for some field types or in some navigation contexts, leaving sensitive data unprotected.

Mitigation & Contingency

Mitigation: Prototype the focus-intercept mechanism during the first sprint of this epic, before building the dialog UI. Evaluate Flutter's SemanticsBinding.instance callbacks and custom SemanticsActions as intercept points. Document the chosen mechanism with platform compatibility notes.

Contingency: If no reliable focus-intercept is available, implement an alternative where sensitive fields show a static 'Screen reader active — tap to reveal' overlay instead of an OS dialog, which is less seamless but achieves equivalent privacy protection without relying on an unreliable event hook.

medium impact low prob dependency

The AccessibilityTestHarness depends on internal flutter_test semantic tree APIs that can change between Flutter minor versions. If the project upgrades Flutter during this epic, the harness may break silently, causing CI accessibility tests to pass while actually skipping assertions.

Mitigation & Contingency

Mitigation: Pin the Flutter SDK version in pubspec.yaml for the duration of this epic. Document which flutter_test APIs are used and their stability tier. Add a canary test that explicitly fails if the semantic tree API surface changes.

Contingency: If a forced Flutter upgrade breaks the harness, prioritise patching the harness as a blocking task before any other epic work continues, using the canary test failure as the trigger.