@@ -755,6 +755,158 @@ define(function (require, exports, module) {
755755 return LiveDevMultiBrowser . status === LiveDevMultiBrowser . STATUS_ACTIVE ;
756756 } , "live dev to reopen" , 20000 ) ;
757757 } , 30000 ) ;
758+
759+ it ( "should closing and reopening live preview panel preserve md iframe, cache, and scroll" , async function ( ) {
760+ await _openMdFileAndWaitForPreview ( "long.md" ) ;
761+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Long Document" ) ,
762+ "long doc content to load" ) ;
763+ await _enterEditMode ( ) ;
764+
765+ // Scroll down
766+ _setViewerScrollTop ( 300 ) ;
767+ await awaitsFor ( ( ) => _getViewerScrollTop ( ) >= 290 , "scroll to apply" ) ;
768+ const scrollBefore = _getViewerScrollTop ( ) ;
769+
770+ // Set verification code to check iframe persists
771+ const verificationCode = "panel_persist_" + Date . now ( ) ;
772+ _getMdIFrameWin ( ) . __test_panel_persist = verificationCode ;
773+
774+ // Close live preview panel
775+ await awaitsForDone ( CommandManager . execute ( Commands . FILE_LIVE_FILE_PREVIEW ) ) ;
776+ await awaitsFor ( ( ) => ! WorkspaceManager . isPanelVisible ( "live-preview-panel" ) ,
777+ "live preview panel to close" ) ;
778+
779+ // Reopen live preview panel
780+ await awaitsForDone ( CommandManager . execute ( Commands . FILE_LIVE_FILE_PREVIEW ) ) ;
781+ await awaitsFor ( ( ) => WorkspaceManager . isPanelVisible ( "live-preview-panel" ) ,
782+ "live preview panel to reopen" ) ;
783+ await _waitForMdPreviewReady ( ) ;
784+
785+ // Verify iframe persisted (JS variable survived)
786+ const win = _getMdIFrameWin ( ) ;
787+ expect ( win . __test_panel_persist ) . toBe ( verificationCode ) ;
788+
789+ // Verify content is still correct
790+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Long Document" ) ,
791+ "long doc content after panel reopen" ) ;
792+
793+ // Verify edit mode preserved
794+ await _assertMdEditMode ( true ) ;
795+
796+ // Verify scroll position preserved
797+ await awaitsFor ( ( ) => {
798+ const scroll = _getViewerScrollTop ( ) ;
799+ return Math . abs ( scroll - scrollBefore ) < 50 ;
800+ } , "scroll position to be preserved after panel reopen" ) ;
801+ } , 15000 ) ;
802+
803+ it ( "should reload button re-render current file with fresh DOM preserving scroll and edit mode" , async function ( ) {
804+ await _openMdFileAndWaitForPreview ( "long.md" ) ;
805+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Long Document" ) ,
806+ "long doc to load" ) ;
807+ await _enterEditMode ( ) ;
808+
809+ // Scroll down
810+ _setViewerScrollTop ( 300 ) ;
811+ await awaitsFor ( ( ) => _getViewerScrollTop ( ) >= 290 , "scroll to apply" ) ;
812+ const scrollBefore = _getViewerScrollTop ( ) ;
813+
814+ // Capture the current h1 DOM node
815+ const h1Before = _getMdIFrameDoc ( ) . querySelector ( "#viewer-content h1" ) ;
816+ expect ( h1Before ) . not . toBeNull ( ) ;
817+
818+ // Click reload button
819+ testWindow . $ ( "#reloadLivePreviewButton" ) . click ( ) ;
820+
821+ // Wait for re-render — the h1 should be a NEW DOM node (old one disposed)
822+ await awaitsFor ( ( ) => {
823+ const h1After = _getMdIFrameDoc ( ) . querySelector ( "#viewer-content h1" ) ;
824+ return h1After && h1After !== h1Before &&
825+ h1After . textContent . includes ( "Long Document" ) ;
826+ } , "DOM to be recreated after reload" ) ;
827+
828+ // Verify edit mode preserved
829+ await _assertMdEditMode ( true ) ;
830+
831+ // Verify scroll position approximately preserved
832+ await awaitsFor ( ( ) => {
833+ const scroll = _getViewerScrollTop ( ) ;
834+ return Math . abs ( scroll - scrollBefore ) < 100 ;
835+ } , "scroll position to be approximately restored after reload" ) ;
836+ } , 15000 ) ;
837+
838+ it ( "should working set changes sync to iframe and cache entries persist" , async function ( ) {
839+ // Open multiple files to populate cache
840+ await _openMdFileAndWaitForPreview ( "doc1.md" ) ;
841+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Document One" ) ,
842+ "doc1 to load" ) ;
843+
844+ await _openMdFileAndWaitForPreview ( "doc2.md" ) ;
845+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Document Two" ) ,
846+ "doc2 to load" ) ;
847+
848+ // Both should be in cache
849+ const win = _getMdIFrameWin ( ) ;
850+ await awaitsFor ( ( ) => {
851+ const keys = win . __getCacheKeys ( ) ;
852+ return keys . some ( k => k . endsWith ( "doc1.md" ) ) &&
853+ keys . some ( k => k . endsWith ( "doc2.md" ) ) ;
854+ } , "both doc1 and doc2 to be in cache" ) ;
855+
856+ // Close doc2 from working set
857+ await awaitsForDone ( CommandManager . execute ( Commands . FILE_CLOSE ) ,
858+ "close doc2" ) ;
859+
860+ // doc1 should still be cached and displayable
861+ await _openMdFileAndWaitForPreview ( "doc1.md" ) ;
862+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Document One" ) ,
863+ "doc1 still showing after doc2 closed" ) ;
864+
865+ await awaitsFor ( ( ) => {
866+ const keys = win . __getCacheKeys ( ) ;
867+ return keys . some ( k => k . endsWith ( "doc1.md" ) ) ;
868+ } , "doc1 still in cache after doc2 closed" ) ;
869+ } , 15000 ) ;
870+
871+ it ( "should cache multiple files and retrieve them from cache" , async function ( ) {
872+ // Open doc1, doc2, doc3 sequentially to populate cache
873+ await _openMdFileAndWaitForPreview ( "doc1.md" ) ;
874+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Document One" ) ,
875+ "doc1 to load" ) ;
876+
877+ await _openMdFileAndWaitForPreview ( "doc2.md" ) ;
878+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Document Two" ) ,
879+ "doc2 to load" ) ;
880+
881+ await _openMdFileAndWaitForPreview ( "doc3.md" ) ;
882+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Document Three" ) ,
883+ "doc3 to load" ) ;
884+
885+ // All three should be in cache
886+ const win = _getMdIFrameWin ( ) ;
887+ await awaitsFor ( ( ) => {
888+ const keys = win . __getCacheKeys ( ) ;
889+ return keys . some ( k => k . endsWith ( "doc1.md" ) ) &&
890+ keys . some ( k => k . endsWith ( "doc2.md" ) ) &&
891+ keys . some ( k => k . endsWith ( "doc3.md" ) ) ;
892+ } , "all three docs to be in cache" ) ;
893+
894+ // Switch back to doc1 — should load from cache
895+ await _openMdFileAndWaitForPreview ( "doc1.md" ) ;
896+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Document One" ) ,
897+ "doc1 from cache" ) ;
898+
899+ // Switch to doc2 — from cache
900+ await _openMdFileAndWaitForPreview ( "doc2.md" ) ;
901+ await awaitsFor ( ( ) => _getViewerH1Text ( ) . includes ( "Document Two" ) ,
902+ "doc2 from cache" ) ;
903+
904+ // Verify all still cached
905+ const keys = win . __getCacheKeys ( ) ;
906+ expect ( keys . some ( k => k . endsWith ( "doc1.md" ) ) ) . toBeTrue ( ) ;
907+ expect ( keys . some ( k => k . endsWith ( "doc2.md" ) ) ) . toBeTrue ( ) ;
908+ expect ( keys . some ( k => k . endsWith ( "doc3.md" ) ) ) . toBeTrue ( ) ;
909+ } , 15000 ) ;
758910 } ) ;
759911
760912 } ) ;
0 commit comments