critical priority medium complexity testing pending testing specialist Tier 7

Acceptance Criteria

All text elements across the five screens pass 4.5:1 contrast ratio (WCAG 1.4.3) verified against the design token color system
All non-text UI elements (icons, input borders, button outlines) pass 3:1 contrast ratio (WCAG 1.4.11)
Every interactive element has a minimum touch target of 44x44 dp (WCAG 2.5.8) — verified via Flutter widget size assertions
Focus order on each screen follows a logical reading order (top-to-bottom, left-to-right) verified by traversing the Semantics tree
Every interactive element has a Semantics label that describes purpose, not appearance (WCAG 4.1.2)
Error messages are programmatically associated with the relevant form field or action and announced via live region (WCAG 1.3.1, 4.1.3)
Status messages (loading, success) are announced without requiring focus move (WCAG 4.1.3)
No content relies solely on color to convey information — icons, labels, or patterns accompany color indicators (WCAG 1.4.1)
All identified issues are remediated in source code before sign-off
A per-screen sign-off checklist document is produced as a markdown file listing each criterion, its pass/fail status, and the remediation applied (if any), ready for partner organization review

Technical Requirements

frameworks
Flutter
Flutter Semantics API
design token system
apis
Flutter SemanticsDebugger widget (for visual audit)
tester.getSemantics() in flutter_test
Color contrast checker (manual or automated)
performance requirements
Audit tooling (SemanticsDebugger overlays, widget size assertions) must not ship in release builds — guard with kDebugMode or remove after audit
security requirements
Audit documentation must not include screenshots containing real user data — use test fixture data only
Sign-off checklist files must be stored in the repository (docs/accessibility/) not in external tools, to maintain audit trail
ui components
SemanticsDebugger overlay — temporary debug wrapper for visual tree inspection
AccessibilityAuditReport — markdown checklist template per screen

Execution Context

Execution Tier
Tier 7

Tier 7 - 84 tasks

Can start after Tier 6 completes

Implementation Notes

Approach this as two parallel workstreams: (1) automated checks that can run in CI, and (2) a manual audit checklist. For automated contrast checks, build a small test utility: contrastRatioOf(AppColors.textPrimary, AppColors.backgroundSurface) >= 4.5 — this is deterministic because you control the design tokens. For touch target sizes, wrap all AppButton instances in a SizedBox(width: 44, height: 44) minimum — many Flutter themes already do this via MaterialTapTargetSize.padded but verify explicitly. Focus order is harder to automate — use SemanticsDebugger at runtime to visually inspect and then codify in widget tests by walking the semantics tree.

For the sign-off checklist, use the WCAG 2.2 quick reference as the template structure: 1.1.1, 1.3.1, 1.4.1, 1.4.3, 1.4.11, 2.1.1, 2.4.3, 2.5.8, 4.1.2, 4.1.3. Pay extra attention to the Personnummer widget since it contains sensitive data UI patterns that NHF specifically flagged as requiring screen reader warnings (from workshop summary: 'Varsling ved opplesning av sensitive felt'). The GDPR disclosure scroll gate must not trap keyboard/switch-access users — ensure the 'Read disclosure' toggle button is reachable without scrolling.

Testing Requirements

Automated: add flutter_test widget tests that assert minimum Size(44, 44) on all tappable widgets using tester.getSize(find.byType(AppButton)). Automated: assert design token color pairs against a minimum contrast ratio lookup table — implement a contrastRatio(Color fg, Color bg) utility in test helpers and assert >= 4.5 for all text-on-background pairs used in auth screens. Manual: enable SemanticsDebugger wrapper on each screen and record findings. Manual: test with VoiceOver (iOS) and TalkBack (Android) on physical devices or simulators, traversing all interactive elements and verifying announcements.

Produce docs/accessibility/auth-screens-wcag-audit.md with pass/fail per criterion per screen. All automated tests must pass in CI as part of the standard test suite.

Epic Risks (3)
high impact medium prob technical

BankID on mobile uses a WebView or external app redirect that has known compatibility issues with Flutter's WebView package on certain Android versions. BankID's JavaScript-heavy broker pages may also trigger CSP or mixed-content errors in a Flutter WebView, preventing the authentication flow from completing.

Mitigation & Contingency

Mitigation: Use the flutter_inappwebview package (more mature than webview_flutter for complex OAuth pages) and validate BankID WebView rendering on the broker's test environment before integrating with the service layer. Prefer external browser redirect where the broker supports it.

Contingency: If WebView approach fails for certain BankID brokers, implement the full external browser redirect + deep link callback pattern as the primary flow and treat WebView as a fallback only.

medium impact medium prob technical

The OAuth redirect flows (both Vipps and BankID) temporarily move the user outside the Flutter app into an external browser or the Vipps/BankID app. Screen reader users may lose focus context during this transition and become disoriented when the app callback returns them to the loading state, failing the WCAG 2.2 AA mandate.

Mitigation & Contingency

Mitigation: Implement explicit accessibility announcements (live region announcements) at each transition point: when launching the external flow ('Opening Vipps'), during the loading wait state ('Waiting for Vipps confirmation'), and on return ('Login successful' or 'Login failed — please try again'). Test with VoiceOver on iOS and TalkBack on Android during development.

Contingency: If OAuth transition accessibility is unresolvable on a specific platform, add an explicit accessibility user guide in the onboarding flow explaining the external app redirect behavior to set user expectations.

low impact high prob technical

Biometric UI varies significantly across devices — Face ID (iPhone), fingerprint sensor (most Android), front-facing camera biometrics (some Android), and devices with no biometrics at all. Flutter's local_auth handles the OS dialog but the surrounding UI must gracefully handle all these cases, and testing coverage for all permutations is difficult.

Mitigation & Contingency

Mitigation: Use local_auth's getAvailableBiometrics() to detect the exact biometric type and render appropriate iconography (Face ID icon vs. fingerprint icon). For devices with no biometrics, skip the biometric screen entirely and route directly to full re-authentication.

Contingency: If a specific device configuration produces unexpected local_auth behavior in production, implement a user-accessible toggle in Settings to disable biometric login entirely, routing those users to the standard BankID/Vipps flow without biometrics.