/** * @jest-environment jsdom * * Footnote preview tests — DOM-driven, no real timers/animations. */ const { mountFootnotePreview } = require('../src/renderer/footnote-preview'); function makePreviewHtml(refText, fnText) { return `
hello1
plain text
'; document.body.appendChild(root); mountFootnotePreview(root, { delayMs: 0 }); root.querySelector('p').dispatchEvent(new MouseEvent('mouseover', { bubbles: true })); jest.advanceTimersByTime(0); // Popover exists (it was created on first show path normally) but // should not be visible. const popover = document.querySelector('.footnote-preview'); if (popover) expect(popover.style.display).toBe('none'); }); test('does not throw when the footnote body is missing (dangling ref)', () => { const root = document.createElement('div'); // Reference exists but no matchingx99
'; document.body.appendChild(root); mountFootnotePreview(root, { delayMs: 0 }); const ref = root.querySelector('a[data-footnote-ref]'); expect(() => ref.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }))).not.toThrow(); jest.advanceTimersByTime(0); const popover = document.querySelector('.footnote-preview'); if (popover) expect(popover.style.display).toBe('none'); }); test('strips the backref ↩ from the displayed text', () => { const root = document.createElement('div'); root.innerHTML = makePreviewHtml('ref', 'see section 3 for context'); document.body.appendChild(root); mountFootnotePreview(root, { delayMs: 0 }); root .querySelector('a[data-footnote-ref]') .dispatchEvent(new MouseEvent('mouseover', { bubbles: true })); jest.advanceTimersByTime(0); const popover = document.querySelector('.footnote-preview'); expect(popover.textContent).toBe('see section 3 for context'); expect(popover.textContent).not.toMatch(/↩/); }); test('cancels a pending show when a new ref is hovered', () => { const root = document.createElement('div'); root.innerHTML = `