1- import { TestBed , async , ComponentFixture } from '@angular/core/testing' ;
1+ import { TestBed , async , fakeAsync , tick , ComponentFixture } from '@angular/core/testing' ;
22import { Component , OnDestroy , QueryList , ViewChild , ViewChildren } from '@angular/core' ;
33import { By } from '@angular/platform-browser' ;
44import { MdAutocompleteModule , MdAutocompleteTrigger } from './index' ;
@@ -518,97 +518,88 @@ describe('MdAutocomplete', () => {
518518 } ) ;
519519 } ) ) ;
520520
521- it ( 'should set the active item to the first option when DOWN key is pressed' , async ( ( ) => {
522- fixture . whenStable ( ) . then ( ( ) => {
523- const optionEls =
524- overlayContainerElement . querySelectorAll ( 'md-option' ) as NodeListOf < HTMLElement > ;
521+ it ( 'should set the active item to the first option when DOWN key is pressed' , fakeAsync ( ( ) => {
522+ tick ( ) ;
523+ const optionEls =
524+ overlayContainerElement . querySelectorAll ( 'md-option' ) as NodeListOf < HTMLElement > ;
525525
526- fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
526+ fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
527+ tick ( ) ;
528+ fixture . detectChanges ( ) ;
527529
528- fixture . whenStable ( ) . then ( ( ) => {
529- fixture . detectChanges ( ) ;
530- expect ( fixture . componentInstance . trigger . activeOption )
531- . toBe ( fixture . componentInstance . options . first , 'Expected first option to be active.' ) ;
532- expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ;
533- expect ( optionEls [ 1 ] . classList ) . not . toContain ( 'mat-active' ) ;
530+ expect ( fixture . componentInstance . trigger . activeOption )
531+ . toBe ( fixture . componentInstance . options . first , 'Expected first option to be active.' ) ;
532+ expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ;
533+ expect ( optionEls [ 1 ] . classList ) . not . toContain ( 'mat-active' ) ;
534534
535- fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
535+ fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
536+ tick ( ) ;
537+ fixture . detectChanges ( ) ;
536538
537- fixture . whenStable ( ) . then ( ( ) => {
538- fixture . detectChanges ( ) ;
539- expect ( fixture . componentInstance . trigger . activeOption )
540- . toBe ( fixture . componentInstance . options . toArray ( ) [ 1 ] ,
541- 'Expected second option to be active.' ) ;
542- expect ( optionEls [ 0 ] . classList ) . not . toContain ( 'mat-active' ) ;
543- expect ( optionEls [ 1 ] . classList ) . toContain ( 'mat-active' ) ;
544- } ) ;
545- } ) ;
546- } ) ;
539+ expect ( fixture . componentInstance . trigger . activeOption )
540+ . toBe ( fixture . componentInstance . options . toArray ( ) [ 1 ] ,
541+ 'Expected second option to be active.' ) ;
542+ expect ( optionEls [ 0 ] . classList ) . not . toContain ( 'mat-active' ) ;
543+ expect ( optionEls [ 1 ] . classList ) . toContain ( 'mat-active' ) ;
547544 } ) ) ;
548545
549- it ( 'should set the active item to the last option when UP key is pressed' , async ( ( ) => {
550- fixture . whenStable ( ) . then ( ( ) => {
551- const optionEls =
552- overlayContainerElement . querySelectorAll ( 'md-option' ) as NodeListOf < HTMLElement > ;
546+ it ( 'should set the active item to the last option when UP key is pressed' , fakeAsync ( ( ) => {
547+ tick ( ) ;
548+ const optionEls =
549+ overlayContainerElement . querySelectorAll ( 'md-option' ) as NodeListOf < HTMLElement > ;
553550
554- const UP_ARROW_EVENT = new MockKeyboardEvent ( UP_ARROW ) as KeyboardEvent ;
555- fixture . componentInstance . trigger . _handleKeydown ( UP_ARROW_EVENT ) ;
551+ const UP_ARROW_EVENT = new MockKeyboardEvent ( UP_ARROW ) as KeyboardEvent ;
552+ fixture . componentInstance . trigger . _handleKeydown ( UP_ARROW_EVENT ) ;
553+ tick ( ) ;
554+ fixture . detectChanges ( ) ;
556555
557- fixture . whenStable ( ) . then ( ( ) => {
558- fixture . detectChanges ( ) ;
559- expect ( fixture . componentInstance . trigger . activeOption )
560- . toBe ( fixture . componentInstance . options . last , 'Expected last option to be active.' ) ;
561- expect ( optionEls [ 10 ] . classList ) . toContain ( 'mat-active' ) ;
562- expect ( optionEls [ 0 ] . classList ) . not . toContain ( 'mat-active' ) ;
556+ expect ( fixture . componentInstance . trigger . activeOption )
557+ . toBe ( fixture . componentInstance . options . last , 'Expected last option to be active.' ) ;
558+ expect ( optionEls [ 10 ] . classList ) . toContain ( 'mat-active' ) ;
559+ expect ( optionEls [ 0 ] . classList ) . not . toContain ( 'mat-active' ) ;
563560
564- fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
561+ fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
562+ tick ( ) ;
563+ fixture . detectChanges ( ) ;
565564
566- fixture . whenStable ( ) . then ( ( ) => {
567- fixture . detectChanges ( ) ;
568- expect ( fixture . componentInstance . trigger . activeOption )
569- . toBe ( fixture . componentInstance . options . first ,
570- 'Expected first option to be active.' ) ;
571- expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ;
572- expect ( optionEls [ 10 ] . classList ) . not . toContain ( 'mat-active' ) ;
573- } ) ;
574- } ) ;
575- } ) ;
565+ expect ( fixture . componentInstance . trigger . activeOption )
566+ . toBe ( fixture . componentInstance . options . first ,
567+ 'Expected first option to be active.' ) ;
568+ expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ;
576569 } ) ) ;
577570
578- it ( 'should set the active item properly after filtering' , async ( ( ) => {
579- fixture . whenStable ( ) . then ( ( ) => {
580- fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
581- fixture . detectChanges ( ) ;
571+ it ( 'should set the active item properly after filtering' , fakeAsync ( ( ) => {
572+ fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
573+ tick ( ) ;
574+ fixture . detectChanges ( ) ;
582575
583- fixture . whenStable ( ) . then ( ( ) => {
584- typeInElement ( 'o' , input ) ;
585- fixture . detectChanges ( ) ;
576+ typeInElement ( 'o' , input ) ;
577+ fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
578+ tick ( ) ;
579+ fixture . detectChanges ( ) ;
586580
587- fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
581+ const optionEls =
582+ overlayContainerElement . querySelectorAll ( 'md-option' ) as NodeListOf < HTMLElement > ;
588583
589- fixture . whenStable ( ) . then ( ( ) => {
590- fixture . detectChanges ( ) ;
591- const optionEls =
592- overlayContainerElement . querySelectorAll ( 'md-option' ) as NodeListOf < HTMLElement > ;
593-
594- expect ( fixture . componentInstance . trigger . activeOption )
595- . toBe ( fixture . componentInstance . options . first ,
596- 'Expected first option to be active.' ) ;
597- expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ;
598- expect ( optionEls [ 1 ] . classList ) . not . toContain ( 'mat-active' ) ;
599- } ) ;
600- } ) ;
601- } ) ;
584+ expect ( fixture . componentInstance . trigger . activeOption )
585+ . toBe ( fixture . componentInstance . options . first ,
586+ 'Expected first option to be active.' ) ;
587+ expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ;
588+ expect ( optionEls [ 1 ] . classList ) . not . toContain ( 'mat-active' ) ;
602589 } ) ) ;
603590
604591 it ( 'should fill the text field when an option is selected with ENTER' , async ( ( ) => {
605592 fixture . whenStable ( ) . then ( ( ) => {
606593 fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
607- fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ;
608594
609- fixture . detectChanges ( ) ;
610- expect ( input . value )
611- . toContain ( 'Alabama' , `Expected text field to fill with selected value on ENTER.` ) ;
595+ fixture . whenStable ( ) . then ( ( ) => {
596+ fixture . detectChanges ( ) ;
597+
598+ fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ;
599+ fixture . detectChanges ( ) ;
600+ expect ( input . value )
601+ . toContain ( 'Alabama' , `Expected text field to fill with selected value on ENTER.` ) ;
602+ } ) ;
612603 } ) ;
613604 } ) ) ;
614605
@@ -619,11 +610,16 @@ describe('MdAutocomplete', () => {
619610
620611 const SPACE_EVENT = new MockKeyboardEvent ( SPACE ) as KeyboardEvent ;
621612 fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
622- fixture . componentInstance . trigger . _handleKeydown ( SPACE_EVENT ) ;
623- fixture . detectChanges ( ) ;
624613
625- expect ( input . value )
626- . not . toContain ( 'New York' , `Expected option not to be selected on SPACE.` ) ;
614+ fixture . whenStable ( ) . then ( ( ) => {
615+ fixture . detectChanges ( ) ;
616+
617+ fixture . componentInstance . trigger . _handleKeydown ( SPACE_EVENT ) ;
618+ fixture . detectChanges ( ) ;
619+
620+ expect ( input . value )
621+ . not . toContain ( 'New York' , `Expected option not to be selected on SPACE.` ) ;
622+ } ) ;
627623 } ) ;
628624 } ) ) ;
629625
@@ -633,54 +629,74 @@ describe('MdAutocomplete', () => {
633629 . toBe ( false , `Expected control to start out pristine.` ) ;
634630
635631 fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
636- fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ;
637- fixture . detectChanges ( ) ;
632+ fixture . whenStable ( ) . then ( ( ) => {
633+ fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ;
634+ fixture . detectChanges ( ) ;
638635
639- expect ( fixture . componentInstance . stateCtrl . dirty )
640- . toBe ( true , `Expected control to become dirty when option was selected by ENTER.` ) ;
636+ expect ( fixture . componentInstance . stateCtrl . dirty )
637+ . toBe ( true , `Expected control to become dirty when option was selected by ENTER.` ) ;
638+ } ) ;
641639 } ) ;
642640 } ) ) ;
643641
644642 it ( 'should open the panel again when typing after making a selection' , async ( ( ) => {
645643 fixture . whenStable ( ) . then ( ( ) => {
646644 fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
647- fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ;
648- fixture . detectChanges ( ) ;
645+ fixture . whenStable ( ) . then ( ( ) => {
646+ fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ;
647+ fixture . detectChanges ( ) ;
649648
650- expect ( fixture . componentInstance . trigger . panelOpen )
651- . toBe ( false , `Expected panel state to read closed after ENTER key.` ) ;
652- expect ( overlayContainerElement . textContent )
653- . toEqual ( '' , `Expected panel to close after ENTER key.` ) ;
649+ expect ( fixture . componentInstance . trigger . panelOpen )
650+ . toBe ( false , `Expected panel state to read closed after ENTER key.` ) ;
651+ expect ( overlayContainerElement . textContent )
652+ . toEqual ( '' , `Expected panel to close after ENTER key.` ) ;
654653
655- typeInElement ( 'Alabama' , input ) ;
656- fixture . detectChanges ( ) ;
654+ typeInElement ( 'Alabama' , input ) ;
655+ fixture . detectChanges ( ) ;
657656
658- expect ( fixture . componentInstance . trigger . panelOpen )
659- . toBe ( true , `Expected panel state to read open when typing in input.` ) ;
660- expect ( overlayContainerElement . textContent )
661- . toContain ( 'Alabama' , `Expected panel to display when typing in input.` ) ;
657+ expect ( fixture . componentInstance . trigger . panelOpen )
658+ . toBe ( true , `Expected panel state to read open when typing in input.` ) ;
659+ expect ( overlayContainerElement . textContent )
660+ . toContain ( 'Alabama' , `Expected panel to display when typing in input.` ) ;
661+ } ) ;
662662 } ) ;
663663 } ) ) ;
664664
665- it ( 'should scroll to active options below the fold' , async ( ( ) => {
666- fixture . whenStable ( ) . then ( ( ) => {
667- const scrollContainer = document . querySelector ( '.cdk-overlay-pane .mat-autocomplete-panel' ) ;
665+ it ( 'should scroll to active options below the fold' , fakeAsync ( ( ) => {
666+ tick ( ) ;
667+ const scrollContainer =
668+ document . querySelector ( '.cdk-overlay-pane .mat-autocomplete-panel' ) ;
668669
670+ fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
671+ tick ( ) ;
672+ fixture . detectChanges ( ) ;
673+ expect ( scrollContainer . scrollTop ) . toEqual ( 0 , `Expected panel not to scroll.` ) ;
674+
675+ // These down arrows will set the 6th option active, below the fold.
676+ [ 1 , 2 , 3 , 4 , 5 ] . forEach ( ( ) => {
669677 fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
670- fixture . detectChanges ( ) ;
671- expect ( scrollContainer . scrollTop ) . toEqual ( 0 , `Expected panel not to scroll.` ) ;
678+ tick ( ) ;
679+ } ) ;
672680
673- // These down arrows will set the 6th option active, below the fold.
674- [ 1 , 2 , 3 , 4 , 5 ] . forEach ( ( ) => {
675- fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
676- } ) ;
677- fixture . detectChanges ( ) ;
681+ // Expect option bottom minus the panel height (288 - 256 = 32)
682+ expect ( scrollContainer . scrollTop )
683+ . toEqual ( 32 , `Expected panel to reveal the sixth option.` ) ;
684+ } ) ) ;
678685
679- // Expect option bottom minus the panel height (288 - 256 = 32)
680- expect ( scrollContainer . scrollTop ) . toEqual ( 32 , `Expected panel to reveal the sixth option.` ) ;
681- } ) ;
686+ it ( 'should scroll to active options on UP arrow' , fakeAsync ( ( ) => {
687+ tick ( ) ;
688+ const scrollContainer =
689+ document . querySelector ( '.cdk-overlay-pane .mat-autocomplete-panel' ) ;
690+
691+ const UP_ARROW_EVENT = new MockKeyboardEvent ( UP_ARROW ) as KeyboardEvent ;
692+ fixture . componentInstance . trigger . _handleKeydown ( UP_ARROW_EVENT ) ;
693+ tick ( ) ;
694+ fixture . detectChanges ( ) ;
682695
696+ // Expect option bottom minus the panel height (528 - 256 = 272)
697+ expect ( scrollContainer . scrollTop ) . toEqual ( 272 , `Expected panel to reveal last option.` ) ;
683698 } ) ) ;
699+
684700 } ) ;
685701
686702 describe ( 'aria' , ( ) => {
@@ -728,18 +744,23 @@ describe('MdAutocomplete', () => {
728744
729745 const DOWN_ARROW_EVENT = new MockKeyboardEvent ( DOWN_ARROW ) as KeyboardEvent ;
730746 fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
731- fixture . detectChanges ( ) ;
732747
733- expect ( input . getAttribute ( 'aria-activedescendant' ) )
734- . toEqual ( fixture . componentInstance . options . first . id ,
735- 'Expected aria-activedescendant to match the active item after 1 down arrow.' ) ;
748+ fixture . whenStable ( ) . then ( ( ) => {
749+ fixture . detectChanges ( ) ;
750+ expect ( input . getAttribute ( 'aria-activedescendant' ) )
751+ . toEqual ( fixture . componentInstance . options . first . id ,
752+ 'Expected aria-activedescendant to match the active item after 1 down arrow.' ) ;
736753
737- fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
738- fixture . detectChanges ( ) ;
754+ fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
755+ fixture . whenStable ( ) . then ( ( ) => {
756+ fixture . detectChanges ( ) ;
757+
758+ expect ( input . getAttribute ( 'aria-activedescendant' ) )
759+ . toEqual ( fixture . componentInstance . options . toArray ( ) [ 1 ] . id ,
760+ 'Expected aria-activedescendant to match the active item after 2 down arrows.' ) ;
761+ } ) ;
762+ } ) ;
739763
740- expect ( input . getAttribute ( 'aria-activedescendant' ) )
741- . toEqual ( fixture . componentInstance . options . toArray ( ) [ 1 ] . id ,
742- 'Expected aria-activedescendant to match the active item after 2 down arrows.' ) ;
743764 } ) ;
744765 } ) ) ;
745766
@@ -879,6 +900,26 @@ describe('MdAutocomplete', () => {
879900 . toContain ( 'Two' , `Expected panel to display when input is focused.` ) ;
880901 } ) ;
881902
903+ it ( 'should filter properly with ngIf after setting the active item' , fakeAsync ( ( ) => {
904+ const fixture = TestBed . createComponent ( NgIfAutocomplete ) ;
905+ fixture . detectChanges ( ) ;
906+
907+ fixture . componentInstance . trigger . openPanel ( ) ;
908+ tick ( ) ;
909+ fixture . detectChanges ( ) ;
910+
911+ const DOWN_ARROW_EVENT = new MockKeyboardEvent ( DOWN_ARROW ) as KeyboardEvent ;
912+ fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ;
913+ tick ( ) ;
914+ fixture . detectChanges ( ) ;
915+
916+ const input = fixture . debugElement . query ( By . css ( 'input' ) ) . nativeElement ;
917+ typeInElement ( 'o' , input ) ;
918+ fixture . detectChanges ( ) ;
919+
920+ expect ( fixture . componentInstance . mdOptions . length ) . toBe ( 2 ) ;
921+ } ) ) ;
922+
882923 } ) ;
883924} ) ;
884925
@@ -956,9 +997,10 @@ class NgIfAutocomplete {
956997 optionCtrl = new FormControl ( ) ;
957998 filteredOptions : Observable < any > ;
958999 isVisible = true ;
1000+ options = [ 'One' , 'Two' , 'Three' ] ;
9591001
9601002 @ViewChild ( MdAutocompleteTrigger ) trigger : MdAutocompleteTrigger ;
961- options = [ 'One' , 'Two' , 'Three' ] ;
1003+ @ ViewChildren ( MdOption ) mdOptions : QueryList < MdOption > ;
9621004
9631005 constructor ( ) {
9641006 this . filteredOptions = this . optionCtrl . valueChanges . startWith ( null ) . map ( ( val ) => {
0 commit comments