11import  { MutationObserverFactory }  from  '@angular/cdk/observers' ; 
22import  { dispatchFakeEvent }  from  '@angular/cdk/testing' ; 
33import  { Component }  from  '@angular/core' ; 
4- import  { ComponentFixture ,  fakeAsync ,  flushMicrotasks ,  TestBed ,  tick }  from  '@angular/core/testing' ; 
4+ import  { 
5+   ComponentFixture , 
6+   fakeAsync , 
7+   flush , 
8+   flushMicrotasks , 
9+   TestBed , 
10+   tick , 
11+ }  from  '@angular/core/testing' ; 
512import  { FormControl ,  FormsModule ,  NgModel ,  ReactiveFormsModule }  from  '@angular/forms' ; 
613import  { defaultRippleAnimationConfig }  from  '@angular/material/core' ; 
714import  { By ,  HAMMER_GESTURE_CONFIG }  from  '@angular/platform-browser' ; 
@@ -773,7 +780,7 @@ describe('MatSlideToggle with forms', () => {
773780      expect ( slideToggleElement . classList ) . toContain ( 'mat-checked' ) ; 
774781    } ) ) ; 
775782
776-     it ( 'should have the correct control state initially and after interaction' ,  ( )  =>  { 
783+     it ( 'should have the correct control state initially and after interaction' ,  fakeAsync ( ( )  =>  { 
777784      // The control should start off valid, pristine, and untouched. 
778785      expect ( slideToggleModel . valid ) . toBe ( true ) ; 
779786      expect ( slideToggleModel . pristine ) . toBe ( true ) ; 
@@ -795,13 +802,31 @@ describe('MatSlideToggle with forms', () => {
795802      // also turn touched. 
796803      dispatchFakeEvent ( inputElement ,  'blur' ) ; 
797804      fixture . detectChanges ( ) ; 
805+       flushMicrotasks ( ) ; 
798806
799807      expect ( slideToggleModel . valid ) . toBe ( true ) ; 
800808      expect ( slideToggleModel . pristine ) . toBe ( false ) ; 
801809      expect ( slideToggleModel . touched ) . toBe ( true ) ; 
802-     } ) ; 
810+     } ) ) ; 
811+ 
812+     it ( 'should not throw an error when disabling while focused' ,  fakeAsync ( ( )  =>  { 
813+       expect ( ( )  =>  { 
814+         // Focus the input element because after disabling, the `blur` event should automatically 
815+         // fire and not result in a changed after checked exception. Related: #12323 
816+         inputElement . focus ( ) ; 
817+ 
818+         // Flush the two nested timeouts from the FocusMonitor that are being created on `focus`. 
819+         flush ( ) ; 
820+ 
821+         slideToggle . disabled  =  true ; 
822+         fixture . detectChanges ( ) ; 
823+         flushMicrotasks ( ) ; 
824+       } ) . not . toThrow ( ) ; 
825+     } ) ) ; 
826+ 
827+     it ( 'should not set the control to touched when changing the state programmatically' , 
828+         fakeAsync ( ( )  =>  { 
803829
804-     it ( 'should not set the control to touched when changing the state programmatically' ,  ( )  =>  { 
805830      // The control should start off with being untouched. 
806831      expect ( slideToggleModel . touched ) . toBe ( false ) ; 
807832
@@ -815,10 +840,11 @@ describe('MatSlideToggle with forms', () => {
815840      // also turn touched. 
816841      dispatchFakeEvent ( inputElement ,  'blur' ) ; 
817842      fixture . detectChanges ( ) ; 
843+       flushMicrotasks ( ) ; 
818844
819845      expect ( slideToggleModel . touched ) . toBe ( true ) ; 
820846      expect ( slideToggleElement . classList ) . toContain ( 'mat-checked' ) ; 
821-     } ) ; 
847+     } ) ) ; 
822848
823849    it ( 'should not set the control to touched when changing the model' ,  fakeAsync ( ( )  =>  { 
824850      // The control should start off with being untouched. 
0 commit comments