@@ -2,12 +2,18 @@ import {DOWN_ARROW, SPACE, UP_ARROW} from '@angular/cdk/keycodes';
2
2
import { Platform } from '@angular/cdk/platform' ;
3
3
import { createKeyboardEvent , dispatchFakeEvent } from '@angular/cdk/testing' ;
4
4
import { Component , DebugElement } from '@angular/core' ;
5
- import { async , ComponentFixture , inject , TestBed } from '@angular/core/testing' ;
5
+ import { async , ComponentFixture , fakeAsync , inject , TestBed , tick } from '@angular/core/testing' ;
6
6
import { By } from '@angular/platform-browser' ;
7
- import { MatListModule , MatListOption , MatSelectionList , MatListOptionChange } from './index' ;
8
-
9
-
10
- describe ( 'MatSelectionList' , ( ) => {
7
+ import {
8
+ MatListModule ,
9
+ MatListOption ,
10
+ MatListOptionChange ,
11
+ MatSelectionList ,
12
+ MatSelectionListChange
13
+ } from './index' ;
14
+ import { FormControl , FormsModule , NgModel , ReactiveFormsModule } from '@angular/forms' ;
15
+
16
+ describe ( 'MatSelectionList without forms' , ( ) => {
11
17
describe ( 'with list option' , ( ) => {
12
18
let fixture : ComponentFixture < SelectionListWithListOptions > ;
13
19
let listOptions : DebugElement [ ] ;
@@ -61,6 +67,44 @@ describe('MatSelectionList', () => {
61
67
} ) ;
62
68
} ) ;
63
69
70
+ it ( 'should not emit a selectionChange event if an option changed programmatically' , ( ) => {
71
+ spyOn ( fixture . componentInstance , 'onValueChange' ) ;
72
+
73
+ expect ( fixture . componentInstance . onValueChange ) . toHaveBeenCalledTimes ( 0 ) ;
74
+
75
+ listOptions [ 2 ] . componentInstance . toggle ( ) ;
76
+ fixture . detectChanges ( ) ;
77
+
78
+ expect ( fixture . componentInstance . onValueChange ) . toHaveBeenCalledTimes ( 0 ) ;
79
+ } ) ;
80
+
81
+ it ( 'should emit a selectionChange event if an option got clicked' , ( ) => {
82
+ spyOn ( fixture . componentInstance , 'onValueChange' ) ;
83
+
84
+ expect ( fixture . componentInstance . onValueChange ) . toHaveBeenCalledTimes ( 0 ) ;
85
+
86
+ dispatchFakeEvent ( listOptions [ 2 ] . nativeElement , 'click' ) ;
87
+ fixture . detectChanges ( ) ;
88
+
89
+ expect ( fixture . componentInstance . onValueChange ) . toHaveBeenCalledTimes ( 1 ) ;
90
+ } ) ;
91
+
92
+ it ( 'should emit a deprecated selectionChange event on the list option that got clicked' , ( ) => {
93
+ const optionInstance = listOptions [ 2 ] . componentInstance as MatListOption ;
94
+ let lastChangeEvent : MatListOptionChange | null = null ;
95
+
96
+ optionInstance . selectionChange . subscribe ( ev => lastChangeEvent = ev ) ;
97
+
98
+ expect ( lastChangeEvent ) . toBeNull ( ) ;
99
+
100
+ dispatchFakeEvent ( listOptions [ 2 ] . nativeElement , 'click' ) ;
101
+ fixture . detectChanges ( ) ;
102
+
103
+ expect ( lastChangeEvent ) . not . toBeNull ( ) ;
104
+ expect ( lastChangeEvent ! . source ) . toBe ( optionInstance ) ;
105
+ expect ( lastChangeEvent ! . selected ) . toBe ( true ) ;
106
+ } ) ;
107
+
64
108
it ( 'should be able to dispatch one selected item' , ( ) => {
65
109
let testListItem = listOptions [ 2 ] . injector . get < MatListOption > ( MatListOption ) ;
66
110
let selectList =
@@ -480,90 +524,167 @@ describe('MatSelectionList', () => {
480
524
expect ( listItemContent . nativeElement . classList ) . toContain ( 'mat-list-item-content-reverse' ) ;
481
525
} ) ;
482
526
} ) ;
527
+ } ) ;
483
528
529
+ describe ( 'MatSelectionList with forms' , ( ) => {
484
530
485
- describe ( 'with multiple values' , ( ) => {
486
- let fixture : ComponentFixture < SelectionListWithMultipleValues > ;
487
- let listOption : DebugElement [ ] ;
488
- let listItemEl : DebugElement ;
489
- let selectionList : DebugElement ;
531
+ beforeEach ( async ( ( ) => {
532
+ TestBed . configureTestingModule ( {
533
+ imports : [ MatListModule , FormsModule , ReactiveFormsModule ] ,
534
+ declarations : [
535
+ SelectionListWithModel ,
536
+ SelectionListWithFormControl
537
+ ]
538
+ } ) ;
490
539
491
- beforeEach ( async ( ( ) => {
492
- TestBed . configureTestingModule ( {
493
- imports : [ MatListModule ] ,
494
- declarations : [
495
- SelectionListWithMultipleValues
496
- ] ,
497
- } ) ;
540
+ TestBed . compileComponents ( ) ;
541
+ } ) ) ;
498
542
499
- TestBed . compileComponents ( ) ;
543
+ describe ( 'and ngModel' , ( ) => {
544
+ let fixture : ComponentFixture < SelectionListWithModel > ;
545
+ let selectionListDebug : DebugElement ;
546
+ let selectionList : MatSelectionList ;
547
+ let listOptions : MatListOption [ ] ;
548
+ let ngModel : NgModel ;
549
+
550
+ beforeEach ( ( ) => {
551
+ fixture = TestBed . createComponent ( SelectionListWithModel ) ;
552
+ fixture . detectChanges ( ) ;
553
+
554
+ selectionListDebug = fixture . debugElement . query ( By . directive ( MatSelectionList ) ) ;
555
+ selectionList = selectionListDebug . componentInstance ;
556
+ ngModel = selectionListDebug . injector . get < NgModel > ( NgModel ) ;
557
+ listOptions = fixture . debugElement . queryAll ( By . directive ( MatListOption ) )
558
+ . map ( optionDebugEl => optionDebugEl . componentInstance ) ;
559
+ } ) ;
560
+
561
+ it ( 'should update the model if an option got selected programmatically' , fakeAsync ( ( ) => {
562
+ expect ( fixture . componentInstance . selectedOptions . length )
563
+ . toBe ( 0 , 'Expected no options to be selected by default' ) ;
564
+
565
+ listOptions [ 0 ] . toggle ( ) ;
566
+ fixture . detectChanges ( ) ;
567
+
568
+ tick ( ) ;
569
+
570
+ expect ( fixture . componentInstance . selectedOptions . length )
571
+ . toBe ( 1 , 'Expected first list option to be selected' ) ;
500
572
} ) ) ;
501
573
502
- beforeEach ( async ( ( ) => {
503
- fixture = TestBed . createComponent ( SelectionListWithMultipleValues ) ;
504
- listOption = fixture . debugElement . queryAll ( By . directive ( MatListOption ) ) ;
505
- listItemEl = fixture . debugElement . query ( By . css ( '.mat-list-item' ) ) ;
506
- selectionList = fixture . debugElement . query ( By . directive ( MatSelectionList ) ) ;
574
+ it ( 'should update the model if an option got clicked' , fakeAsync ( ( ) => {
575
+ expect ( fixture . componentInstance . selectedOptions . length )
576
+ . toBe ( 0 , 'Expected no options to be selected by default' ) ;
577
+
578
+ dispatchFakeEvent ( listOptions [ 0 ] . _getHostElement ( ) , 'click' ) ;
507
579
fixture . detectChanges ( ) ;
580
+
581
+ tick ( ) ;
582
+
583
+ expect ( fixture . componentInstance . selectedOptions . length )
584
+ . toBe ( 1 , 'Expected first list option to be selected' ) ;
508
585
} ) ) ;
509
586
510
- it ( 'should have a value for each item' , ( ) => {
511
- expect ( listOption [ 0 ] . componentInstance . value ) . toBe ( 1 ) ;
512
- expect ( listOption [ 1 ] . componentInstance . value ) . toBe ( 'a' ) ;
513
- expect ( listOption [ 2 ] . componentInstance . value ) . toBe ( true ) ;
514
- } ) ;
587
+ it ( 'should update the options if a model value is set' , fakeAsync ( ( ) => {
588
+ expect ( fixture . componentInstance . selectedOptions . length )
589
+ . toBe ( 0 , 'Expected no options to be selected by default' ) ;
515
590
516
- } ) ;
591
+ fixture . componentInstance . selectedOptions = [ 'opt3' ] ;
592
+ fixture . detectChanges ( ) ;
517
593
518
- describe ( 'with option selected events' , ( ) => {
519
- let fixture : ComponentFixture < SelectionListWithOptionEvents > ;
520
- let testComponent : SelectionListWithOptionEvents ;
521
- let listOption : DebugElement [ ] ;
522
- let selectionList : DebugElement ;
594
+ tick ( ) ;
523
595
524
- beforeEach ( async ( ( ) => {
525
- TestBed . configureTestingModule ( {
526
- imports : [ MatListModule ] ,
527
- declarations : [
528
- SelectionListWithOptionEvents
529
- ] ,
530
- } ) ;
596
+ expect ( fixture . componentInstance . selectedOptions . length )
597
+ . toBe ( 1 , 'Expected first list option to be selected' ) ;
598
+ } ) ) ;
531
599
532
- TestBed . compileComponents ( ) ;
600
+ it ( 'should set the selection-list to touched on blur' , fakeAsync ( ( ) => {
601
+ expect ( ngModel . touched )
602
+ . toBe ( false , 'Expected the selection-list to be untouched by default.' ) ;
603
+
604
+ dispatchFakeEvent ( selectionListDebug . nativeElement , 'blur' ) ;
605
+ fixture . detectChanges ( ) ;
606
+
607
+ tick ( ) ;
608
+
609
+ expect ( ngModel . touched ) . toBe ( true , 'Expected the selection-list to be touched after blur' ) ;
533
610
} ) ) ;
534
611
535
- beforeEach ( async ( ( ) => {
536
- fixture = TestBed . createComponent ( SelectionListWithOptionEvents ) ;
537
- testComponent = fixture . debugElement . componentInstance ;
538
- listOption = fixture . debugElement . queryAll ( By . directive ( MatListOption ) ) ;
539
- selectionList = fixture . debugElement . query ( By . directive ( MatSelectionList ) ) ;
612
+ it ( 'should be pristine by default' , fakeAsync ( ( ) => {
613
+ fixture = TestBed . createComponent ( SelectionListWithModel ) ;
614
+ fixture . componentInstance . selectedOptions = [ 'opt2' ] ;
615
+ fixture . detectChanges ( ) ;
616
+
617
+ ngModel =
618
+ fixture . debugElement . query ( By . directive ( MatSelectionList ) ) . injector . get < NgModel > ( NgModel ) ;
619
+ listOptions = fixture . debugElement . queryAll ( By . directive ( MatListOption ) )
620
+ . map ( optionDebugEl => optionDebugEl . componentInstance ) ;
621
+
622
+ // Flush the initial tick to ensure that every action from the ControlValueAccessor
623
+ // happened before the actual test starts.
624
+ tick ( ) ;
625
+
626
+ expect ( ngModel . pristine )
627
+ . toBe ( true , 'Expected the selection-list to be pristine by default.' ) ;
628
+
629
+ listOptions [ 1 ] . toggle ( ) ;
540
630
fixture . detectChanges ( ) ;
631
+
632
+ tick ( ) ;
633
+
634
+ expect ( ngModel . pristine )
635
+ . toBe ( false , 'Expected the selection-list to be dirty after state change.' ) ;
541
636
} ) ) ;
637
+ } ) ;
638
+
639
+ describe ( 'and formControl' , ( ) => {
640
+ let fixture : ComponentFixture < SelectionListWithFormControl > ;
641
+ let selectionListDebug : DebugElement ;
642
+ let selectionList : MatSelectionList ;
643
+ let listOptions : MatListOption [ ] ;
542
644
543
- it ( 'should trigger the selected and deselected events when clicked in succession.' , ( ) => {
645
+ beforeEach ( ( ) => {
646
+ fixture = TestBed . createComponent ( SelectionListWithFormControl ) ;
647
+ fixture . detectChanges ( ) ;
544
648
545
- let selected : boolean = false ;
649
+ selectionListDebug = fixture . debugElement . query ( By . directive ( MatSelectionList ) ) ;
650
+ selectionList = selectionListDebug . componentInstance ;
651
+ listOptions = fixture . debugElement . queryAll ( By . directive ( MatListOption ) )
652
+ . map ( optionDebugEl => optionDebugEl . componentInstance ) ;
653
+ } ) ;
546
654
547
- spyOn ( testComponent , 'onOptionSelectionChange' )
548
- . and . callFake ( ( event : MatListOptionChange ) => {
549
- selected = event . selected ;
550
- } ) ;
655
+ it ( 'should be able to disable options from the control' , ( ) => {
656
+ expect ( listOptions . every ( option => ! option . disabled ) )
657
+ . toBe ( true , 'Expected every list option to be enabled.' ) ;
551
658
552
- listOption [ 0 ] . nativeElement . click ( ) ;
553
- expect ( testComponent . onOptionSelectionChange ) . toHaveBeenCalledTimes ( 1 ) ;
554
- expect ( selected ) . toBe ( true ) ;
659
+ fixture . componentInstance . formControl . disable ( ) ;
660
+ fixture . detectChanges ( ) ;
555
661
556
- listOption [ 0 ] . nativeElement . click ( ) ;
557
- expect ( testComponent . onOptionSelectionChange ) . toHaveBeenCalledTimes ( 2 ) ;
558
- expect ( selected ) . toBe ( false ) ;
662
+ expect ( listOptions . every ( option => option . disabled ) )
663
+ . toBe ( true , 'Expected every list option to be disabled.' ) ;
559
664
} ) ;
560
665
561
- } ) ;
666
+ it ( 'should be able to set the value through the form control' , ( ) => {
667
+ expect ( listOptions . every ( option => ! option . selected ) )
668
+ . toBe ( true , 'Expected every list option to be unselected.' ) ;
669
+
670
+ fixture . componentInstance . formControl . setValue ( [ 'opt2' , 'opt3' ] ) ;
671
+ fixture . detectChanges ( ) ;
672
+
673
+ expect ( listOptions [ 1 ] . selected ) . toBe ( true , 'Expected second option to be selected.' ) ;
674
+ expect ( listOptions [ 2 ] . selected ) . toBe ( true , 'Expected third option to be selected.' ) ;
562
675
676
+ fixture . componentInstance . formControl . setValue ( null ) ;
677
+ fixture . detectChanges ( ) ;
678
+
679
+ expect ( listOptions . every ( option => ! option . selected ) )
680
+ . toBe ( true , 'Expected every list option to be unselected.' ) ;
681
+ } ) ;
682
+ } ) ;
563
683
} ) ;
564
684
685
+
565
686
@Component ( { template : `
566
- <mat-selection-list id="selection-list-1">
687
+ <mat-selection-list id="selection-list-1" (selectionChange)="onValueChange($event)" >
567
688
<mat-list-option checkboxPosition="before" disabled="true" value="inbox">
568
689
Inbox (disabled selection-option)
569
690
</mat-list-option>
@@ -580,6 +701,8 @@ describe('MatSelectionList', () => {
580
701
</mat-selection-list>` } )
581
702
class SelectionListWithListOptions {
582
703
showLastOption : boolean = true ;
704
+
705
+ onValueChange ( _change : MatSelectionListChange ) { }
583
706
}
584
707
585
708
@Component ( { template : `
@@ -656,27 +779,27 @@ class SelectionListWithTabindexBinding {
656
779
disabled : boolean ;
657
780
}
658
781
659
- @Component ( { template : `
660
- <mat-selection-list id="selection-list-5">
661
- <mat-list-option [value]="1" checkboxPosition="after">
662
- 1
663
- </mat-list-option>
664
- <mat-list-option value="a" checkboxPosition="after">
665
- a
666
- </mat-list-option>
667
- <mat-list-option [value]="true" checkboxPosition="after">
668
- true
669
- </mat-list-option>
670
- </mat-selection-list>` } )
671
- class SelectionListWithMultipleValues {
782
+ @Component ( {
783
+ template : `
784
+ <mat-selection-list [(ngModel)]="selectedOptions">
785
+ <mat-list-option value="opt1">Option 1</mat-list-option>
786
+ <mat-list-option value="opt2">Option 2</mat-list-option>
787
+ <mat-list-option value="opt3">Option 3</mat-list-option>
788
+ </mat-selection-list>`
789
+ } )
790
+ class SelectionListWithModel {
791
+ selectedOptions : string [ ] = [ ] ;
672
792
}
673
793
674
- @Component ( { template : `
675
- <mat-selection-list id="selection-list-6">
676
- <mat-list-option (selectionChange)="onOptionSelectionChange($event)">
677
- Inbox
678
- </mat-list-option>
679
- </mat-selection-list>` } )
680
- class SelectionListWithOptionEvents {
681
- onOptionSelectionChange : ( event ?: MatListOptionChange ) => void = ( ) => { } ;
794
+ @Component ( {
795
+ template : `
796
+ <mat-selection-list [formControl]="formControl">
797
+ <mat-list-option value="opt1">Option 1</mat-list-option>
798
+ <mat-list-option value="opt2">Option 2</mat-list-option>
799
+ <mat-list-option value="opt3">Option 3</mat-list-option>
800
+ </mat-selection-list>
801
+ `
802
+ } )
803
+ class SelectionListWithFormControl {
804
+ formControl = new FormControl ( ) ;
682
805
}
0 commit comments