high priority low complexity testing pending testing specialist Tier 5

Acceptance Criteria

Manual QA performed on a real Android device (or emulator with TalkBack) confirming: live region announcement fires automatically on screen entry without user interaction
Manual QA on Android confirming: the page heading is announced with heading role (TalkBack says 'Heading' before the heading text)
Manual QA on Android confirming: portal link is reachable by swiping right through the accessibility focus order and its label is descriptive (not just 'link' or the raw URL)
Manual QA on Android confirming: logout button is reachable after the portal link in logical focus order and is announced as 'button'
Manual QA performed on a real iOS device (or Simulator with VoiceOver) confirming the same four criteria above for VoiceOver
A QA checklist markdown file is added at docs/qa/no-access-screen-a11y.md documenting each check, pass/fail status, and any fixes applied
Golden file test added at test/goldens/no_access_screen_1x.png (textScaleFactor 1.0, light theme)
Golden file test added at test/goldens/no_access_screen_2x.png (textScaleFactor 2.0, light theme)
Golden file tests pass (or baseline images are committed) and running flutter test with --update-goldens regenerates them deterministically
Any accessibility issues discovered during manual QA are fixed before the task is marked complete — do not close the task with open known issues

Technical Requirements

frameworks
Flutter
flutter_test
performance requirements
Golden file generation completes within 10 seconds per image on the CI host
ui components
matchesGoldenFile matcher from flutter_test
TalkBack (Android accessibility service)
VoiceOver (iOS accessibility service)
MediaQuery textScaler override for golden rendering

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

For golden file tests, pin the test to a fixed device size using tester.binding.setSurfaceSize(Size(390, 844)) and reset after the test to avoid contaminating other tests. Use a fixed ThemeData with no system font substitution to ensure deterministic rendering across machines — apply fontFamily: 'Roboto' or a custom test font via FontLoader. TalkBack QA: enable TalkBack in Android Settings > Accessibility, navigate to the no-access screen, and swipe right to move through focus. Use a single-finger double-tap to activate interactive elements.

VoiceOver QA: enable VoiceOver in iOS Settings > Accessibility, use swipe right to navigate and double-tap to activate. The logical focus order should be: (1) live region announcement, (2) page heading, (3) logo (if labelled), (4) denial message body, (5) portal link, (6) logout button. If any element is announced out of order, adjust the Semantics sortKey or widget order in the tree. Document every finding — even passing checks — in the QA markdown file so it serves as a living accessibility specification for this screen.

Testing Requirements

Golden file tests are added to the existing test file or a new test/goldens/no_access_screen_golden_test.dart. Use testWidgets with pumpWidget wrapping the widget in MaterialApp with a fixed screen size (e.g., Size(390, 844) for iPhone 14) and a fixed textScaler. Call await expectLater(find.byType(NoAccessScreenWidget), matchesGoldenFile('goldens/no_access_screen_1x.png')). Repeat for 2.0 scale.

Golden images must be committed to the repository. CI must run flutter test without --update-goldens and fail if rendered output diverges from baseline. Manual QA checklist is considered a deliverable alongside code changes.

Component
No-Access Screen
ui low
Epic Risks (2)
medium impact medium prob technical

Flutter's live region (SemanticsProperties.liveRegion) announcement may be delayed or swallowed by the OS accessibility engine if the Semantics tree is not fully built when the screen mounts, causing screen-reader users to miss the denial announcement.

Mitigation & Contingency

Mitigation: Trigger the live region announcement from a post-frame callback (WidgetsBinding.addPostFrameCallback) to ensure the Semantics tree is committed before the announcement fires. Test on both VoiceOver (iOS) and TalkBack (Android) physical devices.

Contingency: If live region timing is unreliable, fall back to using SemanticsService.announce() directly in the initState post-frame callback, which provides more deterministic announcement timing.

low impact low prob scope

The organisation logo may fail to load (network error, missing asset) leaving a broken image in an otherwise functional screen, degrading the professional appearance and potentially confusing users.

Mitigation & Contingency

Mitigation: Wrap the logo widget in an error builder that renders a styled fallback (organisation name text or a generic icon) when the logo asset or network image fails to load.

Contingency: If logo loading is persistently unreliable across organisations, remove the logo from the no-access screen entirely in favour of a text-only header using the organisation's display name from the design token system.