@@ -9,6 +9,7 @@ import {FormControl, ReactiveFormsModule} from '@angular/forms';
99import { Subscription } from 'rxjs/Subscription' ;
1010import { ENTER , DOWN_ARROW , SPACE } from '../core/keyboard/keycodes' ;
1111import { MdOption } from '../core/option/option' ;
12+ import { ViewportRuler } from '../core/overlay/position/viewport-ruler' ;
1213
1314describe ( 'MdAutocomplete' , ( ) => {
1415 let overlayContainerElement : HTMLElement ;
@@ -35,6 +36,7 @@ describe('MdAutocomplete', () => {
3536 { provide : Dir , useFactory : ( ) => {
3637 return { value : dir } ;
3738 } } ,
39+ { provide : ViewportRuler , useClass : FakeViewportRuler }
3840 ]
3941 } ) ;
4042
@@ -392,8 +394,8 @@ describe('MdAutocomplete', () => {
392394 } ) ;
393395
394396 describe ( 'aria' , ( ) => {
395- let fixture : ComponentFixture < SimpleAutocomplete > ;
396- let input : HTMLInputElement ;
397+ let fixture : ComponentFixture < SimpleAutocomplete > ;
398+ let input : HTMLInputElement ;
397399
398400 beforeEach ( ( ) => {
399401 fixture = TestBed . createComponent ( SimpleAutocomplete ) ;
@@ -477,6 +479,77 @@ describe('MdAutocomplete', () => {
477479
478480 expect ( input . getAttribute ( 'aria-owns' ) )
479481 . toEqual ( panel . getAttribute ( 'id' ) , 'Expected aria-owns to match attached autocomplete.' ) ;
482+
483+ } ) ;
484+
485+ } ) ;
486+
487+ describe ( 'Fallback positions' , ( ) => {
488+ let fixture : ComponentFixture < SimpleAutocomplete > ;
489+ let input : HTMLInputElement ;
490+
491+ beforeEach ( ( ) => {
492+ fixture = TestBed . createComponent ( SimpleAutocomplete ) ;
493+ fixture . detectChanges ( ) ;
494+
495+ input = fixture . debugElement . query ( By . css ( 'input' ) ) . nativeElement ;
496+ } ) ;
497+
498+ it ( 'should use below positioning by default' , ( ) => {
499+ fixture . componentInstance . trigger . openPanel ( ) ;
500+ fixture . detectChanges ( ) ;
501+
502+ const inputBottom = input . getBoundingClientRect ( ) . bottom ;
503+ const panel = overlayContainerElement . querySelector ( '.md-autocomplete-panel' ) ;
504+ const panelTop = panel . getBoundingClientRect ( ) . top ;
505+
506+ // Panel is offset by 6px in styles so that the underline has room to display.
507+ expect ( ( inputBottom + 6 ) . toFixed ( 2 ) )
508+ . toEqual ( panelTop . toFixed ( 2 ) , `Expected panel top to match input bottom by default.` ) ;
509+ expect ( fixture . componentInstance . trigger . autocomplete . positionY )
510+ . toEqual ( 'below' , `Expected autocomplete positionY to default to below.` ) ;
511+ } ) ;
512+
513+ it ( 'should fall back to above position if panel cannot fit below' , ( ) => {
514+ // Push the autocomplete trigger down so it won't have room to open "below"
515+ input . style . top = '400px' ;
516+ input . style . position = 'relative' ;
517+
518+ fixture . componentInstance . trigger . openPanel ( ) ;
519+ fixture . detectChanges ( ) ;
520+
521+ const inputTop = input . getBoundingClientRect ( ) . top ;
522+ const panel = overlayContainerElement . querySelector ( '.md-autocomplete-panel' ) ;
523+ const panelBottom = panel . getBoundingClientRect ( ) . bottom ;
524+
525+ // Panel is offset by 24px in styles so that the label has room to display.
526+ expect ( ( inputTop - 24 ) . toFixed ( 2 ) )
527+ . toEqual ( panelBottom . toFixed ( 2 ) , `Expected panel to fall back to above position.` ) ;
528+ expect ( fixture . componentInstance . trigger . autocomplete . positionY )
529+ . toEqual ( 'above' , `Expected autocomplete positionY to be "above" if panel won't fit.` ) ;
530+ } ) ;
531+
532+ it ( 'should align panel properly when filtering in "above" position' , ( ) => {
533+ // Push the autocomplete trigger down so it won't have room to open "below"
534+ input . style . top = '400px' ;
535+ input . style . position = 'relative' ;
536+
537+ fixture . componentInstance . trigger . openPanel ( ) ;
538+ fixture . detectChanges ( ) ;
539+
540+ input . value = 'f' ;
541+ dispatchEvent ( 'input' , input ) ;
542+ fixture . detectChanges ( ) ;
543+
544+ const inputTop = input . getBoundingClientRect ( ) . top ;
545+ const panel = overlayContainerElement . querySelector ( '.md-autocomplete-panel' ) ;
546+ const panelBottom = panel . getBoundingClientRect ( ) . bottom ;
547+
548+ // Panel is offset by 24px in styles so that the label has room to display.
549+ expect ( ( inputTop - 24 ) . toFixed ( 2 ) )
550+ . toEqual ( panelBottom . toFixed ( 2 ) , `Expected panel to stay aligned after filtering.` ) ;
551+ expect ( fixture . componentInstance . trigger . autocomplete . positionY )
552+ . toEqual ( 'above' , `Expected autocomplete positionY to be "above" if panel won't fit.` ) ;
480553 } ) ;
481554
482555 } ) ;
@@ -553,5 +626,15 @@ class FakeKeyboardEvent {
553626 preventDefault ( ) { }
554627}
555628
629+ class FakeViewportRuler {
630+ getViewportRect ( ) {
631+ return {
632+ left : 0 , top : 0 , width : 500 , height : 500 , bottom : 500 , right : 500
633+ } ;
634+ }
556635
636+ getViewportScrollPosition ( ) {
637+ return { top : 0 , left : 0 } ;
638+ }
639+ }
557640
0 commit comments