high priority medium complexity testing pending testing specialist Tier 8

Acceptance Criteria

Test: first navigation to ActivityTypeSelectionScreen triggers exactly one Supabase network call (verified via mock call count)
Test: navigating away and returning to ActivityTypeSelectionScreen within cache TTL triggers zero additional Supabase network calls — data is served from ActivityTypeCacheProvider
Test: calling a service mutation (create/update/deactivate) invalidates the cache so the next screen load triggers a fresh Supabase network call
Test: after cache invalidation, the screen displays the updated list reflecting the mutation result
Test: selecting an ActivityType with triggersReimbursementWorkflow=true causes the registration wizard orchestrator to show the reimbursement step
Test: selecting an ActivityType with isTravelExpenseEligible=false causes the registration wizard orchestrator to hide the travel expense section
Test: the ActivityType metadata is passed intact through the navigation stack without data loss
The real ActivityTypeCacheProvider is used (not mocked) so cache eviction logic is exercised
The Supabase client is mocked at the HTTP/RPC layer to control response data and count network calls
Tests are deterministic and do not depend on timing or real clock values

Technical Requirements

frameworks
Flutter
Riverpod
flutter_test
mocktail
apis
Supabase REST API (mocked)
data models
ActivityType
ActivityTypeCacheProvider
RegistrationWizardState
performance requirements
Integration tests must complete within 30 seconds total
Cache hit path must resolve in under 50ms (no async gap to Supabase)
security requirements
Mocked Supabase client must only return org-scoped data matching the test user's orgId
ui components
ActivityTypeSelectionScreen
RegistrationWizardOrchestrator or equivalent parent widget
Reimbursement step widget (asserted visible/hidden)

Execution Context

Execution Tier
Tier 8

Tier 8 - 48 tasks

Can start after Tier 7 completes

Implementation Notes

Mock the Supabase client at the SupabaseClient constructor level by overriding the supabaseClientProvider in ProviderScope. Return pre-built List> from the mocked from() query chain. To count network calls without real HTTP, track invocations on the mock's from() method. For the cache-hit test, boot the provider graph, trigger one fetch, then recreate only the widget subtree (not the ProviderScope) so the cache state is preserved.

For mutation-then-refetch, call the service mutation on the ProviderContainer, then rebuild the selection screen widget and verify the mock was called a second time. For wizard propagation, wrap ActivityTypeSelectionScreen inside a minimal RegistrationWizardOrchestrator stub that reads the selected ActivityType from shared Riverpod state and conditionally renders downstream steps.

Testing Requirements

Flutter integration tests using flutter_test with testWidgets(). Use a real ProviderContainer or ProviderScope booting the full production provider graph, overriding only the Supabase client with a mocktail Mock. Count Supabase mock invocations using verify().called(n). For wizard propagation tests, navigate the full wizard flow using tester.tap() and tester.pumpAndSettle().

Assert presence/absence of downstream wizard widgets using find.byType(). Tests must be runnable with flutter test — no dependency on a running device or emulator beyond what flutter_test provides.

Epic Risks (2)
medium impact medium prob scope

Metadata flag combination rules differ between organisations (e.g., Blindeforbundet honorarium thresholds, HLF mutual exclusion of km and transit). Encoding these as generic service-level validation may be insufficient, forcing organisation-specific branching inside the service that becomes unmaintainable as new organisations are onboarded.

Mitigation & Contingency

Mitigation: Model flag validation as a pure function that accepts an ActivityTypeMetadata object and an org configuration record, making org-specific rules data-driven rather than hardcoded. Establish the validation contract in the foundation epic so the service just delegates to the validator.

Contingency: Defer complex cross-flag validation to a lightweight edge function that can be updated without a mobile app release, accepting that initial validation in the mobile service layer is permissive and corrected server-side.

high impact low prob technical

Blindeforbundet users rely on VoiceOver and JAWS. If the selection screen is built with non-semantic widgets that fail accessibility audit late in the sprint, a significant rework of the widget tree may be required, blocking the registration wizard integration.

Mitigation & Contingency

Mitigation: Build the selection screen against the project's established accessibility design tokens and semantics wrapper conventions from the start. Run Flutter's semantic tree inspector and a manual VoiceOver pass before marking any widget task complete.

Contingency: Wrap all tappable items in the project's SemanticsWrapperWidget and schedule a dedicated accessibility review session with a screen reader user from Blindeforbundet before the epic is closed.