1+ import { SPACE } from '@angular/cdk/keycodes' ;
12import { waitForAsync , ComponentFixture , fakeAsync , TestBed , tick } from '@angular/core/testing' ;
23import { Component , QueryList , ViewChild , ViewChildren } from '@angular/core' ;
34import {
45 MAT_RIPPLE_GLOBAL_OPTIONS ,
56 RippleGlobalOptions ,
67} from '@angular/material-experimental/mdc-core' ;
78import { By } from '@angular/platform-browser' ;
8- import { dispatchFakeEvent , dispatchMouseEvent } from '../../../cdk/testing/private' ;
9+ import {
10+ dispatchFakeEvent ,
11+ dispatchKeyboardEvent ,
12+ dispatchMouseEvent ,
13+ } from '../../../cdk/testing/private' ;
914import { Direction , Directionality } from '@angular/cdk/bidi' ;
1015import { Subject } from 'rxjs' ;
1116import { MatTabsModule } from '../module' ;
@@ -30,6 +35,7 @@ describe('MDC-based MatTabNavBar', () => {
3035 TabLinkWithTabIndexBinding ,
3136 TabLinkWithNativeTabindexAttr ,
3237 TabBarWithInactiveTabsOnInit ,
38+ TabBarWithPanel ,
3339 ] ,
3440 providers : [
3541 { provide : MAT_RIPPLE_GLOBAL_OPTIONS , useFactory : ( ) => globalRippleOptions } ,
@@ -309,6 +315,123 @@ describe('MDC-based MatTabNavBar', () => {
309315 expect ( instance . tabNavBar . selectedIndex ) . toBe ( 1 ) ;
310316 } ) ;
311317
318+ describe ( 'without panel' , ( ) => {
319+ let fixture : ComponentFixture < SimpleTabNavBarTestApp > ;
320+
321+ beforeEach ( ( ) => {
322+ fixture = TestBed . createComponent ( SimpleTabNavBarTestApp ) ;
323+ fixture . detectChanges ( ) ;
324+ } ) ;
325+
326+ it ( 'should have no explicit roles' , ( ) => {
327+ const tabBar = fixture . nativeElement . querySelector ( '.mat-mdc-tab-nav-bar' ) ! ;
328+ expect ( tabBar . getAttribute ( 'role' ) ) . toBe ( null ) ;
329+
330+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
331+ expect ( tabLinks [ 0 ] . getAttribute ( 'role' ) ) . toBe ( null ) ;
332+ expect ( tabLinks [ 1 ] . getAttribute ( 'role' ) ) . toBe ( null ) ;
333+ expect ( tabLinks [ 2 ] . getAttribute ( 'role' ) ) . toBe ( null ) ;
334+ } ) ;
335+
336+ it ( 'should not setup aria-controls' , ( ) => {
337+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
338+ expect ( tabLinks [ 0 ] . getAttribute ( 'aria-controls' ) ) . toBe ( null ) ;
339+ expect ( tabLinks [ 1 ] . getAttribute ( 'aria-controls' ) ) . toBe ( null ) ;
340+ expect ( tabLinks [ 2 ] . getAttribute ( 'aria-controls' ) ) . toBe ( null ) ;
341+ } ) ;
342+
343+ it ( 'should not manage aria-selected' , ( ) => {
344+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
345+ expect ( tabLinks [ 0 ] . getAttribute ( 'aria-selected' ) ) . toBe ( null ) ;
346+ expect ( tabLinks [ 1 ] . getAttribute ( 'aria-selected' ) ) . toBe ( null ) ;
347+ expect ( tabLinks [ 2 ] . getAttribute ( 'aria-selected' ) ) . toBe ( null ) ;
348+ } ) ;
349+
350+ it ( 'should not activate a link when space is pressed' , ( ) => {
351+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
352+ expect ( tabLinks [ 1 ] . classList . contains ( 'mdc-tab--active' ) ) . toBe ( false ) ;
353+
354+ dispatchKeyboardEvent ( tabLinks [ 1 ] , 'keydown' , SPACE ) ;
355+ fixture . detectChanges ( ) ;
356+
357+ expect ( tabLinks [ 1 ] . classList . contains ( 'mdc-tab--active' ) ) . toBe ( false ) ;
358+ } ) ;
359+ } ) ;
360+
361+ describe ( 'with panel' , ( ) => {
362+ let fixture : ComponentFixture < TabBarWithPanel > ;
363+
364+ beforeEach ( ( ) => {
365+ fixture = TestBed . createComponent ( TabBarWithPanel ) ;
366+ fixture . detectChanges ( ) ;
367+ } ) ;
368+
369+ it ( 'should have the proper roles' , ( ) => {
370+ const tabBar = fixture . nativeElement . querySelector ( '.mat-mdc-tab-nav-bar' ) ! ;
371+ expect ( tabBar . getAttribute ( 'role' ) ) . toBe ( 'tablist' ) ;
372+
373+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
374+ expect ( tabLinks [ 0 ] . getAttribute ( 'role' ) ) . toBe ( 'tab' ) ;
375+ expect ( tabLinks [ 1 ] . getAttribute ( 'role' ) ) . toBe ( 'tab' ) ;
376+ expect ( tabLinks [ 2 ] . getAttribute ( 'role' ) ) . toBe ( 'tab' ) ;
377+
378+ const tabPanel = fixture . nativeElement . querySelector ( '.mat-mdc-tab-nav-panel' ) ! ;
379+ expect ( tabPanel . getAttribute ( 'role' ) ) . toBe ( 'tabpanel' ) ;
380+ } ) ;
381+
382+ it ( 'should manage tabindex properly' , ( ) => {
383+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
384+ expect ( tabLinks [ 0 ] . tabIndex ) . toBe ( 0 ) ;
385+ expect ( tabLinks [ 1 ] . tabIndex ) . toBe ( - 1 ) ;
386+ expect ( tabLinks [ 2 ] . tabIndex ) . toBe ( - 1 ) ;
387+
388+ tabLinks [ 1 ] . click ( ) ;
389+ fixture . detectChanges ( ) ;
390+
391+ expect ( tabLinks [ 0 ] . tabIndex ) . toBe ( - 1 ) ;
392+ expect ( tabLinks [ 1 ] . tabIndex ) . toBe ( 0 ) ;
393+ expect ( tabLinks [ 2 ] . tabIndex ) . toBe ( - 1 ) ;
394+ } ) ;
395+
396+ it ( 'should setup aria-controls properly' , ( ) => {
397+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
398+ expect ( tabLinks [ 0 ] . getAttribute ( 'aria-controls' ) ) . toBe ( 'tab-panel' ) ;
399+ expect ( tabLinks [ 1 ] . getAttribute ( 'aria-controls' ) ) . toBe ( 'tab-panel' ) ;
400+ expect ( tabLinks [ 2 ] . getAttribute ( 'aria-controls' ) ) . toBe ( 'tab-panel' ) ;
401+ } ) ;
402+
403+ it ( 'should not manage aria-current' , ( ) => {
404+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
405+ expect ( tabLinks [ 0 ] . getAttribute ( 'aria-current' ) ) . toBe ( null ) ;
406+ expect ( tabLinks [ 1 ] . getAttribute ( 'aria-current' ) ) . toBe ( null ) ;
407+ expect ( tabLinks [ 2 ] . getAttribute ( 'aria-current' ) ) . toBe ( null ) ;
408+ } ) ;
409+
410+ it ( 'should manage aria-selected properly' , ( ) => {
411+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
412+ expect ( tabLinks [ 0 ] . getAttribute ( 'aria-selected' ) ) . toBe ( 'true' ) ;
413+ expect ( tabLinks [ 1 ] . getAttribute ( 'aria-selected' ) ) . toBe ( 'false' ) ;
414+ expect ( tabLinks [ 2 ] . getAttribute ( 'aria-selected' ) ) . toBe ( 'false' ) ;
415+
416+ tabLinks [ 1 ] . click ( ) ;
417+ fixture . detectChanges ( ) ;
418+
419+ expect ( tabLinks [ 0 ] . getAttribute ( 'aria-selected' ) ) . toBe ( 'false' ) ;
420+ expect ( tabLinks [ 1 ] . getAttribute ( 'aria-selected' ) ) . toBe ( 'true' ) ;
421+ expect ( tabLinks [ 2 ] . getAttribute ( 'aria-selected' ) ) . toBe ( 'false' ) ;
422+ } ) ;
423+
424+ it ( 'should activate a link when space is pressed' , ( ) => {
425+ const tabLinks = fixture . nativeElement . querySelectorAll ( '.mat-mdc-tab-link' ) ;
426+ expect ( tabLinks [ 1 ] . classList . contains ( 'mdc-tab--active' ) ) . toBe ( false ) ;
427+
428+ dispatchKeyboardEvent ( tabLinks [ 1 ] , 'keydown' , SPACE ) ;
429+ fixture . detectChanges ( ) ;
430+
431+ expect ( tabLinks [ 1 ] . classList . contains ( 'mdc-tab--active' ) ) . toBe ( true ) ;
432+ } ) ;
433+ } ) ;
434+
312435 describe ( 'ripples' , ( ) => {
313436 let fixture : ComponentFixture < SimpleTabNavBarTestApp > ;
314437
@@ -532,3 +655,21 @@ class TabLinkWithNativeTabindexAttr {}
532655class TabBarWithInactiveTabsOnInit {
533656 tabs = [ 0 , 1 , 2 ] ;
534657}
658+
659+ @Component ( {
660+ template : `
661+ <nav mat-tab-nav-bar [tabPanel]="tabPanel">
662+ <a mat-tab-link
663+ *ngFor="let tab of tabs; let index = index"
664+ [active]="index === activeIndex"
665+ (click)="activeIndex = index">
666+ Tab link
667+ </a>
668+ </nav>
669+ <mat-tab-nav-panel #tabPanel id="tab-panel">Tab panel</mat-tab-nav-panel>
670+ ` ,
671+ } )
672+ class TabBarWithPanel {
673+ tabs = [ 0 , 1 , 2 ] ;
674+ activeIndex = 0 ;
675+ }
0 commit comments