@@ -17,7 +17,7 @@ import {
1717} from '@angular/core' ;
1818import { Direction , Directionality } from '@angular/cdk/bidi' ;
1919import { OverlayContainer , Overlay } from '@angular/cdk/overlay' ;
20- import { ESCAPE , LEFT_ARROW , RIGHT_ARROW , DOWN_ARROW , TAB } from '@angular/cdk/keycodes' ;
20+ import { ESCAPE , LEFT_ARROW , RIGHT_ARROW , DOWN_ARROW , TAB , HOME , END } from '@angular/cdk/keycodes' ;
2121import {
2222 MAT_MENU_DEFAULT_OPTIONS ,
2323 MatMenu ,
@@ -601,6 +601,104 @@ describe('MatMenu', () => {
601601 expect ( overlayContainerElement . textContent ) . toBe ( '' ) ;
602602 } ) ) ;
603603
604+ it ( 'should focus the first item when pressing home' , fakeAsync ( ( ) => {
605+ const fixture = createComponent ( SimpleMenu , [ ] , [ FakeIcon ] ) ;
606+ fixture . detectChanges ( ) ;
607+
608+ fixture . componentInstance . trigger . openMenu ( ) ;
609+ fixture . detectChanges ( ) ;
610+
611+ const panel = overlayContainerElement . querySelector ( '.mat-menu-panel' ) ! ;
612+ const items = Array . from ( panel . querySelectorAll ( '.mat-menu-item' ) ) as HTMLElement [ ] ;
613+ items . forEach ( patchElementFocus ) ;
614+
615+ // Focus the last item since focus starts from the first one.
616+ items [ items . length - 1 ] . focus ( ) ;
617+ fixture . detectChanges ( ) ;
618+
619+ spyOn ( items [ 0 ] , 'focus' ) . and . callThrough ( ) ;
620+
621+ const event = dispatchKeyboardEvent ( panel , 'keydown' , HOME ) ;
622+ fixture . detectChanges ( ) ;
623+
624+ expect ( items [ 0 ] . focus ) . toHaveBeenCalled ( ) ;
625+ expect ( event . defaultPrevented ) . toBe ( true ) ;
626+ flush ( ) ;
627+ } ) ) ;
628+
629+ it ( 'should not focus the first item when pressing home with a modifier key' , fakeAsync ( ( ) => {
630+ const fixture = createComponent ( SimpleMenu , [ ] , [ FakeIcon ] ) ;
631+ fixture . detectChanges ( ) ;
632+
633+ fixture . componentInstance . trigger . openMenu ( ) ;
634+ fixture . detectChanges ( ) ;
635+
636+ const panel = overlayContainerElement . querySelector ( '.mat-menu-panel' ) ! ;
637+ const items = Array . from ( panel . querySelectorAll ( '.mat-menu-item' ) ) as HTMLElement [ ] ;
638+ items . forEach ( patchElementFocus ) ;
639+
640+ // Focus the last item since focus starts from the first one.
641+ items [ items . length - 1 ] . focus ( ) ;
642+ fixture . detectChanges ( ) ;
643+
644+ spyOn ( items [ 0 ] , 'focus' ) . and . callThrough ( ) ;
645+
646+ const event = createKeyboardEvent ( 'keydown' , HOME ) ;
647+ Object . defineProperty ( event , 'altKey' , { get : ( ) => true } ) ;
648+
649+ dispatchEvent ( panel , event ) ;
650+ fixture . detectChanges ( ) ;
651+
652+ expect ( items [ 0 ] . focus ) . not . toHaveBeenCalled ( ) ;
653+ expect ( event . defaultPrevented ) . toBe ( false ) ;
654+ flush ( ) ;
655+ } ) ) ;
656+
657+ it ( 'should focus the last item when pressing end' , fakeAsync ( ( ) => {
658+ const fixture = createComponent ( SimpleMenu , [ ] , [ FakeIcon ] ) ;
659+ fixture . detectChanges ( ) ;
660+
661+ fixture . componentInstance . trigger . openMenu ( ) ;
662+ fixture . detectChanges ( ) ;
663+
664+ const panel = overlayContainerElement . querySelector ( '.mat-menu-panel' ) ! ;
665+ const items = Array . from ( panel . querySelectorAll ( '.mat-menu-item' ) ) as HTMLElement [ ] ;
666+ items . forEach ( patchElementFocus ) ;
667+
668+ spyOn ( items [ items . length - 1 ] , 'focus' ) . and . callThrough ( ) ;
669+
670+ const event = dispatchKeyboardEvent ( panel , 'keydown' , END ) ;
671+ fixture . detectChanges ( ) ;
672+
673+ expect ( items [ items . length - 1 ] . focus ) . toHaveBeenCalled ( ) ;
674+ expect ( event . defaultPrevented ) . toBe ( true ) ;
675+ flush ( ) ;
676+ } ) ) ;
677+
678+ it ( 'should not focus the last item when pressing end with a modifier key' , fakeAsync ( ( ) => {
679+ const fixture = createComponent ( SimpleMenu , [ ] , [ FakeIcon ] ) ;
680+ fixture . detectChanges ( ) ;
681+
682+ fixture . componentInstance . trigger . openMenu ( ) ;
683+ fixture . detectChanges ( ) ;
684+
685+ const panel = overlayContainerElement . querySelector ( '.mat-menu-panel' ) ! ;
686+ const items = Array . from ( panel . querySelectorAll ( '.mat-menu-item' ) ) as HTMLElement [ ] ;
687+ items . forEach ( patchElementFocus ) ;
688+
689+ spyOn ( items [ items . length - 1 ] , 'focus' ) . and . callThrough ( ) ;
690+
691+ const event = createKeyboardEvent ( 'keydown' , END ) ;
692+ Object . defineProperty ( event , 'altKey' , { get : ( ) => true } ) ;
693+
694+ dispatchEvent ( panel , event ) ;
695+ fixture . detectChanges ( ) ;
696+
697+ expect ( items [ items . length - 1 ] . focus ) . not . toHaveBeenCalled ( ) ;
698+ expect ( event . defaultPrevented ) . toBe ( false ) ;
699+ flush ( ) ;
700+ } ) ) ;
701+
604702 describe ( 'lazy rendering' , ( ) => {
605703 it ( 'should be able to render the menu content lazily' , fakeAsync ( ( ) => {
606704 const fixture = createComponent ( SimpleLazyMenu ) ;
0 commit comments