import { describe, expect, it } from 'vitest'; import { LOCAL_GAME_PREVIEW_SIZE_MESSAGE, parseLocalGamePreviewContentSize, resolveLocalGamePreviewContentSizeUpdate, resolveLocalGamePreviewFitLayout, } from '../src/features/project-workspace/LocalGamePreviewFrame'; describe('local game preview viewport fitting', () => { it('keeps a game at native size when its content fits', () => { expect( resolveLocalGamePreviewFitLayout( { width: 1200, height: 700 }, { contentWidth: 1200, contentHeight: 700, viewportWidth: 1200, viewportHeight: 700, }, ), ).toEqual({ width: 1200, height: 700, scale: 1 }); }); it('scales the complete game document into the available viewport', () => { expect( resolveLocalGamePreviewFitLayout( { width: 1200, height: 700 }, { contentWidth: 1200, contentHeight: 1000, viewportWidth: 1200, viewportHeight: 700, }, ), ).toEqual({ width: 1200, height: 1000, scale: 0.7 }); }); it('accepts the native viewport report and keeps viewport out of fit state', () => { const nativeViewport = { width: 1200, height: 700 }; const report = { contentWidth: 1200, contentHeight: 1000, viewportWidth: 1200, viewportHeight: 700, }; expect( resolveLocalGamePreviewContentSizeUpdate( null, report, nativeViewport, nativeViewport, ), ).toEqual(report); }); it('accepts changed content after the iframe has adopted the first fit viewport', () => { const nativeViewport = { width: 1200, height: 700 }; const current = { contentWidth: 1200, contentHeight: 1000, viewportWidth: 1200, viewportHeight: 700, }; const changed = { contentWidth: 1200, contentHeight: 1400, viewportWidth: 1200, viewportHeight: 1000, }; expect( resolveLocalGamePreviewContentSizeUpdate( current, changed, nativeViewport, { width: 1200, height: 1000, }, ), ).toEqual({ contentWidth: 1200, contentHeight: 1400, viewportWidth: 1200, viewportHeight: 700, }); }); it('shrinks the fitted frame when content becomes shorter inside the applied viewport', () => { const nativeViewport = { width: 1200, height: 700 }; const current = { contentWidth: 1200, contentHeight: 1000, viewportWidth: 1200, viewportHeight: 700, }; const changed = { contentWidth: 1200, contentHeight: 800, viewportWidth: 1200, viewportHeight: 1000, }; const updated = resolveLocalGamePreviewContentSizeUpdate( current, changed, nativeViewport, { width: 1200, height: 1000 }, ); expect(updated).toEqual({ contentWidth: 1200, contentHeight: 800, viewportWidth: 1200, viewportHeight: 700, }); expect(resolveLocalGamePreviewFitLayout(nativeViewport, updated)).toEqual({ width: 1200, height: 800, scale: 0.875, }); }); it('keeps the current state for repeated content dimensions and fit viewport feedback', () => { const nativeViewport = { width: 1200, height: 700 }; const current = { contentWidth: 1200, contentHeight: 1400, viewportWidth: 1200, viewportHeight: 700, }; expect( resolveLocalGamePreviewContentSizeUpdate( current, { ...current, viewportHeight: 1400 }, nativeViewport, { width: 1200, height: 1400 }, ), ).toBe(current); }); it('ignores delayed reports from a stale fitted viewport', () => { const nativeViewport = { width: 1200, height: 700 }; const current = { contentWidth: 1200, contentHeight: 1400, viewportWidth: 1200, viewportHeight: 700, }; expect( resolveLocalGamePreviewContentSizeUpdate( current, { contentWidth: 1200, contentHeight: 1100, viewportWidth: 1200, viewportHeight: 1000, }, nativeViewport, { width: 1200, height: 1400 }, ), ).toBe(current); }); it('rejects malformed or unrelated cross-frame messages', () => { expect( parseLocalGamePreviewContentSize({ type: LOCAL_GAME_PREVIEW_SIZE_MESSAGE, contentWidth: 1200, contentHeight: Number.NaN, viewportWidth: 1200, viewportHeight: 700, }), ).toBeNull(); expect( parseLocalGamePreviewContentSize({ type: 'unrelated', contentWidth: 1200, contentHeight: 700, viewportWidth: 1200, viewportHeight: 700, }), ).toBeNull(); }); });