import { describe, expect, it } from 'vitest'; import { JSDOM } from 'jsdom'; import { buildManualEditBridge, isMeaningfulManualEditElement, isManualEditHostNode, isSourceMappableManualEditElement, manualEditDomPathForElement, manualEditStableIdForElement, } from '../../src/edit-mode/bridge'; describe('manual edit bridge target normalization', () => { it('prefers explicit data-od-id over generated ids', () => { const dom = new JSDOM('

Title

'); const target = dom.window.document.querySelector('h1')!; expect(manualEditStableIdForElement(target)).toBe('hero'); expect(target.getAttribute('data-od-runtime-id')).toBeNull(); }); it('generates stable DOM path ids for unannotated elements', () => { const dom = new JSDOM('

First

Second

'); const target = dom.window.document.querySelectorAll('p')[1]!; expect(manualEditDomPathForElement(target)).toBe('path-0-0-1'); expect(manualEditStableIdForElement(target)).toBe('path-0-0-1'); expect(manualEditStableIdForElement(target)).toBe('path-0-0-1'); expect(target.getAttribute('data-od-runtime-id')).toBe('path-0-0-1'); }); it('generates DOM path ids against source-shaped children, ignoring host shim nodes', () => { const dom = new JSDOM( '

First

Second

', ); const target = dom.window.document.querySelectorAll('p')[1]!; expect(isManualEditHostNode(dom.window.document.querySelector('[data-od-sandbox-shim]')!)).toBe(true); expect(manualEditDomPathForElement(target)).toBe('path-0-0-1'); }); it('discovers meaningful elements and ignores tiny or irrelevant elements', () => { const dom = new JSDOM('

Title

'); const title = dom.window.document.querySelector('h1')!; const script = dom.window.document.querySelector('script')!; expect(isMeaningfulManualEditElement(title, { width: 80, height: 24 })).toBe(true); expect(isMeaningfulManualEditElement(title, { width: 3, height: 24 })).toBe(false); expect(isMeaningfulManualEditElement(script, { width: 80, height: 24 })).toBe(false); }); it('does not expose path targets unless they carry a source path marker', () => { const dom = new JSDOM('

Runtime title

Source text

'); const runtimeTitle = dom.window.document.querySelector('h1')!; const sourceText = dom.window.document.querySelector('p')!; expect(isSourceMappableManualEditElement(runtimeTitle)).toBe(false); expect(isSourceMappableManualEditElement(sourceText)).toBe(true); expect(isMeaningfulManualEditElement(runtimeTitle, { width: 80, height: 24 })).toBe(false); }); it('omits selected outerHTML from bulk target posts but includes it for selected targets', () => { const bridge = buildManualEditBridge(true); expect(bridge).toContain('targets.push(targetFrom(nodes[i], false))'); expect(bridge).toContain("target: targetFrom(el, true)"); expect(bridge).toContain('if (!isSourceMappable(nodes[i])) continue;'); expect(bridge).toContain('if (isPrimaryTarget(el)) return el;'); }); });