import { describe, expect, it } from 'vitest'; import { diffMarkdown } from './text-diff'; /** Concatenate the segments of one type back into a string. */ function only( segments: ReturnType, type: 'added' | 'removed' | 'equal', ): string { return segments .filter((s) => s.type === type) .map((s) => s.value) .join(''); } describe('diffMarkdown (issue #42)', () => { it('marks added and removed words against a fixture pair', () => { const before = 'The quick brown fox'; const after = 'The slow brown fox jumps'; const segments = diffMarkdown(before, after); expect(only(segments, 'removed')).toContain('quick'); expect(only(segments, 'added')).toContain('slow'); expect(only(segments, 'added')).toContain('jumps'); // Unchanged words stay in the equal channel. expect(only(segments, 'equal')).toContain('brown'); expect(only(segments, 'equal')).toContain('fox'); }); it('round-trips: equal+removed reconstructs before, equal+added reconstructs after', () => { const before = '# Title\n\nHello world, this is old.'; const after = '# Title\n\nHello brave world, this is new.'; const segments = diffMarkdown(before, after); const reconstructedBefore = segments .filter((s) => s.type !== 'added') .map((s) => s.value) .join(''); const reconstructedAfter = segments .filter((s) => s.type !== 'removed') .map((s) => s.value) .join(''); expect(reconstructedBefore).toBe(before); expect(reconstructedAfter).toBe(after); }); it('returns only equal segments for identical text', () => { const text = 'nothing changed here'; const segments = diffMarkdown(text, text); expect(segments.every((s) => s.type === 'equal')).toBe(true); expect(only(segments, 'equal')).toBe(text); }); it('handles empty before (pure insert) and empty after (pure delete)', () => { expect(diffMarkdown('', 'brand new')).toEqual([{ type: 'added', value: 'brand new' }]); expect(diffMarkdown('all gone', '')).toEqual([{ type: 'removed', value: 'all gone' }]); }); });