// @vitest-environment jsdom
import { afterEach, expect, it, vi } from 'vitest';
import { MOTION_PREVIEW_ACTIVITY, MOTION_PREVIEW_PROBE, MOTION_PREVIEW_REQUEST } from '@open-design/contracts/runtime/motion-source-player';
import { bindMotionPreviewActivity, unbindMotionPreviewActivity } from '../../src/runtime/motion-preview-activity';
import { buildSrcdoc } from '../../src/runtime/srcdoc';
afterEach(() => {
for (const frame of document.querySelectorAll('iframe')) unbindMotionPreviewActivity(frame);
document.body.innerHTML = '';
vi.restoreAllMocks();
});
function frame() {
const element = document.createElement('iframe');
element.dataset.odActive = 'true';
document.body.appendChild(element);
const post = vi.spyOn(element.contentWindow!, 'postMessage').mockImplementation(() => {});
bindMotionPreviewActivity(element);
const request = (id: string, source: MessageEventSource | null = element.contentWindow) => window.dispatchEvent(new MessageEvent('message', {source, data:{type:MOTION_PREVIEW_REQUEST, id}}));
return { element, post, request };
}
it('answers a reloaded hidden document with inactive and challenges it again on activation', async () => {
const { element, post, request } = frame();
request('first');
expect(post).toHaveBeenLastCalledWith({type:MOTION_PREVIEW_ACTIVITY, id:'first', active:true}, '*');
element.dataset.odActive = 'false';
await Promise.resolve();
expect(post).toHaveBeenLastCalledWith({type:MOTION_PREVIEW_ACTIVITY, active:false}, '*');
request('reloaded');
expect(post).toHaveBeenLastCalledWith({type:MOTION_PREVIEW_ACTIVITY, id:'reloaded', active:false}, '*');
element.dataset.odActive = 'true';
await Promise.resolve();
expect(post).toHaveBeenLastCalledWith({type:MOTION_PREVIEW_PROBE}, '*');
request('reloaded');
expect(post).toHaveBeenLastCalledWith({type:MOTION_PREVIEW_ACTIVITY, id:'reloaded', active:true}, '*');
});
it('ignores a different frame and removes listeners when the frame is evicted', () => {
const { element, post, request } = frame();
post.mockClear();
request('foreign', window);
expect(post).not.toHaveBeenCalled();
unbindMotionPreviewActivity(element);
post.mockClear();
request('after-eviction');
element.dispatchEvent(new Event('load'));
expect(post).not.toHaveBeenCalled();
});
it('marks only live video srcdoc and leaves standalone, frozen and ordinary documents unchanged', () => {
const video='';
const live=buildSrcdoc(video,{motionPreview:true});
expect(live).toContain('window.__odMotionPreview=true');
expect(live.indexOf('__odMotionPreview=true')).toBeLessThan(live.indexOf('data-od-motion-source-player'));
expect(buildSrcdoc(video)).not.toContain('__odMotionPreview=true');
expect(buildSrcdoc(video,{motionPreview:true,freezeMotion:true})).not.toContain('__odMotionPreview=true');
for(const content of ['Prototype','Interactive','']) {
expect(buildSrcdoc(content,{motionPreview:true})).toBe(buildSrcdoc(content));
}
});
it('pauses an inactive motion document without changing ordinary iframe prewarming', async () => {
const { element, post, request } = frame();
element.dataset.odMotionActive = 'false';
await Promise.resolve();
expect(element.dataset.odActive).toBe('true');
expect(post).toHaveBeenLastCalledWith({ type: MOTION_PREVIEW_ACTIVITY, active: false }, '*');
request('warm-hidden-document');
expect(post).toHaveBeenLastCalledWith({ type: MOTION_PREVIEW_ACTIVITY, id: 'warm-hidden-document', active: false }, '*');
element.dataset.odMotionActive = 'true';
await Promise.resolve();
request('warm-hidden-document');
expect(post).toHaveBeenLastCalledWith({ type: MOTION_PREVIEW_ACTIVITY, id: 'warm-hidden-document', active: true }, '*');
});