Integration Test for Cron End-to-End Flow
epic-certification-management-automation-task-010 — Write an integration test that seeds the database with certifications in each expiry window, triggers the CertificationExpiryCron function manually, and asserts that the correct service calls were made and idempotency records were written. Verify that re-running the cron on the same date produces no duplicate actions. Run against a local Supabase instance using the Supabase CLI.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
Use the Supabase JS client with the local URL (`http://localhost:54321`) and service_role key from environment variable `SUPABASE_SERVICE_ROLE_KEY` loaded from `.env.test`. Trigger the Edge Function via `fetch('http://localhost:54321/functions/v1/certification-expiry-cron', { method: 'POST', headers: { Authorization: 'Bearer ${serviceKey}' } })` — no Supabase client wrapper for the invocation, raw HTTP is clearer for integration tests. For seeding, insert directly into the `certifications` table using the admin client, setting `expiry_date` to `new Date(Date.now() - 86400000).toISOString()` for an expired record. Assert DB state with a `select` query after each cron invocation rather than inspecting logs — logs are observable side effects, DB state is the source of truth.
For the idempotency assertion, count rows in `certification_idempotency_log` where `certification_id IN (test IDs)` before and after the second run and assert the counts are equal. Keep the test script self-contained with no external test framework dependencies beyond Deno's built-in `assert` module to minimise setup friction.
Testing Requirements
This task is an integration test, not a unit test. It requires a running local Supabase instance (`supabase start`). The test runner is Deno (`deno test --allow-net --allow-env`). Structure: (1) `beforeAll`: run migrations, seed test data via Supabase admin client.
(2) Test case A: invoke cron, assert DB state post-run. (3) Test case B: invoke cron again (idempotency), assert no changes. (4) Test case C: manually insert a missed-pause scenario (set expiry_date in past, no idempotency record, status='active'), invoke cron, assert audit log captures the miss. (5) `afterAll`: delete all rows with the test UUIDs.
Add this test to the CI pipeline in a separate job that starts Supabase CLI as a service container. Document the local setup steps in a `tests/integration/README.md` so any developer can run it independently.
Supabase Edge Functions can have cold-start latency that causes the nightly cron to time out when processing large cohorts of expiring certifications, resulting in partial reminder dispatches.
Mitigation & Contingency
Mitigation: Batch the cron processing in chunks of 50 mentors per iteration. Use pagination with a cursor to resume processing if the function is re-invoked. Keep total invocation time well under the Edge Function timeout limit.
Contingency: If timeouts occur in production, split the cron into two separate functions: one for reminders and one for auto-pauses, each with its own schedule offset to reduce peak load.
Certification BLoC covers three distinct workflows (view, renew, enrol) which may lead to an overly complex state machine that is hard to test and maintain, particularly when error states from multiple concurrent operations need to be differentiated in the UI.
Mitigation & Contingency
Mitigation: Use separate sealed state classes per workflow (CertificationViewState, RenewalState, EnrolmentState) composed into a single BLoC state wrapper. Follow the existing BLoC patterns established in the codebase for consistency.
Contingency: If the BLoC grows too complex, split into two BLoCs: CertificationBLoC (view/load) and CertificationActionBLoC (mutations), connected via a shared stream.