1
- import { ComponentFixture , fakeAsync , TestBed , tick , flush } from '@angular/core/testing' ;
1
+ import {
2
+ ComponentFixture ,
3
+ fakeAsync ,
4
+ TestBed ,
5
+ tick ,
6
+ flush ,
7
+ flushMicrotasks ,
8
+ } from '@angular/core/testing' ;
2
9
import { FormControl , FormsModule , NgModel , ReactiveFormsModule } from '@angular/forms' ;
3
10
import { Component , DebugElement , ViewChild , Type } from '@angular/core' ;
4
11
import { By } from '@angular/platform-browser' ;
@@ -873,29 +880,63 @@ describe('MatCheckbox', () => {
873
880
let checkboxNativeElement : HTMLElement ;
874
881
let checkboxInstance : MatCheckbox ;
875
882
let inputElement : HTMLInputElement ;
883
+ let ngModel : NgModel ;
876
884
877
885
beforeEach ( ( ) => {
878
- fixture = createComponent ( CheckboxWithFormDirectives ) ;
886
+ fixture = createComponent ( CheckboxWithNgModel ) ;
887
+
888
+ fixture . componentInstance . isRequired = false ;
879
889
fixture . detectChanges ( ) ;
880
890
881
891
checkboxDebugElement = fixture . debugElement . query ( By . directive ( MatCheckbox ) ) ;
882
892
checkboxNativeElement = checkboxDebugElement . nativeElement ;
883
893
checkboxInstance = checkboxDebugElement . componentInstance ;
884
894
inputElement = < HTMLInputElement > checkboxNativeElement . querySelector ( 'input' ) ;
895
+ ngModel = checkboxDebugElement . injector . get < NgModel > ( NgModel ) ;
885
896
} ) ;
886
897
887
- it ( 'should be in pristine, untouched, and valid states initially' , fakeAsync ( ( ) => {
888
- flush ( ) ;
889
-
890
- let checkboxElement = fixture . debugElement . query ( By . directive ( MatCheckbox ) ) ;
891
- let ngModel = checkboxElement . injector . get < NgModel > ( NgModel ) ;
892
-
898
+ it ( 'should be pristine, untouched, and valid initially' , ( ) => {
893
899
expect ( ngModel . valid ) . toBe ( true ) ;
894
900
expect ( ngModel . pristine ) . toBe ( true ) ;
895
901
expect ( ngModel . touched ) . toBe ( false ) ;
902
+ } ) ;
903
+
904
+ it ( 'should have correct control states after interaction' , fakeAsync ( ( ) => {
905
+ inputElement . click ( ) ;
906
+ fixture . detectChanges ( ) ;
907
+
908
+ // Flush the timeout that is being created whenever a `click` event has been fired by
909
+ // the underlying input.
910
+ flush ( ) ;
911
+
912
+ // After the value change through interaction, the control should be dirty, but remain
913
+ // untouched as long as the focus is still on the underlying input.
914
+ expect ( ngModel . pristine ) . toBe ( false ) ;
915
+ expect ( ngModel . touched ) . toBe ( false ) ;
896
916
897
- // TODO(jelbourn): test that `touched` and `pristine` state are modified appropriately.
898
- // This is currently blocked on issues with async() and fakeAsync().
917
+ // If the input element loses focus, the control should remain dirty but should
918
+ // also turn touched.
919
+ dispatchFakeEvent ( inputElement , 'blur' ) ;
920
+ fixture . detectChanges ( ) ;
921
+ flushMicrotasks ( ) ;
922
+
923
+ expect ( ngModel . pristine ) . toBe ( false ) ;
924
+ expect ( ngModel . touched ) . toBe ( true ) ;
925
+ } ) ) ;
926
+
927
+ it ( 'should not throw an error when disabling while focused' , fakeAsync ( ( ) => {
928
+ expect ( ( ) => {
929
+ // Focus the input element because after disabling, the `blur` event should automatically
930
+ // fire and not result in a changed after checked exception. Related: #12323
931
+ inputElement . focus ( ) ;
932
+
933
+ // Flush the two nested timeouts from the FocusMonitor that are being created on `focus`.
934
+ flush ( ) ;
935
+
936
+ checkboxInstance . disabled = true ;
937
+ fixture . detectChanges ( ) ;
938
+ flushMicrotasks ( ) ;
939
+ } ) . not . toThrow ( ) ;
899
940
} ) ) ;
900
941
901
942
it ( 'should toggle checked state on click' , ( ) => {
@@ -911,29 +952,9 @@ describe('MatCheckbox', () => {
911
952
912
953
expect ( checkboxInstance . checked ) . toBe ( false ) ;
913
954
} ) ;
914
- } ) ;
915
-
916
- describe ( 'with required ngModel' , ( ) => {
917
- let checkboxInstance : MatCheckbox ;
918
- let inputElement : HTMLInputElement ;
919
- let testComponent : CheckboxWithNgModel ;
920
-
921
- beforeEach ( ( ) => {
922
- fixture = createComponent ( CheckboxWithNgModel ) ;
923
- fixture . detectChanges ( ) ;
924
-
925
- let checkboxDebugElement = fixture . debugElement . query ( By . directive ( MatCheckbox ) ) ;
926
- let checkboxNativeElement = checkboxDebugElement . nativeElement ;
927
- testComponent = fixture . debugElement . componentInstance ;
928
- checkboxInstance = checkboxDebugElement . componentInstance ;
929
- inputElement = < HTMLInputElement > checkboxNativeElement . querySelector ( 'input' ) ;
930
- } ) ;
931
955
932
956
it ( 'should validate with RequiredTrue validator' , ( ) => {
933
- let checkboxElement = fixture . debugElement . query ( By . directive ( MatCheckbox ) ) ;
934
- let ngModel = checkboxElement . injector . get < NgModel > ( NgModel ) ;
935
-
936
- testComponent . isRequired = true ;
957
+ fixture . componentInstance . isRequired = true ;
937
958
inputElement . click ( ) ;
938
959
fixture . detectChanges ( ) ;
939
960
@@ -1124,18 +1145,6 @@ class SingleCheckbox {
1124
1145
onCheckboxChange : ( event ?: MatCheckboxChange ) => void = ( ) => { } ;
1125
1146
}
1126
1147
1127
- /** Simple component for testing an MatCheckbox with ngModel in a form. */
1128
- @Component ( {
1129
- template : `
1130
- <form>
1131
- <mat-checkbox name="cb" [(ngModel)]="isGood">Be good</mat-checkbox>
1132
- </form>
1133
- ` ,
1134
- } )
1135
- class CheckboxWithFormDirectives {
1136
- isGood : boolean = false ;
1137
- }
1138
-
1139
1148
/** Simple component for testing an MatCheckbox with required ngModel. */
1140
1149
@Component ( {
1141
1150
template : `<mat-checkbox [required]="isRequired" [(ngModel)]="isGood">Be good</mat-checkbox>` ,
0 commit comments