import { HighlightSyncManager } from '@/lib/highlight-sync-manager' import { addHighlight, getAllHighlights, clearAllHighlights } from '@/lib/highlight-manager' import { resolveConflict, mergeHighlights } from '@/lib/sync-conflict-resolver' import { BibleHighlight } from '@/types' describe('E2E: Highlights Sync Flow', () => { let manager: HighlightSyncManager beforeEach(async () => { manager = new HighlightSyncManager() // Clear database before each test await clearAllHighlights() }) it('should complete full sync workflow', async () => { // 1. User creates highlight locally const highlight: BibleHighlight = { id: 'h-1', verseId: 'v-1', color: 'yellow', createdAt: Date.now(), updatedAt: Date.now(), syncStatus: 'pending' } await addHighlight(highlight) // 2. Queue it for sync await manager.init() await manager.queueHighlight(highlight) // 3. Check pending items const pending = await manager.getPendingSyncItems() expect(pending.length).toBe(1) expect(pending[0].color).toBe('yellow') // 4. Mark as syncing await manager.markSyncing(['h-1']) const syncing = await manager.getSyncingItems() expect(syncing.length).toBe(1) // 5. Simulate server response and mark synced await manager.markSynced(['h-1']) const allHighlights = await getAllHighlights() const synced = allHighlights.find(h => h.id === 'h-1') expect(synced?.syncStatus).toBe('synced') }) it('should handle conflict resolution', () => { const clientVersion: BibleHighlight = { id: 'h-1', verseId: 'v-1', color: 'blue', createdAt: 1000, updatedAt: 3000, syncStatus: 'pending' } const serverVersion: BibleHighlight = { id: 'h-1', verseId: 'v-1', color: 'yellow', createdAt: 1000, updatedAt: 2000, syncStatus: 'synced' } // Client version is newer, should win const resolved = resolveConflict(clientVersion, serverVersion) expect(resolved.color).toBe('blue') expect(resolved.syncStatus).toBe('synced') }) it('should handle sync errors gracefully', async () => { const highlight: BibleHighlight = { id: 'h-1', verseId: 'v-1', color: 'yellow', createdAt: Date.now(), updatedAt: Date.now(), syncStatus: 'pending' } await addHighlight(highlight) await manager.init() await manager.queueHighlight(highlight) // Mark as error await manager.markError(['h-1'], 'Network timeout') const syncing = await manager.getSyncingItems() expect(syncing.length).toBe(0) // Not syncing anymore const all = await getAllHighlights() const errored = all.find(h => h.id === 'h-1') expect(errored?.syncStatus).toBe('error') expect(errored?.syncErrorMsg).toBe('Network timeout') }) it('should merge highlights with conflict resolution', () => { const clientHighlights: BibleHighlight[] = [ { id: 'h-1', verseId: 'v-1', color: 'yellow', createdAt: 1000, updatedAt: 2000, syncStatus: 'pending' }, { id: 'h-2', verseId: 'v-2', color: 'blue', createdAt: 1000, updatedAt: Date.now(), syncStatus: 'pending' } ] const serverHighlights: BibleHighlight[] = [ { id: 'h-1', verseId: 'v-1', color: 'orange', createdAt: 1000, updatedAt: 3000, // Server is newer syncStatus: 'synced' }, { id: 'h-3', verseId: 'v-3', color: 'pink', createdAt: 1000, updatedAt: 1500, syncStatus: 'synced' } ] const merged = mergeHighlights(clientHighlights, serverHighlights) // Should have 3 highlights expect(merged.length).toBe(3) // h-1: Server won (newer timestamp) const h1 = merged.find(h => h.id === 'h-1') expect(h1?.color).toBe('orange') expect(h1?.syncStatus).toBe('synced') // h-2: Client only, kept as is const h2 = merged.find(h => h.id === 'h-2') expect(h2?.color).toBe('blue') expect(h2?.syncStatus).toBe('pending') // h-3: Server only, added const h3 = merged.find(h => h.id === 'h-3') expect(h3?.color).toBe('pink') expect(h3?.syncStatus).toBe('synced') }) })