@@ -14,6 +14,7 @@ import {OverlayContainer} from '../core/overlay/overlay-container';
14
14
import { MdSelect , MdSelectFloatPlaceholderType } from './select' ;
15
15
import { MdOption } from '../core/option/option' ;
16
16
import { Dir } from '../core/rtl/dir' ;
17
+ import { DOWN_ARROW , UP_ARROW } from '../core/keyboard/keycodes' ;
17
18
import {
18
19
ControlValueAccessor , FormControl , FormsModule , NG_VALUE_ACCESSOR , ReactiveFormsModule
19
20
} from '@angular/forms' ;
@@ -1078,6 +1079,79 @@ describe('MdSelect', () => {
1078
1079
expect ( select . getAttribute ( 'tabindex' ) ) . toEqual ( '0' ) ;
1079
1080
} ) ;
1080
1081
1082
+ it ( 'should be able to select options via the arrow keys on a closed select' , ( ) => {
1083
+ const formControl = fixture . componentInstance . control ;
1084
+ const options = fixture . componentInstance . options . toArray ( ) ;
1085
+
1086
+ expect ( formControl . value ) . toBeFalsy ( 'Expected no initial value.' ) ;
1087
+
1088
+ dispatchKeydownEvent ( select , DOWN_ARROW ) ;
1089
+
1090
+ expect ( options [ 0 ] . selected ) . toBe ( true , 'Expected first option to be selected.' ) ;
1091
+ expect ( formControl . value ) . toBe ( options [ 0 ] . value ,
1092
+ 'Expected value from first option to have been set on the model.' ) ;
1093
+
1094
+ dispatchKeydownEvent ( select , DOWN_ARROW ) ;
1095
+ dispatchKeydownEvent ( select , DOWN_ARROW ) ;
1096
+
1097
+ // Note that the third option is skipped, because it is disabled.
1098
+ expect ( options [ 3 ] . selected ) . toBe ( true , 'Expected fourth option to be selected.' ) ;
1099
+ expect ( formControl . value ) . toBe ( options [ 3 ] . value ,
1100
+ 'Expected value from fourth option to have been set on the model.' ) ;
1101
+
1102
+ dispatchKeydownEvent ( select , UP_ARROW ) ;
1103
+
1104
+ expect ( options [ 1 ] . selected ) . toBe ( true , 'Expected second option to be selected.' ) ;
1105
+ expect ( formControl . value ) . toBe ( options [ 1 ] . value ,
1106
+ 'Expected value from second option to have been set on the model.' ) ;
1107
+ } ) ;
1108
+
1109
+ it ( 'should do nothing if the key manager did not change the active item' , ( ) => {
1110
+ const formControl = fixture . componentInstance . control ;
1111
+
1112
+ expect ( formControl . value ) . toBeNull ( 'Expected form control value to be empty.' ) ;
1113
+ expect ( formControl . pristine ) . toBe ( true , 'Expected form control to be clean.' ) ;
1114
+
1115
+ dispatchKeydownEvent ( select , 16 ) ; // Press a random key. In this case left shift.
1116
+
1117
+ expect ( formControl . value ) . toBeNull ( 'Expected form control value to stay empty.' ) ;
1118
+ expect ( formControl . pristine ) . toBe ( true , 'Expected form control to stay clean.' ) ;
1119
+ } ) ;
1120
+
1121
+ it ( 'should continue from the selected option when the value is set programmatically' , ( ) => {
1122
+ const formControl = fixture . componentInstance . control ;
1123
+
1124
+ formControl . setValue ( 'eggs-5' ) ;
1125
+ fixture . detectChanges ( ) ;
1126
+
1127
+ dispatchKeydownEvent ( select , DOWN_ARROW ) ;
1128
+
1129
+ expect ( formControl . value ) . toBe ( 'pasta-6' ) ;
1130
+ expect ( fixture . componentInstance . options . toArray ( ) [ 6 ] . selected ) . toBe ( true ) ;
1131
+ } ) ;
1132
+
1133
+ it ( 'should not cycle through the options if the control is disabled' , ( ) => {
1134
+ const formControl = fixture . componentInstance . control ;
1135
+
1136
+ formControl . setValue ( 'eggs-5' ) ;
1137
+ formControl . disable ( ) ;
1138
+ dispatchKeydownEvent ( select , DOWN_ARROW ) ;
1139
+
1140
+ expect ( formControl . value ) . toBe ( 'eggs-5' , 'Expected value to remain unchaged.' ) ;
1141
+ } ) ;
1142
+
1143
+ it ( 'should not wrap selection around after reaching the end of the options' , ( ) => {
1144
+ const lastOption = fixture . componentInstance . options . last ;
1145
+
1146
+ fixture . componentInstance . options . forEach ( ( ) => dispatchKeydownEvent ( select , DOWN_ARROW ) ) ;
1147
+
1148
+ expect ( lastOption . selected ) . toBe ( true , 'Expected last option to be selected.' ) ;
1149
+
1150
+ dispatchKeydownEvent ( select , DOWN_ARROW ) ;
1151
+
1152
+ expect ( lastOption . selected ) . toBe ( true , 'Expected last option to stay selected.' ) ;
1153
+ } ) ;
1154
+
1081
1155
} ) ;
1082
1156
1083
1157
describe ( 'for options' , ( ) => {
@@ -1603,6 +1677,23 @@ function dispatchEvent(eventName: string, element: HTMLElement): void {
1603
1677
element . dispatchEvent ( event ) ;
1604
1678
}
1605
1679
1680
+ /**
1681
+ * TODO: Move this to core testing utility.
1682
+ *
1683
+ * Dispatches a keydown event on an element.
1684
+ * @param element Element on which to dispatch the event.
1685
+ * @param keyCode Code of the pressed key.
1686
+ */
1687
+ function dispatchKeydownEvent ( element : Node , keyCode : number ) {
1688
+ let event : any = document . createEvent ( 'KeyboardEvent' ) ;
1689
+ ( event . initKeyEvent || event . initKeyboardEvent ) . bind ( event ) (
1690
+ 'keydown' , true , true , window , 0 , 0 , 0 , 0 , 0 , keyCode ) ;
1691
+ Object . defineProperty ( event , 'keyCode' , {
1692
+ get : function ( ) { return keyCode ; }
1693
+ } ) ;
1694
+ element . dispatchEvent ( event ) ;
1695
+ }
1696
+
1606
1697
class FakeViewportRuler {
1607
1698
getViewportRect ( ) {
1608
1699
return {
0 commit comments