1
1
import { TestBed , async , ComponentFixture } from '@angular/core/testing' ;
2
2
import { By } from '@angular/platform-browser' ;
3
- import { Component , DebugElement , QueryList , ViewChild , ViewChildren } from '@angular/core' ;
3
+ import { Component , QueryList , ViewChild , ViewChildren } from '@angular/core' ;
4
4
import { MdSelectModule } from './index' ;
5
5
import { OverlayContainer } from '../core/overlay/overlay-container' ;
6
6
import { MdSelect } from './select' ;
7
7
import { MdOption } from './option' ;
8
8
import { Dir } from '../core/rtl/dir' ;
9
+ import { FormControl , ReactiveFormsModule } from '@angular/forms' ;
9
10
10
11
describe ( 'MdSelect' , ( ) => {
11
12
let overlayContainerElement : HTMLElement ;
12
13
let dir : { value : string } ;
13
14
14
15
beforeEach ( async ( ( ) => {
15
16
TestBed . configureTestingModule ( {
16
- imports : [ MdSelectModule . forRoot ( ) ] ,
17
+ imports : [ MdSelectModule . forRoot ( ) , ReactiveFormsModule ] ,
17
18
declarations : [ BasicSelect ] ,
18
19
providers : [
19
20
{ provide : OverlayContainer , useFactory : ( ) => {
@@ -190,7 +191,7 @@ describe('MdSelect', () => {
190
191
} ) ) ;
191
192
192
193
it ( 'should select an option that was added after initialization' , ( ) => {
193
- fixture . componentInstance . foods . push ( { viewValue : 'Pasta' } ) ;
194
+ fixture . componentInstance . foods . push ( { viewValue : 'Pasta' , value : 'pasta-3' } ) ;
194
195
trigger . click ( ) ;
195
196
fixture . detectChanges ( ) ;
196
197
@@ -206,6 +207,94 @@ describe('MdSelect', () => {
206
207
207
208
} ) ;
208
209
210
+ describe ( 'forms integration' , ( ) => {
211
+ let fixture : ComponentFixture < BasicSelect > ;
212
+ let trigger : HTMLElement ;
213
+
214
+ beforeEach ( ( ) => {
215
+ fixture = TestBed . createComponent ( BasicSelect ) ;
216
+ fixture . detectChanges ( ) ;
217
+
218
+ trigger = fixture . debugElement . query ( By . css ( '.md-select-trigger' ) ) . nativeElement ;
219
+ } ) ;
220
+
221
+ it ( 'should set the view value from the form' , ( ) => {
222
+ let value = fixture . debugElement . query ( By . css ( '.md-select-value' ) ) ;
223
+ expect ( value ) . toBeNull ( ) ;
224
+
225
+ fixture . componentInstance . control . setValue ( 'pizza-1' ) ;
226
+ fixture . detectChanges ( ) ;
227
+
228
+ value = fixture . debugElement . query ( By . css ( '.md-select-value' ) ) ;
229
+ expect ( value . nativeElement . textContent ) . toContain ( 'Pizza' ) ;
230
+ } ) ;
231
+
232
+ it ( 'should update the form value when the view changes' , ( ) => {
233
+ expect ( fixture . componentInstance . control . value ) . toEqual ( null ) ;
234
+
235
+ trigger . click ( ) ;
236
+ fixture . detectChanges ( ) ;
237
+
238
+ const option = overlayContainerElement . querySelector ( 'md-option' ) as HTMLElement ;
239
+ option . click ( ) ;
240
+ fixture . detectChanges ( ) ;
241
+
242
+ expect ( fixture . componentInstance . control . value ) . toEqual ( 'steak-0' ) ;
243
+ } ) ;
244
+
245
+ it ( 'should set the control to touched when the select is touched' , ( ) => {
246
+ expect ( fixture . componentInstance . control . touched ) . toEqual ( false ) ;
247
+
248
+ trigger . click ( ) ;
249
+ fixture . detectChanges ( ) ;
250
+ expect ( fixture . componentInstance . control . touched ) . toEqual ( false ) ;
251
+
252
+ const backdrop =
253
+ overlayContainerElement . querySelector ( '.md-overlay-backdrop' ) as HTMLElement ;
254
+ backdrop . click ( ) ;
255
+ dispatchEvent ( 'blur' , trigger ) ;
256
+ fixture . detectChanges ( ) ;
257
+
258
+ expect ( fixture . componentInstance . control . touched ) . toEqual ( true ) ;
259
+ } ) ;
260
+
261
+ it ( 'should set the control to dirty when the select\'s value changes in the DOM' , ( ) => {
262
+ expect ( fixture . componentInstance . control . dirty ) . toEqual ( false ) ;
263
+
264
+ trigger . click ( ) ;
265
+ fixture . detectChanges ( ) ;
266
+
267
+ const option = overlayContainerElement . querySelector ( 'md-option' ) as HTMLElement ;
268
+ option . click ( ) ;
269
+ fixture . detectChanges ( ) ;
270
+
271
+ expect ( fixture . componentInstance . control . dirty ) . toEqual ( true ) ;
272
+ } ) ;
273
+
274
+ it ( 'should not set the control to dirty when the value changes programmatically' , ( ) => {
275
+ expect ( fixture . componentInstance . control . dirty ) . toEqual ( false ) ;
276
+
277
+ fixture . componentInstance . control . setValue ( 'pizza-1' ) ;
278
+
279
+ expect ( fixture . componentInstance . control . dirty ) . toEqual ( false ) ;
280
+ } ) ;
281
+
282
+
283
+ it ( 'should set an asterisk after the placeholder if the control is required' , ( ) => {
284
+ const placeholder =
285
+ fixture . debugElement . query ( By . css ( '.md-select-placeholder' ) ) . nativeElement ;
286
+ const initialContent = getComputedStyle ( placeholder , '::after' ) . getPropertyValue ( 'content' ) ;
287
+
288
+ // must support both default cases to work in all browsers in Saucelabs
289
+ expect ( initialContent === 'none' || initialContent === '' ) . toBe ( true ) ;
290
+
291
+ fixture . componentInstance . isRequired = true ;
292
+ fixture . detectChanges ( ) ;
293
+ expect ( getComputedStyle ( placeholder , '::after' ) . getPropertyValue ( 'content' ) ) . toContain ( '*' ) ;
294
+ } ) ;
295
+
296
+ } ) ;
297
+
209
298
describe ( 'animations' , ( ) => {
210
299
let fixture : ComponentFixture < BasicSelect > ;
211
300
let trigger : HTMLElement ;
@@ -278,22 +367,40 @@ describe('MdSelect', () => {
278
367
} ) ;
279
368
280
369
describe ( 'for select' , ( ) => {
281
- let select : DebugElement ;
370
+ let select : HTMLElement ;
282
371
283
372
beforeEach ( ( ) => {
284
- select = fixture . debugElement . query ( By . css ( 'md-select' ) ) ;
373
+ select = fixture . debugElement . query ( By . css ( 'md-select' ) ) . nativeElement ;
285
374
} ) ;
286
375
287
376
it ( 'should set the role of the select to listbox' , ( ) => {
288
- expect ( select . nativeElement . getAttribute ( 'role' ) ) . toEqual ( 'listbox' ) ;
377
+ expect ( select . getAttribute ( 'role' ) ) . toEqual ( 'listbox' ) ;
289
378
} ) ;
290
379
291
380
it ( 'should set the aria label of the select to the placeholder' , ( ) => {
292
- expect ( select . nativeElement . getAttribute ( 'aria-label' ) ) . toEqual ( 'Food' ) ;
381
+ expect ( select . getAttribute ( 'aria-label' ) ) . toEqual ( 'Food' ) ;
293
382
} ) ;
294
383
295
384
it ( 'should set the tabindex of the select to 0' , ( ) => {
296
- expect ( select . nativeElement . getAttribute ( 'tabindex' ) ) . toEqual ( '0' ) ;
385
+ expect ( select . getAttribute ( 'tabindex' ) ) . toEqual ( '0' ) ;
386
+ } ) ;
387
+
388
+ it ( 'should set aria-required for required selects' , ( ) => {
389
+ expect ( select . getAttribute ( 'aria-required' ) ) . toEqual ( 'false' ) ;
390
+
391
+ fixture . componentInstance . isRequired = true ;
392
+ fixture . detectChanges ( ) ;
393
+
394
+ expect ( select . getAttribute ( 'aria-required' ) ) . toEqual ( 'true' ) ;
395
+ } ) ;
396
+
397
+ it ( 'should set aria-invalid for selects that are invalid' , ( ) => {
398
+ expect ( select . getAttribute ( 'aria-invalid' ) ) . toEqual ( 'false' ) ;
399
+
400
+ fixture . componentInstance . isRequired = true ;
401
+ fixture . detectChanges ( ) ;
402
+
403
+ expect ( select . getAttribute ( 'aria-invalid' ) ) . toEqual ( 'true' ) ;
297
404
} ) ;
298
405
299
406
} ) ;
@@ -347,19 +454,34 @@ describe('MdSelect', () => {
347
454
@Component ( {
348
455
selector : 'basic-select' ,
349
456
template : `
350
- <md-select placeholder="Food">
351
- <md-option *ngFor="let food of foods">{{ food.viewValue }}</md-option>
457
+ <md-select placeholder="Food" [formControl]="control" [required]="isRequired" >
458
+ <md-option *ngFor="let food of foods" [value]="food.value" >{{ food.viewValue }}</md-option>
352
459
</md-select>
353
460
`
354
461
} )
355
462
class BasicSelect {
356
463
foods = [
357
- { viewValue : 'Steak' } ,
358
- { viewValue : 'Pizza' } ,
359
- { viewValue : 'Tacos' } ,
464
+ { value : 'steak-0' , viewValue : 'Steak' } ,
465
+ { value : 'pizza-1' , viewValue : 'Pizza' } ,
466
+ { value : 'tacos-2' , viewValue : 'Tacos' } ,
360
467
] ;
468
+ control = new FormControl ( ) ;
469
+ isRequired : boolean ;
361
470
362
471
@ViewChild ( MdSelect ) select : MdSelect ;
363
472
@ViewChildren ( MdOption ) options : QueryList < MdOption > ;
473
+ }
364
474
475
+ /**
476
+ * TODO: Move this to core testing utility until Angular has event faking
477
+ * support.
478
+ *
479
+ * Dispatches an event from an element.
480
+ * @param eventName Name of the event
481
+ * @param element The element from which the event will be dispatched.
482
+ */
483
+ function dispatchEvent ( eventName : string , element : HTMLElement ) : void {
484
+ let event = document . createEvent ( 'Event' ) ;
485
+ event . initEvent ( eventName , true , true ) ;
486
+ element . dispatchEvent ( event ) ;
365
487
}
0 commit comments