import { htmlToJson, jsonToHtml } from './collaboration.util'; const findFirst = (json: any, type: string): any | undefined => { if (!json || typeof json !== 'object') return undefined; if (json.type === type) return json; if (Array.isArray(json.content)) { for (const child of json.content) { const found = findFirst(child, type); if (found) return found; } } return undefined; }; /** * Guards the fragile parse-priority approach that lets a `footnoteReference` * NODE win over the `Superscript` MARK for `` elements. In the server * `tiptapExtensions` list, Superscript is registered BEFORE the footnote nodes, * so without the priority guard a `` would be parsed as * an (empty) superscript mark and the footnote reference would be lost. */ describe('footnote reference vs superscript mark (server schema round-trip)', () => { const HTML = '

Water' + '' + ' here.

' + '
' + '

First note.

' + '
'; it('parses into a footnoteReference NODE (not a superscript mark)', () => { const json = htmlToJson(HTML); const ref = findFirst(json, 'footnoteReference'); expect(ref).toBeDefined(); expect(ref.attrs.id).toBe('fn1'); // It must NOT have been swallowed as a superscript mark on text. const superscriptText = JSON.stringify(json).includes('"superscript"'); expect(superscriptText).toBe(false); // The matching definition survives too. const def = findFirst(json, 'footnoteDefinition'); expect(def).toBeDefined(); expect(def.attrs.id).toBe('fn1'); }); it('round-trips an empty footnoteReference back to ', () => { const json = htmlToJson(HTML); const html = jsonToHtml(json); expect(html).toContain('data-footnote-ref'); expect(html).toContain('data-id="fn1"'); // And a second parse still yields the node (stable round-trip). const json2 = htmlToJson(html); const ref2 = findFirst(json2, 'footnoteReference'); expect(ref2).toBeDefined(); expect(ref2.attrs.id).toBe('fn1'); }); });