@@ -2,12 +2,12 @@ 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' ;
7
+ import { MatListModule , MatListOption , MatSelectionList , MatSelectionListChange } from './index' ;
8
+ import { FormControl , FormsModule , NgModel , ReactiveFormsModule } from '@angular/forms' ;
8
9
9
-
10
- describe ( 'MatSelectionList' , ( ) => {
10
+ describe ( 'MatSelectionList without forms' , ( ) => {
11
11
describe ( 'with list option' , ( ) => {
12
12
let fixture : ComponentFixture < SelectionListWithListOptions > ;
13
13
let listOptions : DebugElement [ ] ;
@@ -61,6 +61,28 @@ describe('MatSelectionList', () => {
61
61
} ) ;
62
62
} ) ;
63
63
64
+ it ( 'should not emit a change event if an option changed programmatically' , ( ) => {
65
+ spyOn ( fixture . componentInstance , 'onValueChange' ) ;
66
+
67
+ expect ( fixture . componentInstance . onValueChange ) . toHaveBeenCalledTimes ( 0 ) ;
68
+
69
+ listOptions [ 2 ] . componentInstance . toggle ( ) ;
70
+ fixture . detectChanges ( ) ;
71
+
72
+ expect ( fixture . componentInstance . onValueChange ) . toHaveBeenCalledTimes ( 0 ) ;
73
+ } ) ;
74
+
75
+ it ( 'should not emit a change event if an option got clicked' , ( ) => {
76
+ spyOn ( fixture . componentInstance , 'onValueChange' ) ;
77
+
78
+ expect ( fixture . componentInstance . onValueChange ) . toHaveBeenCalledTimes ( 0 ) ;
79
+
80
+ dispatchFakeEvent ( listOptions [ 2 ] . nativeElement , 'click' ) ;
81
+ fixture . detectChanges ( ) ;
82
+
83
+ expect ( fixture . componentInstance . onValueChange ) . toHaveBeenCalledTimes ( 1 ) ;
84
+ } ) ;
85
+
64
86
it ( 'should be able to dispatch one selected item' , ( ) => {
65
87
let testListItem = listOptions [ 2 ] . injector . get < MatListOption > ( MatListOption ) ;
66
88
let selectList =
@@ -480,90 +502,167 @@ describe('MatSelectionList', () => {
480
502
expect ( listItemContent . nativeElement . classList ) . toContain ( 'mat-list-item-content-reverse' ) ;
481
503
} ) ;
482
504
} ) ;
505
+ } ) ;
483
506
507
+ describe ( 'MatSelectionList with forms' , ( ) => {
484
508
485
- describe ( 'with multiple values' , ( ) => {
486
- let fixture : ComponentFixture < SelectionListWithMultipleValues > ;
487
- let listOption : DebugElement [ ] ;
488
- let listItemEl : DebugElement ;
489
- let selectionList : DebugElement ;
509
+ beforeEach ( async ( ( ) => {
510
+ TestBed . configureTestingModule ( {
511
+ imports : [ MatListModule , FormsModule , ReactiveFormsModule ] ,
512
+ declarations : [
513
+ SelectionListWithModel ,
514
+ SelectionListWithFormControl
515
+ ]
516
+ } ) ;
490
517
491
- beforeEach ( async ( ( ) => {
492
- TestBed . configureTestingModule ( {
493
- imports : [ MatListModule ] ,
494
- declarations : [
495
- SelectionListWithMultipleValues
496
- ] ,
497
- } ) ;
518
+ TestBed . compileComponents ( ) ;
519
+ } ) ) ;
498
520
499
- TestBed . compileComponents ( ) ;
521
+ describe ( 'and ngModel' , ( ) => {
522
+ let fixture : ComponentFixture < SelectionListWithModel > ;
523
+ let selectionListDebug : DebugElement ;
524
+ let selectionList : MatSelectionList ;
525
+ let listOptions : MatListOption [ ] ;
526
+ let ngModel : NgModel ;
527
+
528
+ beforeEach ( ( ) => {
529
+ fixture = TestBed . createComponent ( SelectionListWithModel ) ;
530
+ fixture . detectChanges ( ) ;
531
+
532
+ selectionListDebug = fixture . debugElement . query ( By . directive ( MatSelectionList ) ) ;
533
+ selectionList = selectionListDebug . componentInstance ;
534
+ ngModel = selectionListDebug . injector . get < NgModel > ( NgModel ) ;
535
+ listOptions = fixture . debugElement . queryAll ( By . directive ( MatListOption ) )
536
+ . map ( optionDebugEl => optionDebugEl . componentInstance ) ;
537
+ } ) ;
538
+
539
+ it ( 'should update the model if an option got selected programmatically' , fakeAsync ( ( ) => {
540
+ expect ( fixture . componentInstance . selectedOptions . length )
541
+ . toBe ( 0 , 'Expected no options to be selected by default' ) ;
542
+
543
+ listOptions [ 0 ] . toggle ( ) ;
544
+ fixture . detectChanges ( ) ;
545
+
546
+ tick ( ) ;
547
+
548
+ expect ( fixture . componentInstance . selectedOptions . length )
549
+ . toBe ( 1 , 'Expected first list option to be selected' ) ;
500
550
} ) ) ;
501
551
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 ) ) ;
552
+ it ( 'should update the model if an option got clicked' , fakeAsync ( ( ) => {
553
+ expect ( fixture . componentInstance . selectedOptions . length )
554
+ . toBe ( 0 , 'Expected no options to be selected by default' ) ;
555
+
556
+ dispatchFakeEvent ( listOptions [ 0 ] . _getHostElement ( ) , 'click' ) ;
507
557
fixture . detectChanges ( ) ;
558
+
559
+ tick ( ) ;
560
+
561
+ expect ( fixture . componentInstance . selectedOptions . length )
562
+ . toBe ( 1 , 'Expected first list option to be selected' ) ;
508
563
} ) ) ;
509
564
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
- } ) ;
565
+ it ( 'should update the options if a model value is set' , fakeAsync ( ( ) => {
566
+ expect ( fixture . componentInstance . selectedOptions . length )
567
+ . toBe ( 0 , 'Expected no options to be selected by default' ) ;
515
568
516
- } ) ;
569
+ fixture . componentInstance . selectedOptions = [ 'opt3' ] ;
570
+ fixture . detectChanges ( ) ;
517
571
518
- describe ( 'with option selected events' , ( ) => {
519
- let fixture : ComponentFixture < SelectionListWithOptionEvents > ;
520
- let testComponent : SelectionListWithOptionEvents ;
521
- let listOption : DebugElement [ ] ;
522
- let selectionList : DebugElement ;
572
+ tick ( ) ;
523
573
524
- beforeEach ( async ( ( ) => {
525
- TestBed . configureTestingModule ( {
526
- imports : [ MatListModule ] ,
527
- declarations : [
528
- SelectionListWithOptionEvents
529
- ] ,
530
- } ) ;
574
+ expect ( fixture . componentInstance . selectedOptions . length )
575
+ . toBe ( 1 , 'Expected first list option to be selected' ) ;
576
+ } ) ) ;
531
577
532
- TestBed . compileComponents ( ) ;
578
+ it ( 'should set the selection-list to touched on blur' , fakeAsync ( ( ) => {
579
+ expect ( ngModel . touched )
580
+ . toBe ( false , 'Expected the selection-list to be untouched by default.' ) ;
581
+
582
+ dispatchFakeEvent ( selectionListDebug . nativeElement , 'blur' ) ;
583
+ fixture . detectChanges ( ) ;
584
+
585
+ tick ( ) ;
586
+
587
+ expect ( ngModel . touched ) . toBe ( true , 'Expected the selection-list to be touched after blur' ) ;
533
588
} ) ) ;
534
589
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 ) ) ;
590
+ it ( 'should be pristine by default' , fakeAsync ( ( ) => {
591
+ fixture = TestBed . createComponent ( SelectionListWithModel ) ;
592
+ fixture . componentInstance . selectedOptions = [ 'opt2' ] ;
540
593
fixture . detectChanges ( ) ;
594
+
595
+ ngModel =
596
+ fixture . debugElement . query ( By . directive ( MatSelectionList ) ) . injector . get < NgModel > ( NgModel ) ;
597
+ listOptions = fixture . debugElement . queryAll ( By . directive ( MatListOption ) )
598
+ . map ( optionDebugEl => optionDebugEl . componentInstance ) ;
599
+
600
+ // Flush the initial tick to ensure that every action from the ControlValueAccessor
601
+ // happened before the actual test starts.
602
+ tick ( ) ;
603
+
604
+ expect ( ngModel . pristine )
605
+ . toBe ( true , 'Expected the selection-list to be pristine by default.' ) ;
606
+
607
+ listOptions [ 1 ] . toggle ( ) ;
608
+ fixture . detectChanges ( ) ;
609
+
610
+ tick ( ) ;
611
+
612
+ expect ( ngModel . pristine )
613
+ . toBe ( false , 'Expected the selection-list to be dirty after state change.' ) ;
541
614
} ) ) ;
615
+ } ) ;
616
+
617
+ describe ( 'and formControl' , ( ) => {
618
+ let fixture : ComponentFixture < SelectionListWithFormControl > ;
619
+ let selectionListDebug : DebugElement ;
620
+ let selectionList : MatSelectionList ;
621
+ let listOptions : MatListOption [ ] ;
542
622
543
- it ( 'should trigger the selected and deselected events when clicked in succession.' , ( ) => {
623
+ beforeEach ( ( ) => {
624
+ fixture = TestBed . createComponent ( SelectionListWithFormControl ) ;
625
+ fixture . detectChanges ( ) ;
544
626
545
- let selected : boolean = false ;
627
+ selectionListDebug = fixture . debugElement . query ( By . directive ( MatSelectionList ) ) ;
628
+ selectionList = selectionListDebug . componentInstance ;
629
+ listOptions = fixture . debugElement . queryAll ( By . directive ( MatListOption ) )
630
+ . map ( optionDebugEl => optionDebugEl . componentInstance ) ;
631
+ } ) ;
546
632
547
- spyOn ( testComponent , 'onOptionSelectionChange' )
548
- . and . callFake ( ( event : MatListOptionChange ) => {
549
- selected = event . selected ;
550
- } ) ;
633
+ it ( 'should be able to disable options from the control' , ( ) => {
634
+ expect ( listOptions . every ( option => ! option . disabled ) )
635
+ . toBe ( true , 'Expected every list option to be enabled.' ) ;
551
636
552
- listOption [ 0 ] . nativeElement . click ( ) ;
553
- expect ( testComponent . onOptionSelectionChange ) . toHaveBeenCalledTimes ( 1 ) ;
554
- expect ( selected ) . toBe ( true ) ;
637
+ fixture . componentInstance . formControl . disable ( ) ;
638
+ fixture . detectChanges ( ) ;
555
639
556
- listOption [ 0 ] . nativeElement . click ( ) ;
557
- expect ( testComponent . onOptionSelectionChange ) . toHaveBeenCalledTimes ( 2 ) ;
558
- expect ( selected ) . toBe ( false ) ;
640
+ expect ( listOptions . every ( option => option . disabled ) )
641
+ . toBe ( true , 'Expected every list option to be disabled.' ) ;
559
642
} ) ;
560
643
561
- } ) ;
644
+ it ( 'should be able to set the value through the form control' , ( ) => {
645
+ expect ( listOptions . every ( option => ! option . selected ) )
646
+ . toBe ( true , 'Expected every list option to be unselected.' ) ;
647
+
648
+ fixture . componentInstance . formControl . setValue ( [ 'opt2' , 'opt3' ] ) ;
649
+ fixture . detectChanges ( ) ;
650
+
651
+ expect ( listOptions [ 1 ] . selected ) . toBe ( true , 'Expected second option to be selected.' ) ;
652
+ expect ( listOptions [ 2 ] . selected ) . toBe ( true , 'Expected third option to be selected.' ) ;
653
+
654
+ fixture . componentInstance . formControl . setValue ( null ) ;
655
+ fixture . detectChanges ( ) ;
562
656
657
+ expect ( listOptions . every ( option => ! option . selected ) )
658
+ . toBe ( true , 'Expected every list option to be unselected.' ) ;
659
+ } ) ;
660
+ } ) ;
563
661
} ) ;
564
662
663
+
565
664
@Component ( { template : `
566
- <mat-selection-list id="selection-list-1">
665
+ <mat-selection-list id="selection-list-1" (change)="onValueChange($event)" >
567
666
<mat-list-option checkboxPosition="before" disabled="true" value="inbox">
568
667
Inbox (disabled selection-option)
569
668
</mat-list-option>
@@ -580,6 +679,8 @@ describe('MatSelectionList', () => {
580
679
</mat-selection-list>` } )
581
680
class SelectionListWithListOptions {
582
681
showLastOption : boolean = true ;
682
+
683
+ onValueChange ( _change : MatSelectionListChange ) { }
583
684
}
584
685
585
686
@Component ( { template : `
@@ -656,27 +757,27 @@ class SelectionListWithTabindexBinding {
656
757
disabled : boolean ;
657
758
}
658
759
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 {
760
+ @Component ( {
761
+ template : `
762
+ <mat-selection-list [(ngModel)]="selectedOptions">
763
+ <mat-list-option value="opt1">Option 1</mat-list-option>
764
+ <mat-list-option value="opt2">Option 2</mat-list-option>
765
+ <mat-list-option value="opt3">Option 3</mat-list-option>
766
+ </mat-selection-list>`
767
+ } )
768
+ class SelectionListWithModel {
769
+ selectedOptions : string [ ] = [ ] ;
672
770
}
673
771
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 = ( ) => { } ;
772
+ @Component ( {
773
+ template : `
774
+ <mat-selection-list [formControl]="formControl">
775
+ <mat-list-option value="opt1">Option 1</mat-list-option>
776
+ <mat-list-option value="opt2">Option 2</mat-list-option>
777
+ <mat-list-option value="opt3">Option 3</mat-list-option>
778
+ </mat-selection-list>
779
+ `
780
+ } )
781
+ class SelectionListWithFormControl {
782
+ formControl = new FormControl ( ) ;
682
783
}
0 commit comments