@@ -269,6 +269,65 @@ function installVisualViewport(height: number, offsetTop = 0) {
269269 return visualViewport ;
270270}
271271
272+ function installFullscreenApiForMobileShell ( ) {
273+ let fullscreenElement : Element | null = null ;
274+
275+ const requestFullscreen = vi . fn ( ) . mockImplementation ( function ( this : HTMLElement ) {
276+ fullscreenElement = this ;
277+ document . dispatchEvent ( new Event ( "fullscreenchange" ) ) ;
278+ return Promise . resolve ( ) ;
279+ } ) ;
280+
281+ const exitFullscreen = vi . fn ( ) . mockImplementation ( async ( ) => {
282+ fullscreenElement = null ;
283+ document . dispatchEvent ( new Event ( "fullscreenchange" ) ) ;
284+ } ) ;
285+
286+ Object . defineProperty ( document , "fullscreenEnabled" , {
287+ configurable : true ,
288+ value : true ,
289+ } ) ;
290+
291+ Object . defineProperty ( document , "fullscreenElement" , {
292+ configurable : true ,
293+ get : ( ) => fullscreenElement ,
294+ } ) ;
295+
296+ Object . defineProperty ( document , "exitFullscreen" , {
297+ configurable : true ,
298+ value : exitFullscreen ,
299+ } ) ;
300+
301+ Object . defineProperty ( HTMLElement . prototype , "requestFullscreen" , {
302+ configurable : true ,
303+ value : requestFullscreen ,
304+ } ) ;
305+
306+ return { requestFullscreen, exitFullscreen } ;
307+ }
308+
309+ function removeFullscreenApiForMobileShell ( ) {
310+ Object . defineProperty ( document , "fullscreenEnabled" , {
311+ configurable : true ,
312+ value : false ,
313+ } ) ;
314+
315+ Object . defineProperty ( document , "fullscreenElement" , {
316+ configurable : true ,
317+ get : ( ) => null ,
318+ } ) ;
319+
320+ Object . defineProperty ( document , "exitFullscreen" , {
321+ configurable : true ,
322+ value : undefined ,
323+ } ) ;
324+
325+ Object . defineProperty ( HTMLElement . prototype , "requestFullscreen" , {
326+ configurable : true ,
327+ value : undefined ,
328+ } ) ;
329+ }
330+
272331function installMatchMediaMock ( predicate : ( query : string ) => boolean ) {
273332 const originalMatchMedia = window . matchMedia ;
274333 const listeners = new Map < string , Set < ( event : MediaQueryListEvent ) => void > > ( ) ;
@@ -704,6 +763,37 @@ describe("MobileShell Phase 2 workspace", () => {
704763 expect ( screen . getByText ( "SettingsPage" ) ) . toBeInTheDocument ( ) ;
705764 } ) ;
706765
766+ it ( "shows a fullscreen toggle to the right of settings when the browser supports fullscreen" , async ( ) => {
767+ installFullscreenApiForMobileShell ( ) ;
768+ renderMobileShell ( { initialEntry : "/workspace" } ) ;
769+
770+ const settingsButton = screen . getByRole ( "button" , { name : "Open settings" } ) ;
771+ const fullscreenButton = await screen . findByRole ( "button" , { name : "Enter Fullscreen" } ) ;
772+
773+ expect ( settingsButton . nextElementSibling ) . toBe ( fullscreenButton ) ;
774+ } ) ;
775+
776+ it ( "hides the fullscreen toggle on mobile when the browser does not support fullscreen" , async ( ) => {
777+ removeFullscreenApiForMobileShell ( ) ;
778+ renderMobileShell ( { initialEntry : "/workspace" } ) ;
779+
780+ expect ( screen . getByRole ( "button" , { name : "Open settings" } ) ) . toBeInTheDocument ( ) ;
781+ expect ( screen . queryByRole ( "button" , { name : "Enter Fullscreen" } ) ) . toBeNull ( ) ;
782+ } ) ;
783+
784+ it ( "switches the mobile fullscreen button to exit mode after entering fullscreen" , async ( ) => {
785+ const api = installFullscreenApiForMobileShell ( ) ;
786+ const user = userEvent . setup ( ) ;
787+ renderMobileShell ( { initialEntry : "/workspace" } ) ;
788+
789+ await user . click ( await screen . findByRole ( "button" , { name : "Enter Fullscreen" } ) ) ;
790+
791+ await waitFor ( ( ) => {
792+ expect ( api . requestFullscreen ) . toHaveBeenCalledTimes ( 1 ) ;
793+ expect ( screen . getByRole ( "button" , { name : "Exit Fullscreen" } ) ) . toBeInTheDocument ( ) ;
794+ } ) ;
795+ } ) ;
796+
707797 it ( "keeps welcome route as full-page content outside the workspace scaffold" , ( ) => {
708798 renderMobileShell ( { initialEntry : "/" , withWorkspaces : false } ) ;
709799
0 commit comments