high priority medium complexity testing pending testing specialist Tier 5

Acceptance Criteria

Widget test: notification-preferences-screen renders toggle initial state from mocked repository; toggling calls repository update method with correct arguments
Widget test: notification-preferences-screen loading state shows indicator; error state shows error message
Widget test: in-app-notification-banner is visible on appearance and dismisses automatically after the configured timer duration (use fake async)
Widget test: tapping in-app-notification-banner invokes the navigation callback with the correct notification ID
Widget test: in-app-notification-banner emits a SemanticsService.announce call or has a liveRegion semantics node when it appears
Widget test: scenario-notification-detail-view renders all contextual data fields correctly for a mocked full-data notification record
Widget test: scenario-notification-detail-view calls markAsRead exactly once on mount
Widget test: scenario-notification-detail-view CTA button tap invokes scenario-deep-link-router with correct ScenarioType and payload
Integration test: a Supabase Realtime INSERT event on the notifications channel causes in-app-notification-banner to appear within 3 seconds in the running app
Integration test: tapping the banner navigates to scenario-notification-detail-view and the detail view resolves the correct route via scenario-deep-link-router
All widget tests run in under 30 seconds total; integration tests run cleanly on a physical device or emulator in CI
Test coverage for the three components is at or above 80% line coverage as reported by flutter test --coverage

Technical Requirements

frameworks
Flutter
flutter_test
Riverpod (ProviderScope overrides)
fake_async
apis
Supabase Realtime channel (notifications table INSERT events) — integration test only
scenario-notification-repository (579) — mocked in widget tests
scenario-deep-link-router (578) — mocked in widget tests
data models
ScenarioNotification
ScenarioType
ScenarioPayload
NotificationPreference
performance requirements
Widget test suite must complete in under 30 seconds
Integration tests must not have hardcoded sleep() calls; use pumpAndSettle or explicit event-driven await patterns
security requirements
Integration test Supabase connection must use a dedicated test project or a row-level-security-isolated test schema; never run integration tests against the production database

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Organise test files mirroring the source structure: test/features/notifications/widget/ and test/features/notifications/integration/. For the Supabase Realtime integration test, insert a row into the test notifications table programmatically (via the Supabase admin client in test setup) and listen for the Flutter UI reaction rather than simulating the WebSocket event directly — this tests the real integration path. Use FakeAsync for the auto-dismiss timer test to avoid slow real-time waits in the widget test suite. When mocking Riverpod providers, use ProviderScope(overrides: [...]) rather than injecting mocks into constructors — this is the idiomatic Riverpod testing pattern.

Ensure each test file has a clear tearDown/tearDownAll that disposes ProviderContainers and closes Supabase subscriptions to prevent test pollution. Add a Makefile or script target run_notification_tests for CI convenience.

Testing Requirements

Widget tests: use ProviderScope with overrides to inject mock implementations of all Riverpod providers. Use fake_async / fakeAsync from flutter_test for timer-based tests (auto-dismiss). Use tester.getSemantics() to verify semantic announcements. Use mocktail or mockito for repository and router mocks.

Integration tests: configure a test Supabase project with a seeded notification record. Use flutter_driver or integration_test package. Test the full path: Supabase Realtime event → banner appears → tap → detail screen → deep-link resolved. Capture and assert final route name in the router to confirm correct navigation.

Run integration tests in CI against TestFlight build configuration where feasible.

Component
In-App Notification Banner
ui low
Epic Risks (2)
medium impact medium prob technical

The in-app notification banner depends on a Supabase Realtime subscription to detect new notification records. If the subscription reconnects slowly after an app resume from background, or if Realtime delivery is delayed under high load, the banner may not appear within the 2-second acceptance criterion.

Mitigation & Contingency

Mitigation: Implement an explicit subscription reconnect handler on app foreground events using Flutter's AppLifecycleState.resumed hook, and add a polling fallback that queries for unread notifications once per app foreground event as a safety net against missed Realtime events.

Contingency: If Realtime proves unreliable in production, promote the polling fallback to the primary mechanism with a 30-second interval, accepting slight latency in exchange for reliability.

medium impact medium prob technical

Cold-start deep linking (app not running when push notification is tapped) requires deferred navigation after the Flutter engine and Supabase session are fully initialised. If the deep link is consumed before authentication completes, the router may navigate to a protected route without a valid session, causing an error or redirect loop.

Mitigation & Contingency

Mitigation: Implement a deferred navigation queue in scenario-deep-link-router that holds the parsed deep-link target until the auth session restoration lifecycle event fires, following the existing deep-link-handler pattern used in the BankID and Vipps authentication flows.

Contingency: If deferred navigation is not achievable within the epic's scope, fall back to navigating the user to the notification centre (which is always accessible post-login) where the relevant notification record is visible and tappable.