Write unit tests for Realtime subscription service
epic-in-app-notification-centre-foundation-task-011 — Write unit tests for SupabaseRealtimeSubscriptionService using a mock Supabase Realtime channel. Cover: subscription opens on instantiation with correct user_id filter, INSERT events are mapped to Notification objects and emitted on the stream, reconnection logic triggers when auth state changes, dispose() cancels the subscription without errors, and connectionStatus stream emits correct states for connected/disconnected/error scenarios.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
The key design challenge is making the service testable: inject the Supabase Realtime channel factory and the auth state stream via constructor parameters rather than creating them internally. This enables full mock substitution in tests. For stream assertions, prefer `expectLater(service.notifications, emits(isA
... : stream.isClosed)` or by attempting to listen and catching the closed stream error. The malformed payload test is important for resilience — the service should catch JSON parse errors per-event and log them rather than crashing the stream.
Testing Requirements
Unit tests using flutter_test with fake/mock Supabase Realtime channel and a fake auth state stream. Place tests in `test/features/notifications/data/supabase_realtime_subscription_service_test.dart`. Use `StreamController` fakes to simulate channel events and auth state changes — this avoids async timing issues. Test groups: (1) subscription lifecycle (open on init, correct filter), (2) event mapping (valid INSERT, malformed INSERT), (3) auth state reactivity (re-auth, sign-out), (4) dispose correctness, (5) connectionStatus stream states.
Use `expect(stream, emitsInOrder([...]))` or `expectLater` for async stream assertions. Verify dispose with a `verify(mockChannel.unsubscribe()).called(1)` assertion.
Supabase Realtime channels on mobile networks can drop silently. If reconnection logic is flawed, users miss notifications without knowing it, undermining the audit-trail guarantee.
Mitigation & Contingency
Mitigation: Implement exponential-backoff reconnection with a maximum of 5 retries; expose a channel-status stream to the BLoC so it can trigger a full-fetch fallback when the channel reconnects after a gap.
Contingency: If Realtime reliability proves insufficient in production, fall back to polling the repository every 60 seconds as a background supplement to the Realtime channel.
Coordinator and org-admin RLS expansions require joining user_roles and org_memberships tables. An incorrect policy could expose notifications to wrong users or block legitimate access entirely.
Mitigation & Contingency
Mitigation: Write dedicated RLS integration tests for each role (peer mentor, coordinator, org admin) using separate Supabase test projects. Review policies with the security checklist before merging.
Contingency: If an RLS defect is discovered post-deployment, disable the expanded-scope policy and revert to user-scoped-only access while a corrected migration is prepared and tested.
JSONB payload structure may vary across notification types created by different Edge Functions (reminder, expiry, scenario, pause). Missing or renamed fields will cause runtime parse failures.
Mitigation & Contingency
Mitigation: Define a canonical NotificationPayload union type in a shared schema document. Each Edge Function must validate its payload against this schema before inserting. Add fallback parsing with default values in the domain model.
Contingency: Wrap all payload parsing in try/catch and log malformed payloads to a monitoring channel; render a generic notification item rather than crashing when the payload cannot be parsed.