Something went wrong. Try again.
A local-first note taking app
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172import * as Automerge from '@automerge/automerge';import { describe, expect, it } from 'vitest';
import { readDocContent, spliceText, updateTextContent } from './text-diff';
type Doc = { content: string };
describe('updateTextContent', () => { it('merges concurrent character-level edits without clobbering', () => { const base = Automerge.from<Doc>({ content: 'hello world' });
// Two actors fork from the same base and edit different regions. let a = Automerge.clone(base, { actor: 'aaaaaaaaaaaaaaaa' }); let b = Automerge.clone(base, { actor: 'bbbbbbbbbbbbbbbb' });
a = Automerge.change(a, (d) => updateTextContent(d, ['content'], 'HELLO world'), ); b = Automerge.change(b, (d) => updateTextContent(d, ['content'], 'hello WORLD'), );
const merged = Automerge.merge(a, b);
// Character-level splices merge: both edits survive (a wholesale write // would have kept only one side). expect(readDocContent(merged.content)).toBe('HELLO WORLD'); });
it('replaces content for a single editor', () => { let doc = Automerge.from<Doc>({ content: 'v1' }); doc = Automerge.change(doc, (d) => updateTextContent(d, ['content'], 'v2 longer text'), ); expect(readDocContent(doc.content)).toBe('v2 longer text'); });
it('assigns into an empty field', () => { let doc = Automerge.from<Doc>({ content: '' }); doc = Automerge.change(doc, (d) => updateTextContent(d, ['content'], 'fresh'), ); expect(readDocContent(doc.content)).toBe('fresh'); });});
describe('spliceText', () => { it('applies minimal character-level edits', () => { let doc = Automerge.from<Doc>({ content: 'the quick brown fox' }); doc = Automerge.change(doc, (d) => spliceText(d, ['content'], 'the quick brown fox', 'the slow brown fox'), ); expect(readDocContent(doc.content)).toBe('the slow brown fox'); });});
describe('readDocContent', () => { it('returns plain strings as-is', () => { expect(readDocContent('hello')).toBe('hello'); });
it('passes through binary content', () => { const bytes = new Uint8Array([1, 2, 3]); expect(readDocContent(bytes)).toBe(bytes); });
it('returns null for null/undefined', () => { expect(readDocContent(null)).toBeNull(); expect(readDocContent(undefined)).toBeNull(); });});