open-design/apps/web/tests/edit-mode/bridge.test.ts
marco 5dd70b5016
Some checks failed
ci / Validate workspace (push) Successful in 12m32s
landing-page-ci / Validate landing page (push) Successful in 9m41s
landing-page-deploy / Deploy landing page (push) Failing after 5m23s
refresh-contributors-wall / Refresh contributors wall cache bust (push) Failing after 11s
github-metrics / Generate repository metrics SVG (push) Failing after 2m3s
Initial import: open-design source for helix-mind.ai distribution
This repository contains the open-design daemon CLI source code, built
and packaged at https://helix-mind.ai/cli/open-design/latest.tgz for use
by the HelixMind /design slash command.

Licenses: Apache-2.0 (root) + MIT (skills/*)
2026-05-06 20:50:24 +02:00

70 lines
3.3 KiB
TypeScript

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('<main><h1 data-od-id="hero">Title</h1></main>');
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('<main><section><p>First</p><p>Second</p></section></main>');
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(
'<script data-od-sandbox-shim></script><main><section><p>First</p><p>Second</p></section></main><script data-od-edit-bridge></script>',
);
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('<main><h1 data-od-source-path="path-0-0">Title</h1><script>1</script></main>');
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('<main><h1>Runtime title</h1><p data-od-source-path="path-0-1">Source text</p></main>');
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;');
});
});