@@ -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 ,
@@ -624,6 +624,104 @@ describe('MatMenu', () => {
624624 expect ( overlayContainerElement . textContent ) . toBe ( '' ) ;
625625 } ) ) ;
626626
627+ it ( 'should focus the first item when pressing home' , fakeAsync ( ( ) => {
628+ const fixture = createComponent ( SimpleMenu , [ ] , [ FakeIcon ] ) ;
629+ fixture . detectChanges ( ) ;
630+
631+ fixture . componentInstance . trigger . openMenu ( ) ;
632+ fixture . detectChanges ( ) ;
633+
634+ const panel = overlayContainerElement . querySelector ( '.mat-menu-panel' ) ! ;
635+ const items = Array . from ( panel . querySelectorAll ( '.mat-menu-item' ) ) as HTMLElement [ ] ;
636+ items . forEach ( patchElementFocus ) ;
637+
638+ // Focus the last item since focus starts from the first one.
639+ items [ items . length - 1 ] . focus ( ) ;
640+ fixture . detectChanges ( ) ;
641+
642+ spyOn ( items [ 0 ] , 'focus' ) . and . callThrough ( ) ;
643+
644+ const event = dispatchKeyboardEvent ( panel , 'keydown' , HOME ) ;
645+ fixture . detectChanges ( ) ;
646+
647+ expect ( items [ 0 ] . focus ) . toHaveBeenCalled ( ) ;
648+ expect ( event . defaultPrevented ) . toBe ( true ) ;
649+ flush ( ) ;
650+ } ) ) ;
651+
652+ it ( 'should not focus the first item when pressing home with a modifier key' , fakeAsync ( ( ) => {
653+ const fixture = createComponent ( SimpleMenu , [ ] , [ FakeIcon ] ) ;
654+ fixture . detectChanges ( ) ;
655+
656+ fixture . componentInstance . trigger . openMenu ( ) ;
657+ fixture . detectChanges ( ) ;
658+
659+ const panel = overlayContainerElement . querySelector ( '.mat-menu-panel' ) ! ;
660+ const items = Array . from ( panel . querySelectorAll ( '.mat-menu-item' ) ) as HTMLElement [ ] ;
661+ items . forEach ( patchElementFocus ) ;
662+
663+ // Focus the last item since focus starts from the first one.
664+ items [ items . length - 1 ] . focus ( ) ;
665+ fixture . detectChanges ( ) ;
666+
667+ spyOn ( items [ 0 ] , 'focus' ) . and . callThrough ( ) ;
668+
669+ const event = createKeyboardEvent ( 'keydown' , HOME ) ;
670+ Object . defineProperty ( event , 'altKey' , { get : ( ) => true } ) ;
671+
672+ dispatchEvent ( panel , event ) ;
673+ fixture . detectChanges ( ) ;
674+
675+ expect ( items [ 0 ] . focus ) . not . toHaveBeenCalled ( ) ;
676+ expect ( event . defaultPrevented ) . toBe ( false ) ;
677+ flush ( ) ;
678+ } ) ) ;
679+
680+ it ( 'should focus the last item when pressing end' , fakeAsync ( ( ) => {
681+ const fixture = createComponent ( SimpleMenu , [ ] , [ FakeIcon ] ) ;
682+ fixture . detectChanges ( ) ;
683+
684+ fixture . componentInstance . trigger . openMenu ( ) ;
685+ fixture . detectChanges ( ) ;
686+
687+ const panel = overlayContainerElement . querySelector ( '.mat-menu-panel' ) ! ;
688+ const items = Array . from ( panel . querySelectorAll ( '.mat-menu-item' ) ) as HTMLElement [ ] ;
689+ items . forEach ( patchElementFocus ) ;
690+
691+ spyOn ( items [ items . length - 1 ] , 'focus' ) . and . callThrough ( ) ;
692+
693+ const event = dispatchKeyboardEvent ( panel , 'keydown' , END ) ;
694+ fixture . detectChanges ( ) ;
695+
696+ expect ( items [ items . length - 1 ] . focus ) . toHaveBeenCalled ( ) ;
697+ expect ( event . defaultPrevented ) . toBe ( true ) ;
698+ flush ( ) ;
699+ } ) ) ;
700+
701+ it ( 'should not focus the last item when pressing end with a modifier key' , fakeAsync ( ( ) => {
702+ const fixture = createComponent ( SimpleMenu , [ ] , [ FakeIcon ] ) ;
703+ fixture . detectChanges ( ) ;
704+
705+ fixture . componentInstance . trigger . openMenu ( ) ;
706+ fixture . detectChanges ( ) ;
707+
708+ const panel = overlayContainerElement . querySelector ( '.mat-menu-panel' ) ! ;
709+ const items = Array . from ( panel . querySelectorAll ( '.mat-menu-item' ) ) as HTMLElement [ ] ;
710+ items . forEach ( patchElementFocus ) ;
711+
712+ spyOn ( items [ items . length - 1 ] , 'focus' ) . and . callThrough ( ) ;
713+
714+ const event = createKeyboardEvent ( 'keydown' , END ) ;
715+ Object . defineProperty ( event , 'altKey' , { get : ( ) => true } ) ;
716+
717+ dispatchEvent ( panel , event ) ;
718+ fixture . detectChanges ( ) ;
719+
720+ expect ( items [ items . length - 1 ] . focus ) . not . toHaveBeenCalled ( ) ;
721+ expect ( event . defaultPrevented ) . toBe ( false ) ;
722+ flush ( ) ;
723+ } ) ) ;
724+
627725 describe ( 'lazy rendering' , ( ) => {
628726 it ( 'should be able to render the menu content lazily' , fakeAsync ( ( ) => {
629727 const fixture = createComponent ( SimpleLazyMenu ) ;
0 commit comments