Files
biblical-guide.com/__tests__/e2e/highlights-sync.test.ts

160 lines
4.3 KiB
TypeScript

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')
})
})