@@ -24,9 +24,22 @@ import {dispatchFakeEvent} from '../core/testing/dispatch-events';
24
24
import { wrappedErrorMessage } from '../core/testing/wrapped-error-message' ;
25
25
26
26
27
+ class FakeViewportRuler {
28
+ getViewportRect ( ) {
29
+ return {
30
+ left : 0 , top : 0 , width : 1014 , height : 686 , bottom : 686 , right : 1014
31
+ } ;
32
+ }
33
+
34
+ getViewportScrollPosition ( ) {
35
+ return { top : 0 , left : 0 } ;
36
+ }
37
+ }
38
+
27
39
describe ( 'MdSelect' , ( ) => {
28
40
let overlayContainerElement : HTMLElement ;
29
41
let dir : { value : 'ltr' | 'rtl' } ;
42
+ let fakeViewportRuler = new FakeViewportRuler ( ) ;
30
43
31
44
beforeEach ( async ( ( ) => {
32
45
TestBed . configureTestingModule ( {
@@ -65,7 +78,7 @@ describe('MdSelect', () => {
65
78
{ provide : Dir , useFactory : ( ) => {
66
79
return dir = { value : 'ltr' } ;
67
80
} } ,
68
- { provide : ViewportRuler , useClass : FakeViewportRuler }
81
+ { provide : ViewportRuler , useValue : fakeViewportRuler }
69
82
]
70
83
} ) ;
71
84
@@ -661,12 +674,12 @@ describe('MdSelect', () => {
661
674
let trigger : HTMLElement ;
662
675
let select : HTMLElement ;
663
676
664
- beforeEach ( ( ) => {
677
+ beforeEach ( async ( ( ) => {
665
678
fixture = TestBed . createComponent ( BasicSelect ) ;
666
679
fixture . detectChanges ( ) ;
667
680
trigger = fixture . debugElement . query ( By . css ( '.mat-select-trigger' ) ) . nativeElement ;
668
681
select = fixture . debugElement . query ( By . css ( 'md-select' ) ) . nativeElement ;
669
- } ) ;
682
+ } ) ) ;
670
683
671
684
/**
672
685
* Asserts that the given option is aligned with the trigger.
@@ -882,6 +895,94 @@ describe('MdSelect', () => {
882
895
883
896
} ) ;
884
897
898
+ describe ( 'limited space to open horizontally' , ( ) => {
899
+ beforeEach ( async ( ( ) => {
900
+ select . style . position = 'absolute' ;
901
+ select . style . top = '200px' ;
902
+ } ) ) ;
903
+
904
+ it ( 'should stay within the viewport when overflowing on the left in ltr' , async ( ( ) => {
905
+ select . style . left = '-100px' ;
906
+ trigger . click ( ) ;
907
+ fixture . detectChanges ( ) ;
908
+
909
+ fixture . whenStable ( ) . then ( ( ) => {
910
+ const panelLeft = document . querySelector ( '.mat-select-panel' )
911
+ . getBoundingClientRect ( ) . left ;
912
+ expect ( panelLeft ) . toBeGreaterThan ( 0 ,
913
+ `Expected select panel to be inside the viewport in ltr.` ) ;
914
+ } ) ;
915
+ } ) ) ;
916
+
917
+ it ( 'should stay within the viewport when overflowing on the right in rtl' , async ( ( ) => {
918
+ dir . value = 'rtl' ;
919
+ select . style . left = '-100px' ;
920
+ trigger . click ( ) ;
921
+ fixture . detectChanges ( ) ;
922
+
923
+ fixture . whenStable ( ) . then ( ( ) => {
924
+ const panelLeft = document . querySelector ( '.mat-select-panel' )
925
+ . getBoundingClientRect ( ) . left ;
926
+
927
+ expect ( panelLeft ) . toBeGreaterThan ( 0 ,
928
+ `Expected select panel to be inside the viewport in rtl.` ) ;
929
+ } ) ;
930
+ } ) ) ;
931
+
932
+ it ( 'should stay within the viewport when overflowing on the right in ltr' , async ( ( ) => {
933
+ select . style . right = '-100px' ;
934
+ trigger . click ( ) ;
935
+ fixture . detectChanges ( ) ;
936
+
937
+ fixture . whenStable ( ) . then ( ( ) => {
938
+ const viewportRect = fakeViewportRuler . getViewportRect ( ) . right ;
939
+ const panelRight = document . querySelector ( '.mat-select-panel' )
940
+ . getBoundingClientRect ( ) . right ;
941
+
942
+ expect ( viewportRect - panelRight ) . toBeGreaterThan ( 0 ,
943
+ `Expected select panel to be inside the viewport in ltr.` ) ;
944
+ } ) ;
945
+ } ) ) ;
946
+
947
+ it ( 'should stay within the viewport when overflowing on the right in rtl' , async ( ( ) => {
948
+ dir . value = 'rtl' ;
949
+ select . style . right = '-100px' ;
950
+ trigger . click ( ) ;
951
+ fixture . detectChanges ( ) ;
952
+
953
+ fixture . whenStable ( ) . then ( ( ) => {
954
+ const viewportRect = fakeViewportRuler . getViewportRect ( ) . right ;
955
+ const panelRight = document . querySelector ( '.mat-select-panel' )
956
+ . getBoundingClientRect ( ) . right ;
957
+
958
+ expect ( viewportRect - panelRight ) . toBeGreaterThan ( 0 ,
959
+ `Expected select panel to be inside the viewport in rtl.` ) ;
960
+ } ) ;
961
+ } ) ) ;
962
+
963
+ it ( 'should keep the position within the viewport on repeat openings' , async ( ( ) => {
964
+ select . style . left = '-100px' ;
965
+ trigger . click ( ) ;
966
+ fixture . detectChanges ( ) ;
967
+
968
+ let panelLeft = document . querySelector ( '.mat-select-panel' ) . getBoundingClientRect ( ) . left ;
969
+
970
+ expect ( panelLeft ) . toBeGreaterThan ( 0 , `Expected select panel to be inside the viewport.` ) ;
971
+
972
+ fixture . componentInstance . select . close ( ) ;
973
+ fixture . detectChanges ( ) ;
974
+
975
+ fixture . whenStable ( ) . then ( ( ) => {
976
+ trigger . click ( ) ;
977
+ fixture . detectChanges ( ) ;
978
+ panelLeft = document . querySelector ( '.mat-select-panel' ) . getBoundingClientRect ( ) . left ;
979
+
980
+ expect ( panelLeft ) . toBeGreaterThan ( 0 ,
981
+ `Expected select panel continue being inside the viewport.` ) ;
982
+ } ) ;
983
+ } ) ) ;
984
+ } ) ;
985
+
885
986
describe ( 'when scrolled' , ( ) => {
886
987
887
988
// Need to set the scrollTop two different ways to support
@@ -1024,44 +1125,48 @@ describe('MdSelect', () => {
1024
1125
describe ( 'x-axis positioning in multi select mode' , ( ) => {
1025
1126
let multiFixture : ComponentFixture < MultiSelect > ;
1026
1127
1027
- beforeEach ( ( ) => {
1128
+ beforeEach ( async ( ( ) => {
1028
1129
multiFixture = TestBed . createComponent ( MultiSelect ) ;
1029
1130
multiFixture . detectChanges ( ) ;
1030
1131
trigger = multiFixture . debugElement . query ( By . css ( '.mat-select-trigger' ) ) . nativeElement ;
1031
1132
select = multiFixture . debugElement . query ( By . css ( 'md-select' ) ) . nativeElement ;
1032
1133
1033
- select . style . marginLeft = '20px ' ;
1034
- select . style . marginRight = '20px ' ;
1035
- } ) ;
1134
+ select . style . marginLeft = '50px ' ;
1135
+ select . style . marginRight = '50px ' ;
1136
+ } ) ) ;
1036
1137
1037
- it ( 'should adjust for the checkbox in ltr' , ( ) => {
1138
+ it ( 'should adjust for the checkbox in ltr' , async ( ( ) => {
1038
1139
trigger . click ( ) ;
1039
1140
multiFixture . detectChanges ( ) ;
1040
1141
1041
- const triggerLeft = trigger . getBoundingClientRect ( ) . left ;
1042
- const firstOptionLeft =
1043
- document . querySelector ( '.cdk-overlay-pane md-option' ) . getBoundingClientRect ( ) . left ;
1142
+ multiFixture . whenStable ( ) . then ( ( ) => {
1143
+ const triggerLeft = trigger . getBoundingClientRect ( ) . left ;
1144
+ const firstOptionLeft =
1145
+ document . querySelector ( '.cdk-overlay-pane md-option' ) . getBoundingClientRect ( ) . left ;
1044
1146
1045
- // 48px accounts for the checkbox size, margin and the panel's padding.
1046
- expect ( firstOptionLeft . toFixed ( 2 ) )
1047
- . toEqual ( ( triggerLeft - 48 ) . toFixed ( 2 ) ,
1048
- `Expected trigger label to align along x-axis, accounting for the checkbox.` ) ;
1049
- } ) ;
1147
+ // 48px accounts for the checkbox size, margin and the panel's padding.
1148
+ expect ( firstOptionLeft . toFixed ( 2 ) )
1149
+ . toEqual ( ( triggerLeft - 48 ) . toFixed ( 2 ) ,
1150
+ `Expected trigger label to align along x-axis, accounting for the checkbox.` ) ;
1151
+ } ) ;
1152
+ } ) ) ;
1050
1153
1051
- it ( 'should adjust for the checkbox in rtl' , ( ) => {
1154
+ it ( 'should adjust for the checkbox in rtl' , async ( ( ) => {
1052
1155
dir . value = 'rtl' ;
1053
1156
trigger . click ( ) ;
1054
1157
multiFixture . detectChanges ( ) ;
1055
1158
1056
- const triggerRight = trigger . getBoundingClientRect ( ) . right ;
1057
- const firstOptionRight =
1058
- document . querySelector ( '.cdk-overlay-pane md-option' ) . getBoundingClientRect ( ) . right ;
1159
+ multiFixture . whenStable ( ) . then ( ( ) => {
1160
+ const triggerRight = trigger . getBoundingClientRect ( ) . right ;
1161
+ const firstOptionRight =
1162
+ document . querySelector ( '.cdk-overlay-pane md-option' ) . getBoundingClientRect ( ) . right ;
1059
1163
1060
- // 48px accounts for the checkbox size, margin and the panel's padding.
1061
- expect ( firstOptionRight . toFixed ( 2 ) )
1062
- . toEqual ( ( triggerRight + 48 ) . toFixed ( 2 ) ,
1063
- `Expected trigger label to align along x-axis, accounting for the checkbox.` ) ;
1064
- } ) ;
1164
+ // 48px accounts for the checkbox size, margin and the panel's padding.
1165
+ expect ( firstOptionRight . toFixed ( 2 ) )
1166
+ . toEqual ( ( triggerRight + 48 ) . toFixed ( 2 ) ,
1167
+ `Expected trigger label to align along x-axis, accounting for the checkbox.` ) ;
1168
+ } ) ;
1169
+ } ) ) ;
1065
1170
} ) ;
1066
1171
1067
1172
} ) ;
@@ -1956,16 +2061,3 @@ class SelectWithPlainTabindex { }
1956
2061
`
1957
2062
} )
1958
2063
class SelectEarlyAccessSibling { }
1959
-
1960
-
1961
- class FakeViewportRuler {
1962
- getViewportRect ( ) {
1963
- return {
1964
- left : 0 , top : 0 , width : 1014 , height : 686 , bottom : 686 , right : 1014
1965
- } ;
1966
- }
1967
-
1968
- getViewportScrollPosition ( ) {
1969
- return { top : 0 , left : 0 } ;
1970
- }
1971
- }
0 commit comments