@@ -352,6 +352,77 @@ export class BasePage {
352352 await this . _page . keyboard . type ( text )
353353 }
354354
355+ /**
356+ * Deterministically open the mobile navigation menu and wait for it to finish animating
357+ */
358+ async openMobileMenu ( options ?: { timeout ?: number } ) : Promise < void > {
359+ const timeout = options ?. timeout ?? EXTENDED_NAVIGATION_TIMEOUT
360+
361+ await this . waitForHeaderComponents ( { timeout } )
362+ await this . _page . waitForFunction (
363+ ( ) => ! document . documentElement ?. hasAttribute ( 'data-astro-transition' ) ,
364+ undefined ,
365+ { timeout }
366+ )
367+
368+ const toggleButton = this . _page . locator ( 'button[aria-label="toggle menu"]' )
369+ await expect ( toggleButton ) . toBeVisible ( { timeout } )
370+
371+ const expanded = await toggleButton . getAttribute ( 'aria-expanded' )
372+ if ( expanded !== 'true' ) {
373+ await toggleButton . click ( )
374+ }
375+
376+ await this . _page . waitForFunction (
377+ ( ) => {
378+ const header = document . getElementById ( 'header' )
379+ const menu = document . querySelector ( '.main-nav-menu' )
380+ const body = document . body
381+
382+ const headerExpanded = header ?. classList . contains ( 'aria-expanded-true' ) ?? false
383+ const menuVisible = menu ?. classList . contains ( 'menu-visible' ) ?? false
384+ const bodyScrollLocked = body ?. classList . contains ( 'no-scroll' ) ?? false
385+
386+ return headerExpanded && menuVisible && bodyScrollLocked
387+ } ,
388+ undefined ,
389+ { timeout }
390+ )
391+ }
392+
393+ /**
394+ * Deterministically close the mobile navigation menu and wait for scroll lock to clear
395+ */
396+ async closeMobileMenu ( options ?: { timeout ?: number } ) : Promise < void > {
397+ const timeout = options ?. timeout ?? DEFAULT_NAVIGATION_TIMEOUT
398+ const toggleButton = this . _page . locator ( 'button[aria-label="toggle menu"]' )
399+
400+ await expect ( toggleButton ) . toBeVisible ( { timeout } )
401+
402+ const expanded = await toggleButton . getAttribute ( 'aria-expanded' )
403+ if ( expanded !== 'true' ) {
404+ return
405+ }
406+
407+ await toggleButton . click ( )
408+
409+ await this . _page . waitForFunction (
410+ ( ) => {
411+ const header = document . getElementById ( 'header' )
412+ const menu = document . querySelector ( '.main-nav-menu' )
413+ const body = document . body
414+
415+ const headerCollapsed = ! ( header ?. classList . contains ( 'aria-expanded-true' ) ?? false )
416+ const menuHidden = ! ( menu ?. classList . contains ( 'menu-visible' ) ?? false )
417+ const bodyScrollRestored = ! ( body ?. classList . contains ( 'no-scroll' ) ?? false )
418+
419+ return headerCollapsed && menuHidden && bodyScrollRestored
420+ } ,
421+ undefined ,
422+ { timeout }
423+ )
424+ }
425+
355426 /**
356427 * Get keyboard object for advanced keyboard operations
357428 */
0 commit comments