From 180da4462d189c6ea03129efbc69447f8248079b Mon Sep 17 00:00:00 2001 From: Andrei Date: Wed, 12 Nov 2025 07:56:39 +0000 Subject: [PATCH] test: add E2E tests for highlights sync flow --- __tests__/e2e/highlights-sync.test.ts | 159 ++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 __tests__/e2e/highlights-sync.test.ts diff --git a/__tests__/e2e/highlights-sync.test.ts b/__tests__/e2e/highlights-sync.test.ts new file mode 100644 index 0000000..9267f0e --- /dev/null +++ b/__tests__/e2e/highlights-sync.test.ts @@ -0,0 +1,159 @@ +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') + }) +})