- setDeletedAt update nu ook updatedAt (bug 2) - getAllMeasurements filtert deletedAt IS NULL, nieuwe getAllMeasurementsForSync voor sync - mergeMeasurements detecteert server deleted:true → deletedAt (bug 1) - syncAll: pull-push split met remoteUpdatedMap, geen double-push (bug 3) - hard delete alleen na API-succes (bug 4) - DashboardScreen: refreshCache() na syncAll zodat UI niet op Laden blijft hangen - deleteMeasurement() dead code verwijderd (bug 5) - tests: 3 nieuwe testcases voor deleted → deletedAt mapping, 15/15 pass
76 lines
3.1 KiB
TypeScript
76 lines
3.1 KiB
TypeScript
import { mergeMeasurements } from '../src/sync/syncService'
|
|
import { Measurement } from '../src/types'
|
|
|
|
jest.mock('expo-sqlite', () => ({ openDatabaseAsync: jest.fn() }))
|
|
|
|
const make = (overrides: Partial<Measurement> = {}): Measurement => ({
|
|
id: 'id-1', weight: 75, bmi: 22, bodyFatPercentage: 15, fatMass: 10,
|
|
musclePercentage: 40, muscleMass: 30, visceralFat: 8, bmr: 1600,
|
|
measuredAt: '2024-06-01T08:00:00.000Z', createdAt: '2024-06-01T08:00:00.000Z',
|
|
updatedAt: '2024-06-01T08:00:00.000Z', ...overrides,
|
|
})
|
|
|
|
describe('mergeMeasurements', () => {
|
|
it('both empty returns empty', () => {
|
|
expect(mergeMeasurements([], [])).toEqual([])
|
|
})
|
|
|
|
it('local only kept', () => {
|
|
const r = mergeMeasurements([make()], [])
|
|
expect(r).toHaveLength(1)
|
|
})
|
|
|
|
it('remote only kept', () => {
|
|
const r = mergeMeasurements([], [make({ id: 'r1' })])
|
|
expect(r).toHaveLength(1)
|
|
expect(r[0].id).toBe('r1')
|
|
})
|
|
|
|
it('last-writer-wins: remote newer', () => {
|
|
const local = make({ weight: 75, updatedAt: '2024-06-02T08:00:00.000Z' })
|
|
const remote = make({ weight: 76, updatedAt: '2024-06-03T08:00:00.000Z' })
|
|
const r = mergeMeasurements([local], [remote])
|
|
expect(r[0].weight).toBe(76)
|
|
})
|
|
|
|
it('last-writer-wins: local newer', () => {
|
|
const local = make({ weight: 77, updatedAt: '2024-06-04T08:00:00.000Z' })
|
|
const remote = make({ weight: 76, updatedAt: '2024-06-03T08:00:00.000Z' })
|
|
const r = mergeMeasurements([local], [remote])
|
|
expect(r[0].weight).toBe(77)
|
|
})
|
|
|
|
it('remote deleted wins over older local', () => {
|
|
const local = make({ updatedAt: '2024-06-01T08:00:00.000Z' })
|
|
const remote = make({ updatedAt: '2024-06-03T08:00:00.000Z', deletedAt: '2024-06-03T08:00:00.000Z' })
|
|
const r = mergeMeasurements([local], [remote])
|
|
expect(r[0].deletedAt).toBe('2024-06-03T08:00:00.000Z')
|
|
})
|
|
|
|
it('local wins over older remote deleted', () => {
|
|
const local = make({ updatedAt: '2024-06-03T08:00:00.000Z' })
|
|
const remote = make({ updatedAt: '2024-06-01T08:00:00.000Z', deletedAt: '2024-06-01T08:00:00.000Z' })
|
|
const r = mergeMeasurements([local], [remote])
|
|
expect(r[0].deletedAt).toBeUndefined()
|
|
})
|
|
|
|
it('server deleted flag mapped to deletedAt when remote wins', () => {
|
|
const local = make({ updatedAt: '2024-06-01T08:00:00.000Z' })
|
|
const remote: any = { ...make({ updatedAt: '2024-06-03T08:00:00.000Z' }), deleted: true }
|
|
const r = mergeMeasurements([local], [remote])
|
|
expect(r[0].deletedAt).toBe('2024-06-03T08:00:00.000Z')
|
|
})
|
|
|
|
it('server deleted flag ignored when local wins', () => {
|
|
const local = make({ updatedAt: '2024-06-05T08:00:00.000Z' })
|
|
const remote: any = { ...make({ updatedAt: '2024-06-03T08:00:00.000Z' }), deleted: true }
|
|
const r = mergeMeasurements([local], [remote])
|
|
expect(r[0].deletedAt).toBeUndefined()
|
|
})
|
|
|
|
it('server deleted flag works with no local record', () => {
|
|
const remote: any = { ...make({ id: 'r1', updatedAt: '2024-06-03T08:00:00.000Z' }), deleted: true }
|
|
const r = mergeMeasurements([], [remote])
|
|
expect(r[0].deletedAt).toBe('2024-06-03T08:00:00.000Z')
|
|
})
|
|
})
|