medium priority low complexity testing pending testing specialist Tier 1

Acceptance Criteria

Test suite contains at least 8 distinct widget tests
EmailPassword phase test verifies exactly 3 Text widgets with labels 'Organization', 'Credentials', 'Verify' are present
BankID phase test verifies labels 'Organization', 'BankID', 'Complete' are present
Vipps phase test verifies labels 'Organization', 'Vipps', 'Complete' are present
Dot state test: when currentStep=2, dot at index 1 (0-based) has active color, dot at index 0 has completed color, dot at index 2 has inactive color — verified via widget tree color inspection
Animation test: pump with currentStep=1, setState to currentStep=2, pumpAndSettle(), assert transition completed without exception
Semantic label test: verify Semantics node label equals 'Step 2 of 3: Credentials' when currentStep=2 and phase=emailPassword
Contrast test: extract active dot color and background color from design tokens, assert WCAG contrast ratio >= 3:1
All tests pass with zero failures and zero errors

Technical Requirements

frameworks
Flutter
flutter_test
data models
AuthPhase
performance requirements
Full test suite completes in under 15 seconds
ui components
OnboardingProgressIndicator

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Coordinate with the widget implementation (task-012) to ensure dots are assigned ValueKeys (e.g., Key('step-dot-$index')) to make them findable in tests. If the implementation uses AnimatedContainer, color inspection requires finding the Container widget inside it. Consider using a test-only parameter or a TestableOnboardingProgressIndicator wrapper if internal widget state is inaccessible. Keep test file at test/widgets/onboarding_progress_indicator_test.dart.

Import shared test helpers from test/helpers/contrast_utils.dart.

Testing Requirements

Widget tests only. Use WidgetTester.pump and pumpAndSettle for animation verification. Use tester.widget(find.byKey(Key('step-dot-1'))) pattern to inspect dot colors — requires the widget implementation to assign ValueKeys to dots. Use SemanticsHandle for semantic label inspection.

For contrast ratio assertion, reuse the contrastRatio() helper from task-011 tests if it exists in a shared test utility file.

Epic Risks (3)
high impact medium prob technical

iOS Keychain and Android Keystore have meaningfully different failure modes and permission models. The secure storage plugin may throw platform-specific exceptions (e.g., biometric enrollment required, Keystore wipe after device re-enrolment) that crash higher-level flows if not caught at the adapter boundary.

Mitigation & Contingency

Mitigation: Wrap all storage plugin calls in try/catch at the adapter layer and expose a typed StorageResult<T> instead of throwing. Write integration tests on real device simulators for both platforms in CI using Fastlane. Document the exception matrix during spike.

Contingency: If a platform-specific failure cannot be handled gracefully, fall back to in-memory-only storage for the current session and surface a non-blocking warning to the user; log the event for investigation.

high impact medium prob integration

Setting a session-level Postgres variable (app.current_org_id) via a Supabase RPC requires that RLS policies on every table reference this variable. If the Supabase project schema has not yet defined these policies, the configurator will set the variable but queries will return unfiltered data, giving a false sense of security.

Mitigation & Contingency

Mitigation: Include a smoke-test RPC in the SupabaseRLSTenantConfigurator that verifies the variable is readable from a policy-scoped query before marking setup as complete. Coordinate with the database migration task to ensure RLS policies reference app.current_org_id before the configurator is shipped.

Contingency: If RLS policies are not in place at integration time, gate all data-fetching components behind a runtime check in SupabaseRLSTenantConfigurator.isRlsScopeVerified(); block data access and surface a developer warning until policies are confirmed.

medium impact medium prob technical

Fetching feature flags from Supabase on every cold start adds network latency before the first branded screen renders. On slow connections this may cause a perceptible blank-screen gap or cause the app to render with default (unflagged) state before flags arrive.

Mitigation & Contingency

Mitigation: Persist the last-known flag set to disk in the FeatureFlagProvider and serve stale-while-revalidate on startup. Gate flag refresh behind a configurable TTL (default 15 minutes) so network calls are not made on every launch.

Contingency: If stale flags cause a feature to appear that should be hidden, add a post-load re-evaluation pass that reconciles the live flag set with the rendered widget tree and triggers a targeted rebuild where needed.