@@ -14,9 +14,8 @@ import {createKeyboardEvent} from '../../testing/private';
1414import { QueryList } from '@angular/core' ;
1515import { fakeAsync , tick } from '@angular/core/testing' ;
1616import { take } from 'rxjs/operators' ;
17- import { FocusOrigin } from '../focus-monitor/focus-monitor' ;
1817import { TreeKeyManager , TreeKeyManagerItem } from './tree-key-manager' ;
19- import { Observable , of as observableOf } from 'rxjs' ;
18+ import { Observable , of as observableOf , Subscription } from 'rxjs' ;
2019
2120class FakeBaseTreeKeyManagerItem {
2221 public _isExpanded = false ;
@@ -69,8 +68,9 @@ interface ItemConstructorTestContext {
6968}
7069
7170interface ExpandCollapseKeyEventTestContext {
72- expandKeyEvent : KeyboardEvent ;
73- collapseKeyEvent : KeyboardEvent ;
71+ direction : 'ltr' | 'rtl' ;
72+ expandKeyEvent : ( ) => KeyboardEvent ;
73+ collapseKeyEvent : ( ) => KeyboardEvent ;
7474}
7575
7676fdescribe ( 'TreeKeyManager' , ( ) => {
@@ -445,6 +445,298 @@ fdescribe('TreeKeyManager', () => {
445445 expect ( fakeKeyEvents . upArrow . defaultPrevented ) . toBe ( true ) ;
446446 } ) ;
447447 } ) ;
448+
449+ describe ( 'expand/collapse key events' , ( ) => {
450+ const parameters : ExpandCollapseKeyEventTestContext [ ] = [
451+ {
452+ direction : 'ltr' ,
453+ expandKeyEvent : ( ) => fakeKeyEvents . rightArrow ,
454+ collapseKeyEvent : ( ) => fakeKeyEvents . leftArrow ,
455+ } ,
456+ {
457+ direction : 'rtl' ,
458+ expandKeyEvent : ( ) => fakeKeyEvents . leftArrow ,
459+ collapseKeyEvent : ( ) => fakeKeyEvents . rightArrow ,
460+ } ,
461+ ] ;
462+
463+ for ( const param of parameters ) {
464+ describe ( `in ${ param . direction } mode` , ( ) => {
465+ beforeEach ( ( ) => {
466+ keyManager = new TreeKeyManager ( {
467+ items : itemList ,
468+ horizontalOrientation : param . direction ,
469+ } ) ;
470+ for ( const item of itemList ) {
471+ item . _isExpanded = false ;
472+ }
473+ } ) ;
474+
475+ it ( 'with nothing active, expand key does not expand any items' , ( ) => {
476+ expect ( itemList . toArray ( ) . map ( item => item . isExpanded ( ) ) )
477+ . withContext ( 'item expansion state, for all items' )
478+ . toEqual ( itemList . toArray ( ) . map ( _ => false ) ) ;
479+
480+ keyManager . onKeydown ( param . expandKeyEvent ( ) ) ;
481+
482+ expect ( itemList . toArray ( ) . map ( item => item . isExpanded ( ) ) )
483+ . withContext ( 'item expansion state, for all items, after expand event' )
484+ . toEqual ( itemList . toArray ( ) . map ( _ => false ) ) ;
485+ } ) ;
486+
487+ it ( 'with nothing active, collapse key does not collapse any items' , ( ) => {
488+ for ( const item of itemList ) {
489+ item . _isExpanded = true ;
490+ }
491+ expect ( itemList . toArray ( ) . map ( item => item . isExpanded ( ) ) )
492+ . withContext ( 'item expansion state, for all items' )
493+ . toEqual ( itemList . toArray ( ) . map ( _ => true ) ) ;
494+
495+ keyManager . onKeydown ( param . collapseKeyEvent ( ) ) ;
496+
497+ expect ( itemList . toArray ( ) . map ( item => item . isExpanded ( ) ) )
498+ . withContext ( 'item expansion state, for all items' )
499+ . toEqual ( itemList . toArray ( ) . map ( _ => true ) ) ;
500+ } ) ;
501+
502+ it ( 'with nothing active, expand key does not change the active item index' , ( ) => {
503+ expect ( keyManager . getActiveItemIndex ( ) )
504+ . withContext ( 'active item index, initial' )
505+ . toEqual ( - 1 ) ;
506+
507+ keyManager . onKeydown ( param . expandKeyEvent ( ) ) ;
508+
509+ expect ( keyManager . getActiveItemIndex ( ) )
510+ . withContext ( 'active item index, after expand event' )
511+ . toEqual ( - 1 ) ;
512+ } ) ;
513+
514+ it ( 'with nothing active, collapse key does not change the active item index' , ( ) => {
515+ for ( const item of itemList ) {
516+ item . _isExpanded = true ;
517+ }
518+
519+ expect ( keyManager . getActiveItemIndex ( ) )
520+ . withContext ( 'active item index, initial' )
521+ . toEqual ( - 1 ) ;
522+
523+ keyManager . onKeydown ( param . collapseKeyEvent ( ) ) ;
524+
525+ expect ( keyManager . getActiveItemIndex ( ) )
526+ . withContext ( 'active item index, after collapse event' )
527+ . toEqual ( - 1 ) ;
528+ } ) ;
529+
530+ describe ( 'if the current item is expanded' , ( ) => {
531+ let spy : jasmine . Spy ;
532+ let subscription : Subscription ;
533+
534+ beforeEach ( ( ) => {
535+ keyManager . onClick ( parentItem ) ;
536+ parentItem . _isExpanded = true ;
537+
538+ spy = jasmine . createSpy ( 'change spy' ) ;
539+ subscription = keyManager . change . subscribe ( spy ) ;
540+ } ) ;
541+
542+ afterEach ( ( ) => {
543+ subscription . unsubscribe ( ) ;
544+ } ) ;
545+
546+ it ( 'when the expand key is pressed, moves to the first child' , ( ) => {
547+ keyManager . onKeydown ( param . expandKeyEvent ( ) ) ;
548+
549+ expect ( keyManager . getActiveItemIndex ( ) )
550+ . withContext ( 'active item index, after one expand key event.' )
551+ . toBe ( 1 ) ;
552+ expect ( spy ) . not . toHaveBeenCalledWith ( parentItem ) ;
553+ expect ( spy ) . toHaveBeenCalledWith ( childItem ) ;
554+ } ) ;
555+
556+ it (
557+ 'when the expand key is pressed, and the first child is disabled, ' +
558+ 'moves to the first non-disabled child' ,
559+ ( ) => {
560+ childItem . isDisabled = true ;
561+
562+ keyManager . onKeydown ( param . expandKeyEvent ( ) ) ;
563+
564+ expect ( keyManager . getActiveItemIndex ( ) )
565+ . withContext ( 'active item index, after one expand key event.' )
566+ . toBe ( 3 ) ;
567+ expect ( spy ) . not . toHaveBeenCalledWith ( parentItem ) ;
568+ expect ( spy ) . not . toHaveBeenCalledWith ( childItem ) ;
569+ expect ( spy ) . toHaveBeenCalledWith ( childItemWithNoChildren ) ;
570+ } ,
571+ ) ;
572+
573+ it (
574+ 'when the expand key is pressed, and all children are disabled, ' +
575+ 'does not change the active item' ,
576+ ( ) => {
577+ childItem . isDisabled = true ;
578+ childItemWithNoChildren . isDisabled = true ;
579+
580+ keyManager . onKeydown ( param . expandKeyEvent ( ) ) ;
581+
582+ expect ( keyManager . getActiveItemIndex ( ) )
583+ . withContext ( 'active item index, after one expand key event.' )
584+ . toBe ( 0 ) ;
585+ expect ( spy ) . not . toHaveBeenCalled ( ) ;
586+ } ,
587+ ) ;
588+
589+ it ( 'when the collapse key is pressed, collapses the item' , ( ) => {
590+ expect ( parentItem . isExpanded ( ) )
591+ . withContext ( 'active item initial expansion state' )
592+ . toBe ( true ) ;
593+
594+ keyManager . onKeydown ( param . collapseKeyEvent ( ) ) ;
595+
596+ expect ( parentItem . isExpanded ( ) )
597+ . withContext ( 'active item expansion state, after collapse key' )
598+ . toBe ( false ) ;
599+ } ) ;
600+
601+ it ( 'when the collapse key is pressed, does not change the active item' , ( ) => {
602+ expect ( keyManager . getActiveItemIndex ( ) )
603+ . withContext ( 'active item index, initial' )
604+ . toBe ( 0 ) ;
605+
606+ keyManager . onKeydown ( param . collapseKeyEvent ( ) ) ;
607+
608+ expect ( keyManager . getActiveItemIndex ( ) )
609+ . withContext ( 'active item index, after one collapse key event.' )
610+ . toBe ( 0 ) ;
611+ expect ( spy ) . not . toHaveBeenCalled ( ) ;
612+ } ) ;
613+ } ) ;
614+
615+ describe ( 'if the current item is expanded, and there are no children' , ( ) => {
616+ let spy : jasmine . Spy ;
617+ let subscription : Subscription ;
618+
619+ beforeEach ( ( ) => {
620+ keyManager . onClick ( childItemWithNoChildren ) ;
621+ childItemWithNoChildren . _isExpanded = true ;
622+
623+ spy = jasmine . createSpy ( 'change spy' ) ;
624+ subscription = keyManager . change . subscribe ( spy ) ;
625+ } ) ;
626+
627+ afterEach ( ( ) => {
628+ subscription . unsubscribe ( ) ;
629+ } ) ;
630+
631+ it ( 'when the expand key is pressed, does not change the active item' , ( ) => {
632+ keyManager . onKeydown ( param . expandKeyEvent ( ) ) ;
633+
634+ expect ( keyManager . getActiveItemIndex ( ) )
635+ . withContext ( 'active item index, after one expand key event.' )
636+ . toBe ( 3 ) ;
637+ expect ( spy ) . not . toHaveBeenCalled ( ) ;
638+ } ) ;
639+ } ) ;
640+
641+ describe ( 'if the current item is collapsed, and has a parent item' , ( ) => {
642+ let spy : jasmine . Spy ;
643+ let subscription : Subscription ;
644+
645+ beforeEach ( ( ) => {
646+ keyManager . onClick ( childItem ) ;
647+ childItem . _isExpanded = false ;
648+
649+ spy = jasmine . createSpy ( 'change spy' ) ;
650+ subscription = keyManager . change . subscribe ( spy ) ;
651+ } ) ;
652+
653+ afterEach ( ( ) => {
654+ subscription . unsubscribe ( ) ;
655+ } ) ;
656+
657+ it ( 'when the expand key is pressed, expands the current item' , ( ) => {
658+ expect ( childItem . isExpanded ( ) )
659+ . withContext ( 'active item initial expansion state' )
660+ . toBe ( false ) ;
661+
662+ keyManager . onKeydown ( param . expandKeyEvent ( ) ) ;
663+
664+ expect ( childItem . isExpanded ( ) )
665+ . withContext ( 'active item expansion state, after expand key' )
666+ . toBe ( true ) ;
667+ } ) ;
668+
669+ it ( 'when the expand key is pressed, does not change active item' , ( ) => {
670+ expect ( keyManager . getActiveItemIndex ( ) )
671+ . withContext ( 'active item index, initial' )
672+ . toBe ( 1 ) ;
673+
674+ keyManager . onKeydown ( param . expandKeyEvent ( ) ) ;
675+
676+ expect ( keyManager . getActiveItemIndex ( ) )
677+ . withContext ( 'active item index, after one collapse key event.' )
678+ . toBe ( 1 ) ;
679+ expect ( spy ) . not . toHaveBeenCalled ( ) ;
680+ } ) ;
681+
682+ it ( 'when the collapse key is pressed, moves the active item to the parent' , ( ) => {
683+ expect ( keyManager . getActiveItemIndex ( ) )
684+ . withContext ( 'active item index, initial' )
685+ . toBe ( 1 ) ;
686+
687+ keyManager . onKeydown ( param . collapseKeyEvent ( ) ) ;
688+
689+ expect ( keyManager . getActiveItemIndex ( ) )
690+ . withContext ( 'active item index, after one collapse key event.' )
691+ . toBe ( 0 ) ;
692+ } ) ;
693+
694+ it ( 'when the collapse key is pressed, and the parent is disabled, does nothing' , ( ) => {
695+ expect ( keyManager . getActiveItemIndex ( ) )
696+ . withContext ( 'active item index, initial' )
697+ . toBe ( 1 ) ;
698+
699+ parentItem . isDisabled = true ;
700+ keyManager . onKeydown ( param . collapseKeyEvent ( ) ) ;
701+
702+ expect ( keyManager . getActiveItemIndex ( ) )
703+ . withContext ( 'active item index, after one collapse key event.' )
704+ . toBe ( 1 ) ;
705+ } ) ;
706+ } ) ;
707+
708+ describe ( 'if the current item is collapsed, and has no parent items' , ( ) => {
709+ let spy : jasmine . Spy ;
710+ let subscription : Subscription ;
711+
712+ beforeEach ( ( ) => {
713+ keyManager . onClick ( parentItem ) ;
714+ parentItem . _isExpanded = false ;
715+
716+ spy = jasmine . createSpy ( 'change spy' ) ;
717+ subscription = keyManager . change . subscribe ( spy ) ;
718+ } ) ;
719+
720+ afterEach ( ( ) => {
721+ subscription . unsubscribe ( ) ;
722+ } ) ;
723+
724+ it ( 'when the collapse key is pressed, does nothing' , ( ) => {
725+ expect ( keyManager . getActiveItemIndex ( ) )
726+ . withContext ( 'active item index, initial' )
727+ . toBe ( 0 ) ;
728+
729+ keyManager . onKeydown ( param . collapseKeyEvent ( ) ) ;
730+
731+ expect ( keyManager . getActiveItemIndex ( ) )
732+ . withContext ( 'active item index, after one collapse key event.' )
733+ . toBe ( 0 ) ;
734+ expect ( spy ) . not . toHaveBeenCalledWith ( parentItem ) ;
735+ } ) ;
736+ } ) ;
737+ } ) ;
738+ }
739+ } ) ;
448740 } ) ;
449741 }
450742
0 commit comments