Files
crumbs/src/lib/sync/sync.test.ts
T
2026-03-05 21:16:45 +01:00

120 lines
3.5 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { mergeNotes, hasChanges, diffNotes } from './crdt.js';
import type { Note } from '../types/index.js';
function makeNote(overrides: Partial<Note> = {}): Note {
return {
id: 'test-id',
title: 'Test',
content: 'Content',
color: 'default',
pinned: false,
archived: false,
trashed: false,
trashedAt: null,
checklistMode: false,
sortOrder: 0,
createdAt: new Date('2024-01-01'),
updatedAt: new Date('2024-01-01'),
version: 1,
...overrides
};
}
describe('mergeNotes (LWW)', () => {
it('should prefer remote when remote is newer', () => {
const local = makeNote({ title: 'Local', updatedAt: new Date('2024-01-01') });
const remote = makeNote({ title: 'Remote', updatedAt: new Date('2024-01-02') });
const result = mergeNotes(local, remote);
expect(result.title).toBe('Remote');
});
it('should prefer local when local is newer', () => {
const local = makeNote({ title: 'Local', updatedAt: new Date('2024-01-02') });
const remote = makeNote({ title: 'Remote', updatedAt: new Date('2024-01-01') });
const result = mergeNotes(local, remote);
expect(result.title).toBe('Local');
});
it('should prefer higher version when timestamps are equal', () => {
const ts = new Date('2024-01-01');
const local = makeNote({ title: 'Local', updatedAt: ts, version: 1 });
const remote = makeNote({ title: 'Remote', updatedAt: ts, version: 2 });
const result = mergeNotes(local, remote);
expect(result.title).toBe('Remote');
});
it('should prefer local when timestamps and versions are equal', () => {
const ts = new Date('2024-01-01');
const local = makeNote({ title: 'Local', updatedAt: ts, version: 1 });
const remote = makeNote({ title: 'Remote', updatedAt: ts, version: 1 });
const result = mergeNotes(local, remote);
expect(result.title).toBe('Local');
});
});
describe('hasChanges', () => {
it('should detect title change', () => {
const a = makeNote({ title: 'A' });
const b = makeNote({ title: 'B' });
expect(hasChanges(a, b)).toBe(true);
});
it('should detect content change', () => {
const a = makeNote({ content: 'old' });
const b = makeNote({ content: 'new' });
expect(hasChanges(a, b)).toBe(true);
});
it('should detect color change', () => {
const a = makeNote({ color: 'default' });
const b = makeNote({ color: 'coral' });
expect(hasChanges(a, b)).toBe(true);
});
it('should detect pinned change', () => {
const a = makeNote({ pinned: false });
const b = makeNote({ pinned: true });
expect(hasChanges(a, b)).toBe(true);
});
it('should return false when notes are identical', () => {
const a = makeNote();
const b = makeNote();
expect(hasChanges(a, b)).toBe(false);
});
});
describe('diffNotes', () => {
it('should return only changed fields', () => {
const old = makeNote({ title: 'Old', content: 'Same' });
const updated = makeNote({ title: 'New', content: 'Same' });
const diff = diffNotes(old, updated);
expect(diff.title).toBe('New');
expect(diff.content).toBeUndefined();
});
it('should return empty object when no changes', () => {
const a = makeNote();
const b = makeNote();
const diff = diffNotes(a, b);
expect(Object.keys(diff)).toHaveLength(0);
});
it('should track multiple changed fields', () => {
const old = makeNote({ title: 'Old', color: 'default', pinned: false });
const updated = makeNote({ title: 'New', color: 'coral', pinned: true });
const diff = diffNotes(old, updated);
expect(diff.title).toBe('New');
expect(diff.color).toBe('coral');
expect(diff.pinned).toBe(true);
});
});