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' ; 
@@ -523,97 +523,88 @@ describe('MdAutocomplete', () => {
523523      } ) ; 
524524    } ) ) ; 
525525
526-     it ( 'should set the active item to the first option when DOWN key is pressed' ,  async ( ( )  =>  { 
527-       fixture . whenStable ( ) . then ( ( )   =>   { 
528-          const  optionEls  = 
529-              overlayContainerElement . querySelectorAll ( 'md-option' )  as  NodeListOf < HTMLElement > ; 
526+     it ( 'should set the active item to the first option when DOWN key is pressed' ,  fakeAsync ( ( )  =>  { 
527+       tick ( ) ; 
528+       const  optionEls  = 
529+           overlayContainerElement . querySelectorAll ( 'md-option' )  as  NodeListOf < HTMLElement > ; 
530530
531-         fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
531+       fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
532+       tick ( ) ; 
533+       fixture . detectChanges ( ) ; 
532534
533-         fixture . whenStable ( ) . then ( ( )  =>  { 
534-           fixture . detectChanges ( ) ; 
535-           expect ( fixture . componentInstance . trigger . activeOption ) 
536-               . toBe ( fixture . componentInstance . options . first ,  'Expected first option to be active.' ) ; 
537-           expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ; 
538-           expect ( optionEls [ 1 ] . classList ) . not . toContain ( 'mat-active' ) ; 
535+       expect ( fixture . componentInstance . trigger . activeOption ) 
536+           . toBe ( fixture . componentInstance . options . first ,  'Expected first option to be active.' ) ; 
537+       expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ; 
538+       expect ( optionEls [ 1 ] . classList ) . not . toContain ( 'mat-active' ) ; 
539539
540-           fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
540+       fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
541+       tick ( ) ; 
542+       fixture . detectChanges ( ) ; 
541543
542-           fixture . whenStable ( ) . then ( ( )  =>  { 
543-             fixture . detectChanges ( ) ; 
544-             expect ( fixture . componentInstance . trigger . activeOption ) 
545-                 . toBe ( fixture . componentInstance . options . toArray ( ) [ 1 ] , 
546-                     'Expected second option to be active.' ) ; 
547-             expect ( optionEls [ 0 ] . classList ) . not . toContain ( 'mat-active' ) ; 
548-             expect ( optionEls [ 1 ] . classList ) . toContain ( 'mat-active' ) ; 
549-           } ) ; 
550-         } ) ; 
551-       } ) ; 
544+       expect ( fixture . componentInstance . trigger . activeOption ) 
545+           . toBe ( fixture . componentInstance . options . toArray ( ) [ 1 ] , 
546+               'Expected second option to be active.' ) ; 
547+       expect ( optionEls [ 0 ] . classList ) . not . toContain ( 'mat-active' ) ; 
548+       expect ( optionEls [ 1 ] . classList ) . toContain ( 'mat-active' ) ; 
552549    } ) ) ; 
553550
554-     it ( 'should set the active item to the last option when UP key is pressed' ,  async ( ( )  =>  { 
555-       fixture . whenStable ( ) . then ( ( )   =>   { 
556-          const  optionEls  = 
557-              overlayContainerElement . querySelectorAll ( 'md-option' )  as  NodeListOf < HTMLElement > ; 
551+     it ( 'should set the active item to the last option when UP key is pressed' ,  fakeAsync ( ( )  =>  { 
552+       tick ( ) ; 
553+       const  optionEls  = 
554+           overlayContainerElement . querySelectorAll ( 'md-option' )  as  NodeListOf < HTMLElement > ; 
558555
559-         const  UP_ARROW_EVENT  =  new  MockKeyboardEvent ( UP_ARROW )  as  KeyboardEvent ; 
560-         fixture . componentInstance . trigger . _handleKeydown ( UP_ARROW_EVENT ) ; 
556+       const  UP_ARROW_EVENT  =  new  MockKeyboardEvent ( UP_ARROW )  as  KeyboardEvent ; 
557+       fixture . componentInstance . trigger . _handleKeydown ( UP_ARROW_EVENT ) ; 
558+       tick ( ) ; 
559+       fixture . detectChanges ( ) ; 
561560
562-         fixture . whenStable ( ) . then ( ( )  =>  { 
563-           fixture . detectChanges ( ) ; 
564-           expect ( fixture . componentInstance . trigger . activeOption ) 
565-               . toBe ( fixture . componentInstance . options . last ,  'Expected last option to be active.' ) ; 
566-           expect ( optionEls [ 10 ] . classList ) . toContain ( 'mat-active' ) ; 
567-           expect ( optionEls [ 0 ] . classList ) . not . toContain ( 'mat-active' ) ; 
561+       expect ( fixture . componentInstance . trigger . activeOption ) 
562+           . toBe ( fixture . componentInstance . options . last ,  'Expected last option to be active.' ) ; 
563+       expect ( optionEls [ 10 ] . classList ) . toContain ( 'mat-active' ) ; 
564+       expect ( optionEls [ 0 ] . classList ) . not . toContain ( 'mat-active' ) ; 
568565
569-           fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
566+       fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
567+       tick ( ) ; 
568+       fixture . detectChanges ( ) ; 
570569
571-           fixture . whenStable ( ) . then ( ( )  =>  { 
572-             fixture . detectChanges ( ) ; 
573-             expect ( fixture . componentInstance . trigger . activeOption ) 
574-                 . toBe ( fixture . componentInstance . options . first , 
575-                     'Expected first option to be active.' ) ; 
576-             expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ; 
577-             expect ( optionEls [ 10 ] . classList ) . not . toContain ( 'mat-active' ) ; 
578-           } ) ; 
579-         } ) ; 
580-       } ) ; 
570+       expect ( fixture . componentInstance . trigger . activeOption ) 
571+           . toBe ( fixture . componentInstance . options . first , 
572+               'Expected first option to be active.' ) ; 
573+       expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ; 
581574    } ) ) ; 
582575
583-     it ( 'should set the active item properly after filtering' ,  async ( ( )  =>  { 
584-       fixture . whenStable ( ) . then ( ( )   =>   { 
585-          fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
586-          fixture . detectChanges ( ) ; 
576+     it ( 'should set the active item properly after filtering' ,  fakeAsync ( ( )  =>  { 
577+       fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
578+       tick ( ) ; 
579+       fixture . detectChanges ( ) ; 
587580
588-         fixture . whenStable ( ) . then ( ( )  =>  { 
589-           typeInElement ( 'o' ,  input ) ; 
590-           fixture . detectChanges ( ) ; 
581+       typeInElement ( 'o' ,  input ) ; 
582+       fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
583+       tick ( ) ; 
584+       fixture . detectChanges ( ) ; 
591585
592-           fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
586+       const  optionEls  = 
587+           overlayContainerElement . querySelectorAll ( 'md-option' )  as  NodeListOf < HTMLElement > ; 
593588
594-           fixture . whenStable ( ) . then ( ( )  =>  { 
595-             fixture . detectChanges ( ) ; 
596-             const  optionEls  = 
597-                 overlayContainerElement . querySelectorAll ( 'md-option' )  as  NodeListOf < HTMLElement > ; 
598- 
599-             expect ( fixture . componentInstance . trigger . activeOption ) 
600-                 . toBe ( fixture . componentInstance . options . first , 
601-                     'Expected first option to be active.' ) ; 
602-             expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ; 
603-             expect ( optionEls [ 1 ] . classList ) . not . toContain ( 'mat-active' ) ; 
604-           } ) ; 
605-         } ) ; 
606-       } ) ; 
589+       expect ( fixture . componentInstance . trigger . activeOption ) 
590+           . toBe ( fixture . componentInstance . options . first , 
591+               'Expected first option to be active.' ) ; 
592+       expect ( optionEls [ 0 ] . classList ) . toContain ( 'mat-active' ) ; 
593+       expect ( optionEls [ 1 ] . classList ) . not . toContain ( 'mat-active' ) ; 
607594    } ) ) ; 
608595
609596    it ( 'should fill the text field when an option is selected with ENTER' ,  async ( ( )  =>  { 
610597      fixture . whenStable ( ) . then ( ( )  =>  { 
611598        fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
612-         fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ; 
613599
614-         fixture . detectChanges ( ) ; 
615-         expect ( input . value ) 
616-             . toContain ( 'Alabama' ,  `Expected text field to fill with selected value on ENTER.` ) ; 
600+         fixture . whenStable ( ) . then ( ( )  =>  { 
601+           fixture . detectChanges ( ) ; 
602+ 
603+           fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ; 
604+           fixture . detectChanges ( ) ; 
605+           expect ( input . value ) 
606+               . toContain ( 'Alabama' ,  `Expected text field to fill with selected value on ENTER.` ) ; 
607+         } ) ; 
617608      } ) ; 
618609    } ) ) ; 
619610
@@ -624,11 +615,16 @@ describe('MdAutocomplete', () => {
624615
625616        const  SPACE_EVENT  =  new  MockKeyboardEvent ( SPACE )  as  KeyboardEvent ; 
626617        fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
627-         fixture . componentInstance . trigger . _handleKeydown ( SPACE_EVENT ) ; 
628-         fixture . detectChanges ( ) ; 
629618
630-         expect ( input . value ) 
631-             . not . toContain ( 'New York' ,  `Expected option not to be selected on SPACE.` ) ; 
619+         fixture . whenStable ( ) . then ( ( )  =>  { 
620+           fixture . detectChanges ( ) ; 
621+ 
622+           fixture . componentInstance . trigger . _handleKeydown ( SPACE_EVENT ) ; 
623+           fixture . detectChanges ( ) ; 
624+ 
625+           expect ( input . value ) 
626+               . not . toContain ( 'New York' ,  `Expected option not to be selected on SPACE.` ) ; 
627+         } ) ; 
632628      } ) ; 
633629    } ) ) ; 
634630
@@ -638,54 +634,74 @@ describe('MdAutocomplete', () => {
638634            . toBe ( false ,  `Expected control to start out pristine.` ) ; 
639635
640636        fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
641-         fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ; 
642-         fixture . detectChanges ( ) ; 
637+         fixture . whenStable ( ) . then ( ( )  =>  { 
638+           fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ; 
639+           fixture . detectChanges ( ) ; 
643640
644-         expect ( fixture . componentInstance . stateCtrl . dirty ) 
645-             . toBe ( true ,  `Expected control to become dirty when option was selected by ENTER.` ) ; 
641+           expect ( fixture . componentInstance . stateCtrl . dirty ) 
642+               . toBe ( true ,  `Expected control to become dirty when option was selected by ENTER.` ) ; 
643+         } ) ; 
646644      } ) ; 
647645    } ) ) ; 
648646
649647    it ( 'should open the panel again when typing after making a selection' ,  async ( ( )  =>  { 
650648      fixture . whenStable ( ) . then ( ( )  =>  { 
651649        fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
652-         fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ; 
653-         fixture . detectChanges ( ) ; 
650+         fixture . whenStable ( ) . then ( ( )  =>  { 
651+           fixture . componentInstance . trigger . _handleKeydown ( ENTER_EVENT ) ; 
652+           fixture . detectChanges ( ) ; 
654653
655-         expect ( fixture . componentInstance . trigger . panelOpen ) 
656-             . toBe ( false ,  `Expected panel state to read closed after ENTER key.` ) ; 
657-         expect ( overlayContainerElement . textContent ) 
658-             . toEqual ( '' ,  `Expected panel to close after ENTER key.` ) ; 
654+            expect ( fixture . componentInstance . trigger . panelOpen ) 
655+                . toBe ( false ,  `Expected panel state to read closed after ENTER key.` ) ; 
656+            expect ( overlayContainerElement . textContent ) 
657+                . toEqual ( '' ,  `Expected panel to close after ENTER key.` ) ; 
659658
660-         typeInElement ( 'Alabama' ,  input ) ; 
661-         fixture . detectChanges ( ) ; 
659+            typeInElement ( 'Alabama' ,  input ) ; 
660+            fixture . detectChanges ( ) ; 
662661
663-         expect ( fixture . componentInstance . trigger . panelOpen ) 
664-             . toBe ( true ,  `Expected panel state to read open when typing in input.` ) ; 
665-         expect ( overlayContainerElement . textContent ) 
666-             . toContain ( 'Alabama' ,  `Expected panel to display when typing in input.` ) ; 
662+           expect ( fixture . componentInstance . trigger . panelOpen ) 
663+               . toBe ( true ,  `Expected panel state to read open when typing in input.` ) ; 
664+           expect ( overlayContainerElement . textContent ) 
665+               . toContain ( 'Alabama' ,  `Expected panel to display when typing in input.` ) ; 
666+           } ) ; 
667667        } ) ; 
668668    } ) ) ; 
669669
670-     it ( 'should scroll to active options below the fold' ,  async ( ( )  =>  { 
671-       fixture . whenStable ( ) . then ( ( )  =>  { 
672-         const  scrollContainer  =  document . querySelector ( '.cdk-overlay-pane .mat-autocomplete-panel' ) ; 
670+     it ( 'should scroll to active options below the fold' ,  fakeAsync ( ( )  =>  { 
671+       tick ( ) ; 
672+       const  scrollContainer  = 
673+           document . querySelector ( '.cdk-overlay-pane .mat-autocomplete-panel' ) ; 
673674
675+       fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
676+       tick ( ) ; 
677+       fixture . detectChanges ( ) ; 
678+       expect ( scrollContainer . scrollTop ) . toEqual ( 0 ,  `Expected panel not to scroll.` ) ; 
679+ 
680+       // These down arrows will set the 6th option active, below the fold. 
681+       [ 1 ,  2 ,  3 ,  4 ,  5 ] . forEach ( ( )  =>  { 
674682        fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
675-         fixture . detectChanges ( ) ; 
676-          expect ( scrollContainer . scrollTop ) . toEqual ( 0 ,   `Expected panel not to scroll.` ) ; 
683+         tick ( ) ; 
684+       } ) ; 
677685
678-         // These down arrows will set the 6th option active, below the fold. 
679-         [ 1 ,  2 ,  3 ,  4 ,  5 ] . forEach ( ( )  =>  { 
680-           fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
681-         } ) ; 
682-         fixture . detectChanges ( ) ; 
686+       // Expect option bottom minus the panel height (288 - 256 = 32) 
687+       expect ( scrollContainer . scrollTop ) 
688+           . toEqual ( 32 ,  `Expected panel to reveal the sixth option.` ) ; 
689+     } ) ) ; 
683690
684-         // Expect option bottom minus the panel height (288 - 256 = 32) 
685-         expect ( scrollContainer . scrollTop ) . toEqual ( 32 ,  `Expected panel to reveal the sixth option.` ) ; 
686-       } ) ; 
691+     it ( 'should scroll to active options on UP arrow' ,  fakeAsync ( ( )  =>  { 
692+       tick ( ) ; 
693+       const  scrollContainer  = 
694+           document . querySelector ( '.cdk-overlay-pane .mat-autocomplete-panel' ) ; 
695+ 
696+       const  UP_ARROW_EVENT  =  new  MockKeyboardEvent ( UP_ARROW )  as  KeyboardEvent ; 
697+       fixture . componentInstance . trigger . _handleKeydown ( UP_ARROW_EVENT ) ; 
698+       tick ( ) ; 
699+       fixture . detectChanges ( ) ; 
687700
701+       // Expect option bottom minus the panel height (528 - 256 = 272) 
702+       expect ( scrollContainer . scrollTop ) . toEqual ( 272 ,  `Expected panel to reveal last option.` ) ; 
688703    } ) ) ; 
704+ 
689705  } ) ; 
690706
691707  describe ( 'aria' ,  ( )  =>  { 
@@ -733,18 +749,23 @@ describe('MdAutocomplete', () => {
733749
734750        const  DOWN_ARROW_EVENT  =  new  MockKeyboardEvent ( DOWN_ARROW )  as  KeyboardEvent ; 
735751        fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
736-         fixture . detectChanges ( ) ; 
737752
738-         expect ( input . getAttribute ( 'aria-activedescendant' ) ) 
739-             . toEqual ( fixture . componentInstance . options . first . id , 
740-                 'Expected aria-activedescendant to match the active item after 1 down arrow.' ) ; 
753+         fixture . whenStable ( ) . then ( ( )  =>  { 
754+           fixture . detectChanges ( ) ; 
755+           expect ( input . getAttribute ( 'aria-activedescendant' ) ) 
756+               . toEqual ( fixture . componentInstance . options . first . id , 
757+                   'Expected aria-activedescendant to match the active item after 1 down arrow.' ) ; 
741758
742-         fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
743-         fixture . detectChanges ( ) ; 
759+           fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
760+           fixture . whenStable ( ) . then ( ( )  =>  { 
761+             fixture . detectChanges ( ) ; 
762+ 
763+             expect ( input . getAttribute ( 'aria-activedescendant' ) ) 
764+                 . toEqual ( fixture . componentInstance . options . toArray ( ) [ 1 ] . id , 
765+                     'Expected aria-activedescendant to match the active item after 2 down arrows.' ) ; 
766+           } ) ; 
767+         } ) ; 
744768
745-         expect ( input . getAttribute ( 'aria-activedescendant' ) ) 
746-             . toEqual ( fixture . componentInstance . options . toArray ( ) [ 1 ] . id , 
747-                 'Expected aria-activedescendant to match the active item after 2 down arrows.' ) ; 
748769      } ) ; 
749770    } ) ) ; 
750771
@@ -896,6 +917,26 @@ describe('MdAutocomplete', () => {
896917          . toContain ( 'Two' ,  `Expected panel to display when input is focused.` ) ; 
897918    } ) ; 
898919
920+     it ( 'should filter properly with ngIf after setting the active item' ,  fakeAsync ( ( )  =>  { 
921+       const  fixture  =  TestBed . createComponent ( NgIfAutocomplete ) ; 
922+       fixture . detectChanges ( ) ; 
923+ 
924+       fixture . componentInstance . trigger . openPanel ( ) ; 
925+       tick ( ) ; 
926+       fixture . detectChanges ( ) ; 
927+ 
928+       const  DOWN_ARROW_EVENT  =  new  MockKeyboardEvent ( DOWN_ARROW )  as  KeyboardEvent ; 
929+       fixture . componentInstance . trigger . _handleKeydown ( DOWN_ARROW_EVENT ) ; 
930+       tick ( ) ; 
931+       fixture . detectChanges ( ) ; 
932+ 
933+       const  input  =  fixture . debugElement . query ( By . css ( 'input' ) ) . nativeElement ; 
934+       typeInElement ( 'o' ,  input ) ; 
935+       fixture . detectChanges ( ) ; 
936+ 
937+       expect ( fixture . componentInstance . mdOptions . length ) . toBe ( 2 ) ; 
938+     } ) ) ; 
939+ 
899940  } ) ; 
900941} ) ; 
901942
@@ -973,9 +1014,10 @@ class NgIfAutocomplete {
9731014  optionCtrl  =  new  FormControl ( ) ; 
9741015  filteredOptions : Observable < any > ; 
9751016  isVisible  =  true ; 
1017+   options  =  [ 'One' ,  'Two' ,  'Three' ] ; 
9761018
9771019  @ViewChild ( MdAutocompleteTrigger )  trigger : MdAutocompleteTrigger ; 
978-   options   =   [ 'One' ,   'Two' ,   'Three' ] ; 
1020+   @ ViewChildren ( MdOption )   mdOptions :  QueryList < MdOption > ; 
9791021
9801022  constructor ( )  { 
9811023    this . filteredOptions  =  this . optionCtrl . valueChanges . startWith ( null ) . map ( ( val )  =>  { 
0 commit comments