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