test: add E2E tests for highlights sync flow
This commit is contained in:
159
__tests__/e2e/highlights-sync.test.ts
Normal file
159
__tests__/e2e/highlights-sync.test.ts
Normal file
@@ -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')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user