@@ -27,10 +27,23 @@ import {TAB} from '../core/keyboard/keycodes';
27
27
import { ScrollDispatcher } from '../core/overlay/scroll/scroll-dispatcher' ;
28
28
29
29
30
+ class FakeViewportRuler {
31
+ getViewportRect ( ) {
32
+ return {
33
+ left : 0 , top : 0 , width : 1014 , height : 686 , bottom : 686 , right : 1014
34
+ } ;
35
+ }
36
+
37
+ getViewportScrollPosition ( ) {
38
+ return { top : 0 , left : 0 } ;
39
+ }
40
+ }
41
+
30
42
describe ( 'MdSelect' , ( ) => {
31
43
let overlayContainerElement : HTMLElement ;
32
44
let dir : { value : 'ltr' | 'rtl' } ;
33
45
let scrolledSubject = new Subject ( ) ;
46
+ let fakeViewportRuler = new FakeViewportRuler ( ) ;
34
47
35
48
beforeEach ( async ( ( ) => {
36
49
TestBed . configureTestingModule ( {
@@ -72,7 +85,6 @@ describe('MdSelect', () => {
72
85
{ provide : Dir , useFactory : ( ) => {
73
86
return dir = { value : 'ltr' } ;
74
87
} } ,
75
- { provide : ViewportRuler , useClass : FakeViewportRuler } ,
76
88
{ provide : ScrollDispatcher , useFactory : ( ) => {
77
89
return { scrolled : ( delay : number , callback : ( ) => any ) => {
78
90
return scrolledSubject . asObservable ( ) . subscribe ( callback ) ;
@@ -942,6 +954,91 @@ describe('MdSelect', () => {
942
954
943
955
} ) ;
944
956
957
+ describe ( 'limited space to open horizontally' , ( ) => {
958
+ beforeEach ( ( ) => {
959
+ select . style . position = 'absolute' ;
960
+ select . style . top = '200px' ;
961
+ } ) ;
962
+
963
+ it ( 'should stay within the viewport when overflowing on the left in ltr' , fakeAsync ( ( ) => {
964
+ select . style . left = '-100px' ;
965
+ trigger . click ( ) ;
966
+ tick ( 400 ) ;
967
+ fixture . detectChanges ( ) ;
968
+
969
+ const panelLeft = document . querySelector ( '.mat-select-panel' )
970
+ . getBoundingClientRect ( ) . left ;
971
+ expect ( panelLeft ) . toBeGreaterThan ( 0 ,
972
+ `Expected select panel to be inside the viewport in ltr.` ) ;
973
+ } ) ) ;
974
+
975
+ it ( 'should stay within the viewport when overflowing on the left in rtl' , fakeAsync ( ( ) => {
976
+ dir . value = 'rtl' ;
977
+ select . style . left = '-100px' ;
978
+ trigger . click ( ) ;
979
+ tick ( 400 ) ;
980
+ fixture . detectChanges ( ) ;
981
+
982
+ const panelLeft = document . querySelector ( '.mat-select-panel' )
983
+ . getBoundingClientRect ( ) . left ;
984
+
985
+ expect ( panelLeft ) . toBeGreaterThan ( 0 ,
986
+ `Expected select panel to be inside the viewport in rtl.` ) ;
987
+ } ) ) ;
988
+
989
+ it ( 'should stay within the viewport when overflowing on the right in ltr' , fakeAsync ( ( ) => {
990
+ select . style . right = '-100px' ;
991
+ trigger . click ( ) ;
992
+ tick ( 400 ) ;
993
+ fixture . detectChanges ( ) ;
994
+
995
+ const viewportRect = fakeViewportRuler . getViewportRect ( ) . right ;
996
+ const panelRight = document . querySelector ( '.mat-select-panel' )
997
+ . getBoundingClientRect ( ) . right ;
998
+
999
+ expect ( viewportRect - panelRight ) . toBeGreaterThan ( 0 ,
1000
+ `Expected select panel to be inside the viewport in ltr.` ) ;
1001
+ } ) ) ;
1002
+
1003
+ it ( 'should stay within the viewport when overflowing on the right in rtl' , fakeAsync ( ( ) => {
1004
+ dir . value = 'rtl' ;
1005
+ select . style . right = '-100px' ;
1006
+ trigger . click ( ) ;
1007
+ tick ( 400 ) ;
1008
+ fixture . detectChanges ( ) ;
1009
+
1010
+ const viewportRect = fakeViewportRuler . getViewportRect ( ) . right ;
1011
+ const panelRight = document . querySelector ( '.mat-select-panel' )
1012
+ . getBoundingClientRect ( ) . right ;
1013
+
1014
+ expect ( viewportRect - panelRight ) . toBeGreaterThan ( 0 ,
1015
+ `Expected select panel to be inside the viewport in rtl.` ) ;
1016
+ } ) ) ;
1017
+
1018
+ it ( 'should keep the position within the viewport on repeat openings' , async ( ( ) => {
1019
+ select . style . left = '-100px' ;
1020
+ trigger . click ( ) ;
1021
+ fixture . detectChanges ( ) ;
1022
+
1023
+ let panelLeft = document . querySelector ( '.mat-select-panel' ) . getBoundingClientRect ( ) . left ;
1024
+
1025
+ expect ( panelLeft ) . toBeGreaterThan ( 0 , `Expected select panel to be inside the viewport.` ) ;
1026
+
1027
+ fixture . componentInstance . select . close ( ) ;
1028
+ fixture . detectChanges ( ) ;
1029
+
1030
+ fixture . whenStable ( ) . then ( ( ) => {
1031
+ trigger . click ( ) ;
1032
+ fixture . detectChanges ( ) ;
1033
+ panelLeft = document . querySelector ( '.mat-select-panel' ) . getBoundingClientRect ( ) . left ;
1034
+
1035
+ expect ( panelLeft ) . toBeGreaterThan ( 0 ,
1036
+ `Expected select panel continue being inside the viewport.` ) ;
1037
+ } ) ;
1038
+ } ) ) ;
1039
+
1040
+ } ) ;
1041
+
945
1042
describe ( 'when scrolled' , ( ) => {
946
1043
947
1044
// Need to set the scrollTop two different ways to support
@@ -1063,42 +1160,38 @@ describe('MdSelect', () => {
1063
1160
select . style . marginRight = '30px' ;
1064
1161
} ) ;
1065
1162
1066
- it ( 'should align the trigger and the selected option on the x-axis in ltr' , async ( ( ) => {
1163
+ it ( 'should align the trigger and the selected option on the x-axis in ltr' , fakeAsync ( ( ) => {
1067
1164
trigger . click ( ) ;
1165
+ tick ( 400 ) ;
1068
1166
fixture . detectChanges ( ) ;
1069
1167
1070
- fixture . whenStable ( ) . then ( ( ) => {
1071
- const triggerLeft = trigger . getBoundingClientRect ( ) . left ;
1072
- const firstOptionLeft = document . querySelector ( '.cdk-overlay-pane md-option' )
1073
- . getBoundingClientRect ( ) . left ;
1168
+ const triggerLeft = trigger . getBoundingClientRect ( ) . left ;
1169
+ const firstOptionLeft = document . querySelector ( '.cdk-overlay-pane md-option' )
1170
+ . getBoundingClientRect ( ) . left ;
1074
1171
1075
- // Each option is 32px wider than the trigger, so it must be adjusted 16px
1076
- // to ensure the text overlaps correctly.
1077
- expect ( firstOptionLeft . toFixed ( 2 ) ) . toEqual ( ( triggerLeft - 16 ) . toFixed ( 2 ) ,
1078
- `Expected trigger to align with the selected option on the x-axis in LTR.` ) ;
1079
- } ) ;
1172
+ // Each option is 32px wider than the trigger, so it must be adjusted 16px
1173
+ // to ensure the text overlaps correctly.
1174
+ expect ( firstOptionLeft . toFixed ( 2 ) ) . toEqual ( ( triggerLeft - 16 ) . toFixed ( 2 ) ,
1175
+ `Expected trigger to align with the selected option on the x-axis in LTR.` ) ;
1080
1176
} ) ) ;
1081
1177
1082
- it ( 'should align the trigger and the selected option on the x-axis in rtl' , async ( ( ) => {
1178
+ it ( 'should align the trigger and the selected option on the x-axis in rtl' , fakeAsync ( ( ) => {
1083
1179
dir . value = 'rtl' ;
1084
- fixture . whenStable ( ) . then ( ( ) => {
1085
- fixture . detectChanges ( ) ;
1180
+ fixture . detectChanges ( ) ;
1086
1181
1087
- trigger . click ( ) ;
1088
- fixture . detectChanges ( ) ;
1182
+ trigger . click ( ) ;
1183
+ tick ( 400 ) ;
1184
+ fixture . detectChanges ( ) ;
1089
1185
1090
- fixture . whenStable ( ) . then ( ( ) => {
1091
- const triggerRight = trigger . getBoundingClientRect ( ) . right ;
1092
- const firstOptionRight =
1093
- document . querySelector ( '.cdk-overlay-pane md-option' ) . getBoundingClientRect ( ) . right ;
1094
-
1095
- // Each option is 32px wider than the trigger, so it must be adjusted 16px
1096
- // to ensure the text overlaps correctly.
1097
- expect ( firstOptionRight . toFixed ( 2 ) )
1098
- . toEqual ( ( triggerRight + 16 ) . toFixed ( 2 ) ,
1099
- `Expected trigger to align with the selected option on the x-axis in RTL.` ) ;
1100
- } ) ;
1101
- } ) ;
1186
+ const triggerRight = trigger . getBoundingClientRect ( ) . right ;
1187
+ const firstOptionRight =
1188
+ document . querySelector ( '.cdk-overlay-pane md-option' ) . getBoundingClientRect ( ) . right ;
1189
+
1190
+ // Each option is 32px wider than the trigger, so it must be adjusted 16px
1191
+ // to ensure the text overlaps correctly.
1192
+ expect ( firstOptionRight . toFixed ( 2 ) )
1193
+ . toEqual ( ( triggerRight + 16 ) . toFixed ( 2 ) ,
1194
+ `Expected trigger to align with the selected option on the x-axis in RTL.` ) ;
1102
1195
} ) ) ;
1103
1196
} ) ;
1104
1197
@@ -1111,8 +1204,8 @@ describe('MdSelect', () => {
1111
1204
trigger = multiFixture . debugElement . query ( By . css ( '.mat-select-trigger' ) ) . nativeElement ;
1112
1205
select = multiFixture . debugElement . query ( By . css ( 'md-select' ) ) . nativeElement ;
1113
1206
1114
- select . style . marginLeft = '20px ' ;
1115
- select . style . marginRight = '20px ' ;
1207
+ select . style . marginLeft = '60px ' ;
1208
+ select . style . marginRight = '60px ' ;
1116
1209
} ) ;
1117
1210
1118
1211
it ( 'should adjust for the checkbox in ltr' , async ( ( ) => {
@@ -1131,21 +1224,20 @@ describe('MdSelect', () => {
1131
1224
} ) ;
1132
1225
} ) ) ;
1133
1226
1134
- it ( 'should adjust for the checkbox in rtl' , async ( ( ) => {
1227
+ it ( 'should adjust for the checkbox in rtl' , fakeAsync ( ( ) => {
1135
1228
dir . value = 'rtl' ;
1136
1229
trigger . click ( ) ;
1230
+ tick ( 400 ) ;
1137
1231
multiFixture . detectChanges ( ) ;
1138
1232
1139
- multiFixture . whenStable ( ) . then ( ( ) => {
1140
- const triggerRight = trigger . getBoundingClientRect ( ) . right ;
1141
- const firstOptionRight =
1142
- document . querySelector ( '.cdk-overlay-pane md-option' ) . getBoundingClientRect ( ) . right ;
1233
+ const triggerRight = trigger . getBoundingClientRect ( ) . right ;
1234
+ const firstOptionRight =
1235
+ document . querySelector ( '.cdk-overlay-pane md-option' ) . getBoundingClientRect ( ) . right ;
1143
1236
1144
- // 48px accounts for the checkbox size, margin and the panel's padding.
1145
- expect ( firstOptionRight . toFixed ( 2 ) )
1146
- . toEqual ( ( triggerRight + 48 ) . toFixed ( 2 ) ,
1147
- `Expected trigger label to align along x-axis, accounting for the checkbox.` ) ;
1148
- } ) ;
1237
+ // 48px accounts for the checkbox size, margin and the panel's padding.
1238
+ expect ( firstOptionRight . toFixed ( 2 ) )
1239
+ . toEqual ( ( triggerRight + 48 ) . toFixed ( 2 ) ,
1240
+ `Expected trigger label to align along x-axis, accounting for the checkbox.` ) ;
1149
1241
} ) ) ;
1150
1242
} ) ;
1151
1243
@@ -2126,15 +2218,3 @@ class BasicSelectWithTheming {
2126
2218
@ViewChild ( MdSelect ) select : MdSelect ;
2127
2219
theme : string ;
2128
2220
}
2129
-
2130
- class FakeViewportRuler {
2131
- getViewportRect ( ) {
2132
- return {
2133
- left : 0 , top : 0 , width : 1014 , height : 686 , bottom : 686 , right : 1014
2134
- } ;
2135
- }
2136
-
2137
- getViewportScrollPosition ( ) {
2138
- return { top : 0 , left : 0 } ;
2139
- }
2140
- }
0 commit comments