@@ -2,8 +2,9 @@ import ts from "typescript";
22import { expect , it , vi } from "vitest" ;
33import { computed , effectScope , nextTick , reactive , ref , toRaw , watch } from "vue" ;
44import source from "../../packages/web-proxy/src/WebProxySurface.vue?raw" ;
5+ import aiPanelSource from "../components/RightPanel/AiOverlayPanel.vue?raw" ;
56
6- function setupSurface ( safeMode = false , observe = false ) {
7+ function setupSurface ( safeMode = false , observe = false , dom ?: Document ) {
78 const desktopWebProxy = {
89 create : vi . fn ( async ( request : Record < string , unknown > ) => structuredClone ( request ) ) ,
910 onState : vi . fn ( async ( ) => vi . fn ( ) ) ,
@@ -70,16 +71,18 @@ function setupSurface(safeMode = false, observe = false) {
7071 useWorkspaceTabs : ( ) => ( { activeTabId : ref ( "tab" ) , tabs : ref ( [ ] ) , markSessionConnected, closeSession } ) ,
7172 usePlatform : ( ) => ( { } ) ,
7273 registerWorkspaceSessionCloseGuard : vi . fn ( ) ,
73- document : {
74+ document : dom ?? {
7475 visibilityState : "visible" ,
7576 querySelector : vi . fn ( ) ,
7677 addEventListener : vi . fn ( ) ,
7778 removeEventListener : vi . fn ( )
7879 } ,
79- MutationObserver : class {
80- observe ( ) { }
81- disconnect ( ) { }
82- } ,
80+ MutationObserver : dom
81+ ? MutationObserver
82+ : class {
83+ observe ( ) { }
84+ disconnect ( ) { }
85+ } ,
8386 ResizeObserver : class {
8487 observe ( ) { }
8588 disconnect ( ) { }
@@ -114,6 +117,45 @@ function setupSurface(safeMode = false, observe = false) {
114117 } ;
115118}
116119
120+ it . skipIf ( typeof document === "undefined" ) (
121+ "backgrounds the native website for AI and menus, restoring only the active tab" ,
122+ async ( ) => {
123+ const { surface, desktopWebProxy, props, mount, stop } = setupSurface ( false , true , document ) ;
124+ const host = document . createElement ( "div" ) ;
125+ document . body . append ( host ) ;
126+ try {
127+ await mount ( ) ;
128+ expect ( desktopWebProxy . setActive ) . toHaveBeenLastCalledWith ( surface . viewLabel , true ) ;
129+ // Use the actual AI host markup so losing its overlay marker regresses this check.
130+ host . innerHTML = `${ aiPanelSource . match ( / < d i v \s + i d = " w o r k s p a c e - a i - o v e r l a y " [ ^ > ] * > / ) ! [ 0 ] } </div>` ;
131+ await vi . waitFor ( ( ) => expect ( desktopWebProxy . setActive ) . toHaveBeenLastCalledWith ( surface . viewLabel , false ) ) ;
132+
133+ host . insertAdjacentHTML ( "beforeend" , '<div role="menu" data-state="open"></div>' ) ;
134+ host . firstElementChild ! . remove ( ) ;
135+ await nextTick ( ) ;
136+ expect ( desktopWebProxy . setActive ) . toHaveBeenLastCalledWith ( surface . viewLabel , false ) ;
137+ host . replaceChildren ( ) ;
138+ await vi . waitFor ( ( ) => expect ( desktopWebProxy . setActive ) . toHaveBeenLastCalledWith ( surface . viewLabel , true ) ) ;
139+
140+ props . active = false ;
141+ await nextTick ( ) ;
142+ expect ( desktopWebProxy . setActive ) . toHaveBeenLastCalledWith ( surface . viewLabel , false ) ;
143+ host . innerHTML = "<div data-native-view-overlay></div>" ;
144+ await nextTick ( ) ;
145+ host . replaceChildren ( ) ;
146+ await nextTick ( ) ;
147+ expect ( desktopWebProxy . setActive ) . toHaveBeenLastCalledWith ( surface . viewLabel , false ) ;
148+ props . active = true ;
149+ await vi . waitFor ( ( ) => expect ( desktopWebProxy . setActive ) . toHaveBeenLastCalledWith ( surface . viewLabel , true ) ) ;
150+ expect ( desktopWebProxy . create ) . toHaveBeenCalledOnce ( ) ;
151+ expect ( desktopWebProxy . close ) . not . toHaveBeenCalled ( ) ;
152+ } finally {
153+ stop ( ) ;
154+ host . remove ( ) ;
155+ }
156+ }
157+ ) ;
158+
117159it . each ( [ undefined , [ ] , [ "https://sso.test" , "https://asset.test:8443" ] ] . map ( ( allowedUrls ) => ( { allowedUrls } ) ) ) (
118160 "creates a view from reactive session data with allowed URLs $allowedUrls" ,
119161 async ( { allowedUrls } ) => {
0 commit comments