Files
open-design/apps/web/tests/runtime/comment-save-selector.test.ts
T
CaprikaandGitHub 4d4f53fdf4 [OPEND-4150] fix(share): refresh previews during comments and unblock publication (#8904)
* [OPEND-4150] fix(share): unblock updates and resolve native HTML anchors

* [OPEND-4150] fix(share): refresh comments live and decouple publication

* fix(comments): preserve save identity and HTTP UUID compatibility

* fix(comments): save current replacement styles

* fix(comments): clear unfinished strokes on URL preview load

* fix(comments): validate chat targets and refresh slide indices

* test(comments): cover send validation after main integration

* fix(comments): bind target validation to document generation

* fix: preserve normal comment saves during preview refresh (OPEND-4150)
2026-10-22 05:12:50 +00:00

56 lines
3.9 KiB
TypeScript

// @vitest-environment node
import { JSDOM } from 'jsdom';
import { expect, it } from 'vitest';
import { buildSrcdoc } from '../../src/runtime/srcdoc';
it('save validation follows the current selector across text/replacement changes, and reports deletion', () => {
const dom = new JSDOM('<body><button>Original</button></body>', { runScripts: 'outside-only', pretendToBeVisual: true });
try {
const win = dom.window;
const replies: Record<string, unknown>[] = [];
Object.defineProperty(win, 'parent', { value: { postMessage: (data: Record<string, unknown>) => replies.push(data) } });
Object.defineProperty(win.HTMLElement.prototype, 'getBoundingClientRect', { value: () => ({ x: 0, y: 20, width: 100, height: 40 }) });
const script = buildSrcdoc('<body></body>', { commentBridge: true, inspectBridge: true, transportActivationGeneration: 'document-2' }).match(/<script data-od-selection-bridge>([\s\S]*?)<\/script>/)?.[1];
if (!script) throw new Error('missing bridge');
new win.Function(script).call(win);
const save = () => {
win.dispatchEvent(new win.MessageEvent('message', { data: { type: 'od:comment-active-target', validateForSave: true,
requestId: 'save', elementId: 'old-id', selector: 'body > button:nth-of-type(1)' } }));
return replies.at(-1);
};
expect(save()).toMatchObject({ type: 'od:comment-active-target-update', documentVersion: 'srcdoc:document-2', text: 'Original' });
win.document.querySelector('button')!.textContent = 'Changed copy';
expect(save()).toMatchObject({ type: 'od:comment-active-target-update', text: 'Changed copy' });
win.document.querySelector('button')!.outerHTML = '<button data-od-id="new">Replacement</button>';
expect(save()).toMatchObject({ type: 'od:comment-active-target-update', elementId: 'new', text: 'Replacement', selector: '[data-od-id="new"]', requestedSelector: 'body > button:nth-of-type(1)' });
win.dispatchEvent(new win.MessageEvent('message', { data: { type: 'od:comment-mode', enabled: true, mode: 'picker' } }));
const uuid = '12345678-1234-4234-8234-123456789abc';
win.document.querySelector('button')!.outerHTML = `<button data-od-comment-id="${uuid}">UUID replacement</button>`;
expect(save()).toMatchObject({ elementId: `cmt:${uuid}`, selector: `[data-od-comment-id="${uuid}"]`,
requestedSelector: 'body > button:nth-of-type(1)' });
win.document.querySelector('button')!.remove();
expect(save()).toMatchObject({ type: 'od:comment-location-missing', requestId: 'save' });
} finally { dom.window.close(); }
});
it.each(['span', 'div'])('save accepts an existing %s after picker eligibility changes', tag => {
const dom = new JSDOM(`<body><${tag}>Original</${tag}></body>`, { runScripts: 'outside-only', pretendToBeVisual: true });
try {
const win = dom.window;
const replies: Record<string, unknown>[] = [];
Object.defineProperty(win, 'parent', { value: { postMessage: (data: Record<string, unknown>) => replies.push(data) } });
Object.defineProperty(win.HTMLElement.prototype, 'getBoundingClientRect', { value: () => ({ x: 0, y: 20, width: 100, height: 40 }) });
const script = buildSrcdoc('<body></body>', { commentBridge: true }).match(/<script data-od-selection-bridge>([\s\S]*?)<\/script>/)?.[1];
if (!script) throw new Error('missing bridge');
new win.Function(script).call(win);
const save = () => {
win.dispatchEvent(new win.MessageEvent('message', { data: { type: 'od:comment-active-target', validateForSave: true,
requestId: 'save', elementId: 'old', selector: `body > ${tag}:nth-of-type(1)` } }));
return replies.at(-1);
};
expect(save()).toMatchObject({ type: 'od:comment-active-target-update', text: 'Original' });
win.document.querySelector(tag)!.innerHTML = tag === 'span' ? '' : '<span>A</span><span>B</span>';
expect(save()).toMatchObject({ type: 'od:comment-active-target-update', text: tag === 'span' ? '' : 'AB' });
} finally { dom.window.close(); }
});