import { Editor } from '@tiptap/core'; import { markdownOf, richTextExtensions } from './rich-text'; /** Markdown in, the editor's Markdown out: what an edit that changes nothing saves. */ function roundTrip(markdown: string): string { const editor = new Editor({ element: document.createElement('div'), extensions: richTextExtensions(), content: markdown, contentType: 'markdown', }); const out = markdownOf(editor); editor.destroy(); return out; } describe('rich text', () => { it('keeps mentions as the API reads them', () => { expect(roundTrip('Hola @[Ana López](101), ¿lo miras?')).toBe( 'Hola @[Ana López](101), ¿lo miras?', ); }); it('keeps pasted images pointing at their attachment', () => { expect(roundTrip('Mira:\n\n![captura.png](attachment:abc-123)')).toContain( '![captura.png](attachment:abc-123)', ); }); it('keeps formatting, lists, task lists, quotes, code and links', () => { const text = [ '## Pasos', '', 'Texto con **negrita**, *cursiva*, ~~tachado~~ y `código`.', '', '- uno', '- dos', '', '1. primero', '2. segundo', '', '- [ ] pendiente', '- [x] hecho', '', '> una cita', '', '```', 'const a = 1;', '```', '', '[enlace](https://example.com)', ].join('\n'); const out = roundTrip(text); for (const piece of [ '## Pasos', '**negrita**', '*cursiva*', '~~tachado~~', '`código`', '- uno', '1. primero', '- [ ] pendiente', '- [x] hecho', '> una cita', 'const a = 1;', '[enlace](https://example.com)', ]) expect(out).toContain(piece); }); it('keeps tables', () => { const out = roundTrip('| a | b |\n| --- | --- |\n| 1 | 2 |'); expect(out).toMatch(/\|\s*a\s*\|\s*b\s*\|/); expect(out).toMatch(/\|\s*1\s*\|\s*2\s*\|/); }); it('answers an empty string for an empty editor', () => { expect(roundTrip('')).toBe(''); }); }); describe('rich text, line breaks', () => { it('keeps a single line break as a line break', () => { const out = roundTrip('primera línea\nsegunda línea'); expect(out).not.toBe('primera línea segunda línea'); expect(out).toMatch(/primera línea(\s{2}|\\)?\nsegunda línea/); }); });