@@ -300,6 +300,200 @@ describe('MatTabHeader', () => {
300
300
} ) ;
301
301
} ) ;
302
302
303
+ describe ( 'scrolling when holding paginator' , ( ) => {
304
+ let nextButton : HTMLElement ;
305
+ let prevButton : HTMLElement ;
306
+ let header : MatTabHeader ;
307
+ let headerElement : HTMLElement ;
308
+
309
+ beforeEach ( ( ) => {
310
+ fixture = TestBed . createComponent ( SimpleTabHeaderApp ) ;
311
+ fixture . componentInstance . disableRipple = true ;
312
+ fixture . detectChanges ( ) ;
313
+
314
+ fixture . componentInstance . addTabsForScrolling ( 50 ) ;
315
+ fixture . detectChanges ( ) ;
316
+
317
+ nextButton = fixture . nativeElement . querySelector ( '.mat-tab-header-pagination-after' ) ;
318
+ prevButton = fixture . nativeElement . querySelector ( '.mat-tab-header-pagination-before' ) ;
319
+ header = fixture . componentInstance . tabHeader ;
320
+ headerElement = fixture . nativeElement . querySelector ( '.mat-tab-header' ) ;
321
+ } ) ;
322
+
323
+ it ( 'should scroll towards the end while holding down the next button using a mouse' ,
324
+ fakeAsync ( ( ) => {
325
+ assertNextButtonScrolling ( 'mousedown' , 'click' ) ;
326
+ } ) ) ;
327
+
328
+ it ( 'should scroll towards the start while holding down the prev button using a mouse' ,
329
+ fakeAsync ( ( ) => {
330
+ assertPrevButtonScrolling ( 'mousedown' , 'click' ) ;
331
+ } ) ) ;
332
+
333
+ it ( 'should scroll towards the end while holding down the next button using touch' ,
334
+ fakeAsync ( ( ) => {
335
+ assertNextButtonScrolling ( 'touchstart' , 'touchend' ) ;
336
+ } ) ) ;
337
+
338
+ it ( 'should scroll towards the start while holding down the prev button using touch' ,
339
+ fakeAsync ( ( ) => {
340
+ assertPrevButtonScrolling ( 'touchstart' , 'touchend' ) ;
341
+ } ) ) ;
342
+
343
+ it ( 'should not scroll if the sequence is interrupted quickly' , fakeAsync ( ( ) => {
344
+ expect ( header . scrollDistance ) . toBe ( 0 , 'Expected to start off not scrolled.' ) ;
345
+
346
+ dispatchFakeEvent ( nextButton , 'mousedown' ) ;
347
+ fixture . detectChanges ( ) ;
348
+
349
+ tick ( 100 ) ;
350
+
351
+ dispatchFakeEvent ( headerElement , 'mouseleave' ) ;
352
+ fixture . detectChanges ( ) ;
353
+
354
+ tick ( 3000 ) ;
355
+
356
+ expect ( header . scrollDistance ) . toBe ( 0 , 'Expected not to have scrolled after a while.' ) ;
357
+ } ) ) ;
358
+
359
+ it ( 'should clear the timeouts on destroy' , fakeAsync ( ( ) => {
360
+ dispatchFakeEvent ( nextButton , 'mousedown' ) ;
361
+ fixture . detectChanges ( ) ;
362
+ fixture . destroy ( ) ;
363
+
364
+ // No need to assert. If fakeAsync doesn't throw, it means that the timers were cleared.
365
+ } ) ) ;
366
+
367
+ it ( 'should clear the timeouts on click' , fakeAsync ( ( ) => {
368
+ dispatchFakeEvent ( nextButton , 'mousedown' ) ;
369
+ fixture . detectChanges ( ) ;
370
+
371
+ dispatchFakeEvent ( nextButton , 'click' ) ;
372
+ fixture . detectChanges ( ) ;
373
+
374
+ // No need to assert. If fakeAsync doesn't throw, it means that the timers were cleared.
375
+ } ) ) ;
376
+
377
+ it ( 'should clear the timeouts on touchend' , fakeAsync ( ( ) => {
378
+ dispatchFakeEvent ( nextButton , 'touchstart' ) ;
379
+ fixture . detectChanges ( ) ;
380
+
381
+ dispatchFakeEvent ( nextButton , 'touchend' ) ;
382
+ fixture . detectChanges ( ) ;
383
+
384
+ // No need to assert. If fakeAsync doesn't throw, it means that the timers were cleared.
385
+ } ) ) ;
386
+
387
+ it ( 'should clear the timeouts when reaching the end' , fakeAsync ( ( ) => {
388
+ dispatchFakeEvent ( nextButton , 'mousedown' ) ;
389
+ fixture . detectChanges ( ) ;
390
+
391
+ // Simulate a very long timeout.
392
+ tick ( 60000 ) ;
393
+
394
+ // No need to assert. If fakeAsync doesn't throw, it means that the timers were cleared.
395
+ } ) ) ;
396
+
397
+ it ( 'should clear the timeouts when reaching the start' , fakeAsync ( ( ) => {
398
+ header . scrollDistance = Infinity ;
399
+ fixture . detectChanges ( ) ;
400
+
401
+ dispatchFakeEvent ( prevButton , 'mousedown' ) ;
402
+ fixture . detectChanges ( ) ;
403
+
404
+ // Simulate a very long timeout.
405
+ tick ( 60000 ) ;
406
+
407
+ // No need to assert. If fakeAsync doesn't throw, it means that the timers were cleared.
408
+ } ) ) ;
409
+
410
+ it ( 'should stop scrolling if the pointer leaves the header' , fakeAsync ( ( ) => {
411
+ expect ( header . scrollDistance ) . toBe ( 0 , 'Expected to start off not scrolled.' ) ;
412
+
413
+ dispatchFakeEvent ( nextButton , 'mousedown' ) ;
414
+ fixture . detectChanges ( ) ;
415
+ tick ( 300 ) ;
416
+
417
+ expect ( header . scrollDistance ) . toBe ( 0 , 'Expected not to scroll after short amount of time.' ) ;
418
+
419
+ tick ( 1000 ) ;
420
+
421
+ expect ( header . scrollDistance ) . toBeGreaterThan ( 0 , 'Expected to scroll after some time.' ) ;
422
+
423
+ let previousDistance = header . scrollDistance ;
424
+
425
+ dispatchFakeEvent ( headerElement , 'mouseleave' ) ;
426
+ fixture . detectChanges ( ) ;
427
+ tick ( 100 ) ;
428
+
429
+ expect ( header . scrollDistance ) . toBe ( previousDistance ) ;
430
+ } ) ) ;
431
+
432
+ /**
433
+ * Asserts that auto scrolling using the next button works.
434
+ * @param startEventName Name of the event that is supposed to start the scrolling.
435
+ * @param endEventName Name of the event that is supposed to end the scrolling.
436
+ */
437
+ function assertNextButtonScrolling ( startEventName : string , endEventName : string ) {
438
+ expect ( header . scrollDistance ) . toBe ( 0 , 'Expected to start off not scrolled.' ) ;
439
+
440
+ dispatchFakeEvent ( nextButton , startEventName ) ;
441
+ fixture . detectChanges ( ) ;
442
+ tick ( 300 ) ;
443
+
444
+ expect ( header . scrollDistance ) . toBe ( 0 , 'Expected not to scroll after short amount of time.' ) ;
445
+
446
+ tick ( 1000 ) ;
447
+
448
+ expect ( header . scrollDistance ) . toBeGreaterThan ( 0 , 'Expected to scroll after some time.' ) ;
449
+
450
+ let previousDistance = header . scrollDistance ;
451
+
452
+ tick ( 100 ) ;
453
+
454
+ expect ( header . scrollDistance )
455
+ . toBeGreaterThan ( previousDistance , 'Expected to scroll again after some more time.' ) ;
456
+
457
+ dispatchFakeEvent ( nextButton , endEventName ) ;
458
+ }
459
+
460
+ /**
461
+ * Asserts that auto scrolling using the previous button works.
462
+ * @param startEventName Name of the event that is supposed to start the scrolling.
463
+ * @param endEventName Name of the event that is supposed to end the scrolling.
464
+ */
465
+ function assertPrevButtonScrolling ( startEventName : string , endEventName : string ) {
466
+ header . scrollDistance = Infinity ;
467
+ fixture . detectChanges ( ) ;
468
+
469
+ let currentScroll = header . scrollDistance ;
470
+
471
+ expect ( currentScroll ) . toBeGreaterThan ( 0 , 'Expected to start off scrolled.' ) ;
472
+
473
+ dispatchFakeEvent ( prevButton , startEventName ) ;
474
+ fixture . detectChanges ( ) ;
475
+ tick ( 300 ) ;
476
+
477
+ expect ( header . scrollDistance )
478
+ . toBe ( currentScroll , 'Expected not to scroll after short amount of time.' ) ;
479
+
480
+ tick ( 1000 ) ;
481
+
482
+ expect ( header . scrollDistance )
483
+ . toBeLessThan ( currentScroll , 'Expected to scroll after some time.' ) ;
484
+
485
+ currentScroll = header . scrollDistance ;
486
+
487
+ tick ( 100 ) ;
488
+
489
+ expect ( header . scrollDistance )
490
+ . toBeLessThan ( currentScroll , 'Expected to scroll again after some more time.' ) ;
491
+
492
+ dispatchFakeEvent ( nextButton , endEventName ) ;
493
+ }
494
+
495
+ } ) ;
496
+
303
497
it ( 'should re-align the ink bar when the direction changes' , fakeAsync ( ( ) => {
304
498
fixture = TestBed . createComponent ( SimpleTabHeaderApp ) ;
305
499
@@ -424,7 +618,9 @@ class SimpleTabHeaderApp {
424
618
this . tabs [ this . disabledTabIndex ] . disabled = true ;
425
619
}
426
620
427
- addTabsForScrolling ( ) {
428
- this . tabs . push ( { label : 'new' } , { label : 'new' } , { label : 'new' } , { label : 'new' } ) ;
621
+ addTabsForScrolling ( amount = 4 ) {
622
+ for ( let i = 0 ; i < amount ; i ++ ) {
623
+ this . tabs . push ( { label : 'new' } ) ;
624
+ }
429
625
}
430
626
}
0 commit comments