88 dispatchMouseEvent ,
99} from '@angular/cdk/testing' ;
1010import { Component , ViewChild } from '@angular/core' ;
11- import { async , ComponentFixture , inject , TestBed } from '@angular/core/testing' ;
11+ import { async , ComponentFixture , inject , TestBed , fakeAsync , flush } from '@angular/core/testing' ;
1212import { FormControl , FormsModule , ReactiveFormsModule } from '@angular/forms' ;
1313import {
1414 DEC ,
@@ -63,6 +63,7 @@ describe('MatDatepicker', () => {
6363 NoInputDatepicker ,
6464 StandardDatepicker ,
6565 DatepickerWithEvents ,
66+ DatepickerOpeningOnFocus ,
6667 ] ,
6768 } ) ;
6869
@@ -248,7 +249,7 @@ describe('MatDatepicker', () => {
248249 } ) ;
249250
250251 it ( 'clicking the currently selected date should close the calendar ' +
251- 'without firing selectedChanged' , ( ) => {
252+ 'without firing selectedChanged' , fakeAsync ( ( ) => {
252253 const selectedChangedSpy =
253254 spyOn ( testComponent . datepicker . selectedChanged , 'emit' ) . and . callThrough ( ) ;
254255
@@ -263,12 +264,13 @@ describe('MatDatepicker', () => {
263264 let cells = document . querySelectorAll ( '.mat-calendar-body-cell' ) ;
264265 dispatchMouseEvent ( cells [ 1 ] , 'click' ) ;
265266 fixture . detectChanges ( ) ;
267+ flush ( ) ;
266268 }
267269
268270 expect ( selectedChangedSpy . calls . count ( ) ) . toEqual ( 1 ) ;
269271 expect ( document . querySelector ( 'mat-dialog-container' ) ) . toBeNull ( ) ;
270272 expect ( testComponent . datepickerInput . value ) . toEqual ( new Date ( 2020 , JAN , 2 ) ) ;
271- } ) ;
273+ } ) ) ;
272274
273275 it ( 'pressing enter on the currently selected date should close the calendar without ' +
274276 'firing selectedChanged' , ( ) => {
@@ -1020,18 +1022,65 @@ describe('MatDatepicker', () => {
10201022 expect ( testComponent . openedSpy ) . toHaveBeenCalled ( ) ;
10211023 } ) ;
10221024
1023- it ( 'should dispatch an event when a datepicker is closed' , ( ) => {
1025+ it ( 'should dispatch an event when a datepicker is closed' , fakeAsync ( ( ) => {
10241026 testComponent . datepicker . open ( ) ;
10251027 fixture . detectChanges ( ) ;
10261028
10271029 testComponent . datepicker . close ( ) ;
1030+ flush ( ) ;
10281031 fixture . detectChanges ( ) ;
10291032
10301033 expect ( testComponent . closedSpy ) . toHaveBeenCalled ( ) ;
1031- } ) ;
1034+ } ) ) ;
10321035
10331036 } ) ;
10341037
1038+ describe ( 'datepicker that opens on focus' , ( ) => {
1039+ let fixture : ComponentFixture < DatepickerOpeningOnFocus > ;
1040+ let testComponent : DatepickerOpeningOnFocus ;
1041+ let input : HTMLInputElement ;
1042+
1043+ beforeEach ( fakeAsync ( ( ) => {
1044+ fixture = TestBed . createComponent ( DatepickerOpeningOnFocus ) ;
1045+ fixture . detectChanges ( ) ;
1046+ testComponent = fixture . componentInstance ;
1047+ input = fixture . debugElement . query ( By . css ( 'input' ) ) . nativeElement ;
1048+ } ) ) ;
1049+
1050+ it ( 'should not reopen if the browser fires the focus event asynchronously' , fakeAsync ( ( ) => {
1051+ // Stub out the real focus method so we can call it reliably.
1052+ spyOn ( input , 'focus' ) . and . callFake ( ( ) => {
1053+ // Dispatch the event handler async to simulate the IE11 behavior.
1054+ Promise . resolve ( ) . then ( ( ) => dispatchFakeEvent ( input , 'focus' ) ) ;
1055+ } ) ;
1056+
1057+ // Open initially by focusing.
1058+ input . focus ( ) ;
1059+ fixture . detectChanges ( ) ;
1060+ flush ( ) ;
1061+
1062+ // Due to some browser limitations we can't install a stub on `document.activeElement`
1063+ // so instead we have to override the previously-focused element manually.
1064+ ( fixture . componentInstance . datepicker as any ) . _focusedElementBeforeOpen = input ;
1065+
1066+ // Ensure that the datepicker is actually open.
1067+ expect ( testComponent . datepicker . opened ) . toBe ( true , 'Expected datepicker to be open.' ) ;
1068+
1069+ // Close the datepicker.
1070+ testComponent . datepicker . close ( ) ;
1071+ fixture . detectChanges ( ) ;
1072+
1073+ // Schedule the input to be focused asynchronously.
1074+ input . focus ( ) ;
1075+ fixture . detectChanges ( ) ;
1076+
1077+ // Flush out the scheduled tasks.
1078+ flush ( ) ;
1079+
1080+ expect ( testComponent . datepicker . opened ) . toBe ( false , 'Expected datepicker to be closed.' ) ;
1081+ } ) ) ;
1082+ } ) ;
1083+
10351084 } ) ;
10361085
10371086 describe ( 'with missing DateAdapter and MAT_DATE_FORMATS' , ( ) => {
@@ -1390,3 +1439,14 @@ class DatepickerWithEvents {
13901439 closedSpy = jasmine . createSpy ( 'closed spy' ) ;
13911440 @ViewChild ( 'd' ) datepicker : MatDatepicker < Date > ;
13921441}
1442+
1443+
1444+ @Component ( {
1445+ template : `
1446+ <input (focus)="d.open()" [matDatepicker]="d">
1447+ <mat-datepicker #d="matDatepicker"></mat-datepicker>
1448+ ` ,
1449+ } )
1450+ class DatepickerOpeningOnFocus {
1451+ @ViewChild ( MatDatepicker ) datepicker : MatDatepicker < Date > ;
1452+ }
0 commit comments