Widget tests for Notification Card and Detail Sheet
epic-scenario-based-follow-up-prompts-scheduler-and-ui-task-017 — Write Flutter widget tests for ScenarioPromptNotificationCard and ScenarioPromptDetailBottomSheet: verify card renders scenario title and CTA, deep link fires on tap, detail sheet opens from card, wellbeing flags render as chips, dismiss action calls repository, and loading/error states display correctly. Use flutter_test with pump and settle.
Acceptance Criteria
Technical Requirements
Execution Context
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.
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.
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.