/** * RED scaffold — pushCoalescer (Plan 05-03 turns this GREEN). * * Asserts that coalesceListPush: * - Fires the dispatch function exactly ONCE when N calls arrive within the coalesce window * - Passes the correct count (N) to the dispatch function * - Passes the actor's own userId as excludeUserId to suppress self-notifications (D-03) * * These tests fail now because pushCoalescer.ts does not yet exist. * Run: pnpm --filter @familysync/api exec vitest run tests/lib/pushCoalescer.test.ts */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' describe('pushCoalescer — list-change burst coalescing (D-01)', () => { beforeEach(() => { vi.useFakeTimers() vi.resetModules() }) afterEach(() => { vi.useRealTimers() }) it('collapses N rapid coalesceListPush calls into a single dispatch with count=N', async () => { const dispatch = vi.fn().mockResolvedValue(undefined) const { coalesceListPush } = await import('../../src/lib/pushCoalescer.js') const listId = 1 const actorId = 10 const N = 5 for (let i = 0; i < N; i++) { coalesceListPush(listId, actorId, dispatch) } // Advance time past the coalesce window await vi.runAllTimersAsync() expect(dispatch).toHaveBeenCalledTimes(1) const [calledListId, calledActorId, calledCount] = dispatch.mock.calls[0] expect(calledListId).toBe(listId) expect(calledCount).toBe(N) }) it('passes the actor userId as excludeUserId so the actor does not notify themselves (D-03)', async () => { const dispatch = vi.fn().mockResolvedValue(undefined) const { coalesceListPush } = await import('../../src/lib/pushCoalescer.js') const listId = 2 const actorId = 99 coalesceListPush(listId, actorId, dispatch) await vi.runAllTimersAsync() expect(dispatch).toHaveBeenCalledTimes(1) const [, calledActorId] = dispatch.mock.calls[0] expect(calledActorId).toBe(actorId) }) it('fires separate dispatches for different lists independently', async () => { const dispatch = vi.fn().mockResolvedValue(undefined) const { coalesceListPush } = await import('../../src/lib/pushCoalescer.js') coalesceListPush(1, 10, dispatch) coalesceListPush(1, 10, dispatch) coalesceListPush(2, 10, dispatch) // different list coalesceListPush(2, 10, dispatch) await vi.runAllTimersAsync() // Two separate dispatches — one per distinct listId expect(dispatch).toHaveBeenCalledTimes(2) }) })