high priority medium complexity testing pending testing specialist Tier 10

Acceptance Criteria

Card renders scenario title text: find.text(scenarioTitle) resolves to exactly one widget
CTA button is present and tappable: find.byKey(Key('scenario-cta')) resolves and tap triggers deep link callback with correct route string
Tapping the card (outside CTA) opens ScenarioPromptDetailBottomSheet: find.byType(ScenarioPromptDetailBottomSheet) appears after tap + pumpAndSettle
Detail sheet displays all wellbeing flags as chip widgets: for each flag in test data, find.text(flagLabel) resolves inside the sheet
Dismiss action calls the mock repository's dismissPrompt method exactly once with the correct promptId
Loading state: when BLoC/Riverpod state is loading, a CircularProgressIndicator is shown and no card content is visible
Error state: when state is error, an error message widget is shown and no card content is visible
Accessibility: tester.ensureSemantics() passes with no violations for both the card and the open sheet
No real Supabase or network calls are made during any widget test

Technical Requirements

frameworks
Flutter
flutter_test
mockito
BLoC or Riverpod (match implementation)
data models
ScenarioPrompt
WellbeingFlag
PromptDismissAction
performance requirements
Each widget test must complete within 5 seconds including pumpAndSettle
No real timers — wrap time-sensitive tests in fake_async if needed
security requirements
Test fixtures must not contain real user data
ui components
ScenarioPromptNotificationCard
ScenarioPromptDetailBottomSheet
WellbeingFlagChip
AppButton

Execution Context

Execution Tier
Tier 10

Tier 10 - 11 tasks

Can start after Tier 9 completes

Implementation Notes

Create a test helper function buildTestCard({required ScenarioPrompt prompt, MockPromptRepository? repo}) that wraps the card in the minimal widget tree needed (MaterialApp, ProviderScope or BlocProvider). This reduces boilerplate across tests. For BLoC-based state: use MockBloc from bloc_test package and whenListen to emit loading/error/loaded states in sequence.

For Riverpod: use ProviderScope with overrides. When testing the deep link CTA, pass a captured callback (String capturedRoute) and assert capturedRoute == '/activity-wizard?promptId=xxx'. For the dismiss test, verify the repository mock was called — do not assert UI changes as the primary signal. Use ValueKey widgets on interactive elements (CTA button, dismiss button) to make finders robust against label changes.

Test the accessibility-enhanced version from tasks 014 and 015 — run tester.ensureSemantics() as the first assertion in each test group.

Testing Requirements

Flutter widget tests using flutter_test. Wrap widget under test in MaterialApp (or the app's AppWrapper test helper) to provide Router, Theme, and localization. Inject state via a mock BLoC/provider — do not use real Supabase. Use tester.pumpWidget, tester.tap, and tester.pumpAndSettle for interaction.

For deep link assertion, capture the callback argument with an ArgumentCaptor or local variable. For the bottom sheet open test, assert using find.byType after tap + settle. Group tests: one group for NotificationCard, one for DetailSheet, one for integration between them. Run with flutter test test/widgets/scenario_prompt_test.dart.

Coverage target: >= 85% for both widget files.

Component
Scenario Prompt Notification Card
ui medium
Epic Risks (2)
high impact medium prob technical

If the scheduler runs concurrently (e.g., two overlapping cron invocations due to edge function retry), duplicate prompts could be dispatched before the first run's history records are committed, breaking the deduplication guarantee.

Mitigation & Contingency

Mitigation: Use a Postgres advisory lock or unique constraint on (user_id, scenario_id, activity_ref) in the prompt history table to make concurrent writes idempotent; design the scheduler to check history inside a transaction.

Contingency: If concurrency issues persist in production, add a distributed lock via Supabase Edge Function concurrency limit (max_instances=1) for the evaluation function as a hard guard.

medium impact medium prob scope

Coordinators may find scenario configuration unclear if trigger conditions are expressed as raw JSON or technical terminology, leading to misconfiguration and irrelevant prompts being sent to peer mentors.

Mitigation & Contingency

Mitigation: Design the ScenarioConfigurationScreen to display human-readable descriptions of each template's trigger condition (e.g., 'Send 3 days after first contact if wellbeing concern was flagged') rather than raw rule properties; validate with an HLF coordinator in a design review before implementation.

Contingency: If coordinators still misconfigure rules after launch, add a preview mode that shows a simulated prompt based on a test activity before the rule is enabled.