Integration test FCM sender with token lifecycle
epic-certificate-expiry-notifications-data-foundation-task-013 — Write integration tests for FcmPushNotificationSender covering: token registration and persistence, token refresh behavior, single message delivery with mock FCM endpoint, batch delivery, delivery tracking persistence, and retry logic on simulated FCM transient failures. Verify that logout correctly clears the stored token from Supabase. Use a test Firebase project or FCM emulator where available.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Use Dart's http package with an injectable HttpClient so the FCM endpoint URL can be swapped for a mock server in tests. The Supabase client should point to a dedicated test project (configure via environment variables or a test-specific initialization block). For the retry logic tests, use fake_async from the test package to advance time without real delays — this keeps tests fast and deterministic. When testing logout clearance, ensure the test first inserts a row into fcm_tokens, calls clearToken, then queries Supabase directly to assert the row no longer exists.
For batch delivery, assert both FCM call count (via mock) and Supabase delivery_attempts row count. If a Firebase emulator is not available in CI, mock the FCM HTTP v1 endpoint using nock or a lightweight Dart HTTP interceptor. Document in the test file which environment variables are required to run the suite.
Testing Requirements
Integration tests only (no unit mocks of the sender itself — the sender IS the subject under test). Use a real Supabase test project for database assertions; use an HTTP mock client or Firebase local emulator for FCM endpoint simulation. Cover the full happy path, transient retry path, permanent failure path, and logout clearance path. Assert database state after each scenario using direct Supabase queries.
Tests must be deterministic and isolated: each test case seeds its own token data and cleans up afterward using a tearDown hook. Target 100% branch coverage of FcmPushNotificationSender public methods. Include at least one test that validates the retry back-off interval does not exceed the configured maximum delay.
The RLS policy predicate that checks certification_expiry_date and suppression_status on every coordinator list query could cause full table scans at scale, degrading response time for coordinator contact list screens across all chapters.
Mitigation & Contingency
Mitigation: Add a partial index on (certification_expiry_date, suppression_status) filtered to active mentors. Benchmark the policy predicate against a representative data set (500+ mentors) during development using EXPLAIN ANALYZE on Supabase staging.
Contingency: If the index does not resolve the performance issue, introduce a computed boolean column is_publicly_visible that is updated by the mentor_visibility_suppressor service and indexed separately, shifting the predicate cost to write time rather than read time.
FCM device tokens become invalid when users reinstall the app or switch devices. If the token management strategy does not handle token refresh reliably, notification delivery will silently fail for a significant portion of the user base without surfacing errors.
Mitigation & Contingency
Mitigation: Implement the FCM token refresh callback in the Flutter client to upsert the latest token to Supabase on every app launch. Store token with a last_refreshed_at timestamp. The FCM sender should handle UNREGISTERED error codes by deleting stale tokens.
Contingency: If token staleness becomes widespread, add a token health check that forces re-registration during the expiry check edge function run by querying mentors whose token was last refreshed more than 30 days ago and triggering a silent push to prompt re-registration.
The certification expiry and notification record tables may have column naming or constraint conflicts with existing tables in the peer mentor status and certification management features, causing migration failures in shared Supabase environments.
Mitigation & Contingency
Mitigation: Audit existing table schemas for user_roles, certifications, and notification tables before writing migrations. Prefix new columns with expiry_ to avoid collisions. Run migrations against a clean Supabase branch environment before merging.
Contingency: If a conflict is found post-merge, apply ALTER TABLE migrations to rename conflicting columns and issue a hotfix migration. Communicate schema changes to all dependent feature teams via a shared migration changelog.