640 lines
22 KiB
TypeScript
640 lines
22 KiB
TypeScript
import {Direction, Directionality} from '@angular/cdk/bidi';
|
|
import {ENTER, SPACE} from '@angular/cdk/keycodes';
|
|
import {SharedResizeObserver} from '@angular/cdk/observers/private';
|
|
import {
|
|
dispatchFakeEvent,
|
|
dispatchKeyboardEvent,
|
|
dispatchMouseEvent,
|
|
} from '@angular/cdk/testing/private';
|
|
import {Component, QueryList, ViewChild, ViewChildren} from '@angular/core';
|
|
import {ComponentFixture, TestBed, fakeAsync, tick, waitForAsync} from '@angular/core/testing';
|
|
import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core';
|
|
import {By} from '@angular/platform-browser';
|
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
|
import {Subject} from 'rxjs';
|
|
import {MAT_TABS_CONFIG} from '../index';
|
|
import {MatTabsModule} from '../module';
|
|
import {MatTabLink, MatTabNav} from './tab-nav-bar';
|
|
|
|
describe('MatTabNavBar', () => {
|
|
let dir: Direction = 'ltr';
|
|
let dirChange = new Subject();
|
|
let globalRippleOptions: RippleGlobalOptions;
|
|
let resizeEvents: Subject<ResizeObserverEntry[]>;
|
|
|
|
beforeEach(waitForAsync(() => {
|
|
globalRippleOptions = {};
|
|
|
|
TestBed.configureTestingModule({
|
|
imports: [
|
|
MatTabsModule,
|
|
SimpleTabNavBarTestApp,
|
|
TabLinkWithNgIf,
|
|
TabBarWithInactiveTabsOnInit,
|
|
],
|
|
providers: [
|
|
{provide: MAT_RIPPLE_GLOBAL_OPTIONS, useFactory: () => globalRippleOptions},
|
|
{provide: Directionality, useFactory: () => ({value: dir, change: dirChange})},
|
|
],
|
|
});
|
|
|
|
resizeEvents = new Subject();
|
|
spyOn(TestBed.inject(SharedResizeObserver), 'observe').and.returnValue(resizeEvents);
|
|
}));
|
|
|
|
describe('basic behavior', () => {
|
|
let fixture: ComponentFixture<SimpleTabNavBarTestApp>;
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.detectChanges();
|
|
});
|
|
|
|
it('should change active index on click', () => {
|
|
// select the second link
|
|
let tabLink = fixture.debugElement.queryAll(By.css('a'))[1];
|
|
tabLink.nativeElement.click();
|
|
expect(fixture.componentInstance.activeIndex).toBe(1);
|
|
|
|
// select the third link
|
|
tabLink = fixture.debugElement.queryAll(By.css('a'))[2];
|
|
tabLink.nativeElement.click();
|
|
expect(fixture.componentInstance.activeIndex).toBe(2);
|
|
});
|
|
|
|
it('should add the active class if active', () => {
|
|
let tabLink1 = fixture.debugElement.queryAll(By.css('a'))[0];
|
|
let tabLink2 = fixture.debugElement.queryAll(By.css('a'))[1];
|
|
const tabLinkElements = fixture.debugElement
|
|
.queryAll(By.css('a'))
|
|
.map(tabLinkDebugEl => tabLinkDebugEl.nativeElement);
|
|
|
|
tabLink1.nativeElement.click();
|
|
fixture.detectChanges();
|
|
expect(tabLinkElements[0].classList.contains('mdc-tab--active')).toBeTruthy();
|
|
expect(tabLinkElements[1].classList.contains('mdc-tab--active')).toBeFalsy();
|
|
|
|
tabLink2.nativeElement.click();
|
|
fixture.detectChanges();
|
|
expect(tabLinkElements[0].classList.contains('mdc-tab--active')).toBeFalsy();
|
|
expect(tabLinkElements[1].classList.contains('mdc-tab--active')).toBeTruthy();
|
|
});
|
|
|
|
it('should update aria-disabled if disabled', () => {
|
|
const tabLinkElements = fixture.debugElement
|
|
.queryAll(By.css('a'))
|
|
.map(tabLinkDebugEl => tabLinkDebugEl.nativeElement);
|
|
|
|
expect(tabLinkElements.every(tabLink => tabLink.getAttribute('aria-disabled') === 'false'))
|
|
.withContext('Expected aria-disabled to be set to "false" by default.')
|
|
.toBe(true);
|
|
|
|
fixture.componentInstance.disabled = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(tabLinkElements.every(tabLink => tabLink.getAttribute('aria-disabled') === 'true'))
|
|
.withContext('Expected aria-disabled to be set to "true" if link is disabled.')
|
|
.toBe(true);
|
|
});
|
|
|
|
it('should update the tabindex if links are disabled', () => {
|
|
const tabLinkElements = fixture.debugElement
|
|
.queryAll(By.css('a'))
|
|
.map(tabLinkDebugEl => tabLinkDebugEl.nativeElement);
|
|
|
|
expect(tabLinkElements.map(tabLink => tabLink.tabIndex))
|
|
.withContext('Expected first element to be keyboard focusable by default')
|
|
.toEqual([0, -1, -1]);
|
|
|
|
fixture.componentInstance.disabled = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(tabLinkElements.every(tabLink => tabLink.tabIndex === -1))
|
|
.withContext('Expected element to no longer be keyboard focusable if disabled.')
|
|
.toBe(true);
|
|
});
|
|
|
|
it('should mark disabled links', () => {
|
|
const tabLinkElement = fixture.debugElement.query(By.css('a')).nativeElement;
|
|
|
|
expect(tabLinkElement.classList).not.toContain('mat-mdc-tab-disabled');
|
|
|
|
fixture.componentInstance.disabled = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(tabLinkElement.classList).toContain('mat-mdc-tab-disabled');
|
|
});
|
|
|
|
it('should prevent default keyboard actions on disabled links', () => {
|
|
const link = fixture.debugElement.query(By.css('a')).nativeElement;
|
|
fixture.componentInstance.disabled = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
const spaceEvent = dispatchKeyboardEvent(link, 'keydown', SPACE);
|
|
fixture.detectChanges();
|
|
expect(spaceEvent.defaultPrevented).toBe(true);
|
|
|
|
const enterEvent = dispatchKeyboardEvent(link, 'keydown', ENTER);
|
|
fixture.detectChanges();
|
|
expect(enterEvent.defaultPrevented).toBe(true);
|
|
});
|
|
|
|
it('should re-align the ink bar when the direction changes', fakeAsync(() => {
|
|
const inkBar = fixture.componentInstance.tabNavBar._inkBar;
|
|
|
|
spyOn(inkBar, 'alignToElement');
|
|
|
|
dirChange.next();
|
|
tick();
|
|
fixture.detectChanges();
|
|
|
|
expect(inkBar.alignToElement).toHaveBeenCalled();
|
|
}));
|
|
|
|
it('should re-align the ink bar when the tabs list change', fakeAsync(() => {
|
|
const inkBar = fixture.componentInstance.tabNavBar._inkBar;
|
|
|
|
spyOn(inkBar, 'alignToElement');
|
|
|
|
fixture.componentInstance.tabs = [1, 2, 3, 4];
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
expect(inkBar.alignToElement).toHaveBeenCalled();
|
|
}));
|
|
|
|
it('should re-align the ink bar when the tab labels change the width', done => {
|
|
const inkBar = fixture.componentInstance.tabNavBar._inkBar;
|
|
|
|
const spy = spyOn(inkBar, 'alignToElement').and.callFake(() => {
|
|
expect(spy.calls.any()).toBe(true);
|
|
done();
|
|
});
|
|
|
|
fixture.componentInstance.label = 'label change';
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(spy.calls.any()).toBe(false);
|
|
});
|
|
|
|
it('should re-align the ink bar when the nav bar is resized', fakeAsync(() => {
|
|
const inkBar = fixture.componentInstance.tabNavBar._inkBar;
|
|
|
|
spyOn(inkBar, 'alignToElement');
|
|
|
|
resizeEvents.next([]);
|
|
fixture.detectChanges();
|
|
tick(32);
|
|
|
|
expect(inkBar.alignToElement).toHaveBeenCalled();
|
|
}));
|
|
|
|
it('should hide the ink bar when all the links are inactive', () => {
|
|
const inkBar = fixture.componentInstance.tabNavBar._inkBar;
|
|
|
|
spyOn(inkBar, 'hide');
|
|
|
|
fixture.componentInstance.tabLinks.forEach(link => (link.active = false));
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(inkBar.hide).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should update the focusIndex when a tab receives focus directly', () => {
|
|
const thirdLink = fixture.debugElement.queryAll(By.css('a'))[2];
|
|
dispatchFakeEvent(thirdLink.nativeElement, 'focus');
|
|
fixture.detectChanges();
|
|
|
|
expect(fixture.componentInstance.tabNavBar.focusIndex).toBe(2);
|
|
});
|
|
});
|
|
|
|
it('should hide the ink bar if no tabs are active on init', fakeAsync(() => {
|
|
const fixture = TestBed.createComponent(TabBarWithInactiveTabsOnInit);
|
|
fixture.detectChanges();
|
|
tick(20); // Angular turns rAF calls into 16.6ms timeouts in tests.
|
|
fixture.detectChanges();
|
|
|
|
expect(fixture.nativeElement.querySelectorAll('.mdc-tab-indicator--active').length).toBe(0);
|
|
}));
|
|
|
|
it('should clean up the ripple event handlers on destroy', () => {
|
|
let fixture: ComponentFixture<TabLinkWithNgIf> = TestBed.createComponent(TabLinkWithNgIf);
|
|
fixture.detectChanges();
|
|
|
|
let link = fixture.debugElement.nativeElement.querySelector('.mat-mdc-tab-link');
|
|
|
|
fixture.componentInstance.isDestroyed = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
dispatchMouseEvent(link, 'mousedown');
|
|
|
|
expect(link.querySelector('.mat-ripple-element'))
|
|
.withContext('Expected no ripple to be created when ripple target is destroyed.')
|
|
.toBeFalsy();
|
|
});
|
|
|
|
it('should select the proper tab, if the tabs come in after init', () => {
|
|
const fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
const instance = fixture.componentInstance;
|
|
|
|
instance.tabs = [];
|
|
instance.activeIndex = 1;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(instance.tabNavBar.selectedIndex).toBe(-1);
|
|
|
|
instance.tabs = [0, 1, 2];
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(instance.tabNavBar.selectedIndex).toBe(1);
|
|
});
|
|
|
|
it('should have the proper roles', () => {
|
|
const fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.detectChanges();
|
|
|
|
const tabBar = fixture.nativeElement.querySelector('.mat-mdc-tab-nav-bar')!;
|
|
expect(tabBar.getAttribute('role')).toBe('tablist');
|
|
|
|
const tabLinks = fixture.nativeElement.querySelectorAll('.mat-mdc-tab-link');
|
|
|
|
expect(tabLinks[0].getAttribute('role')).toBe('tab');
|
|
expect(tabLinks[1].getAttribute('role')).toBe('tab');
|
|
expect(tabLinks[2].getAttribute('role')).toBe('tab');
|
|
|
|
const tabPanel = fixture.nativeElement.querySelector('.mat-mdc-tab-nav-panel')!;
|
|
expect(tabPanel.getAttribute('role')).toBe('tabpanel');
|
|
});
|
|
|
|
it('should manage tabindex properly', () => {
|
|
const fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.detectChanges();
|
|
|
|
const tabLinks = fixture.nativeElement.querySelectorAll('.mat-mdc-tab-link');
|
|
expect(tabLinks[0].tabIndex).toBe(0);
|
|
expect(tabLinks[1].tabIndex).toBe(-1);
|
|
expect(tabLinks[2].tabIndex).toBe(-1);
|
|
|
|
tabLinks[1].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(tabLinks[0].tabIndex).toBe(-1);
|
|
expect(tabLinks[1].tabIndex).toBe(0);
|
|
expect(tabLinks[2].tabIndex).toBe(-1);
|
|
});
|
|
|
|
it('should setup aria-controls properly', () => {
|
|
const fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.detectChanges();
|
|
|
|
const tabLinks = fixture.nativeElement.querySelectorAll('.mat-mdc-tab-link');
|
|
expect(tabLinks[0].getAttribute('aria-controls')).toBe('tab-panel');
|
|
expect(tabLinks[1].getAttribute('aria-controls')).toBe('tab-panel');
|
|
expect(tabLinks[2].getAttribute('aria-controls')).toBe('tab-panel');
|
|
});
|
|
|
|
it('should not manage aria-current', () => {
|
|
const fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.detectChanges();
|
|
|
|
const tabLinks = fixture.nativeElement.querySelectorAll('.mat-mdc-tab-link');
|
|
expect(tabLinks[0].getAttribute('aria-current')).toBe(null);
|
|
expect(tabLinks[1].getAttribute('aria-current')).toBe(null);
|
|
expect(tabLinks[2].getAttribute('aria-current')).toBe(null);
|
|
});
|
|
|
|
it('should manage aria-selected properly', () => {
|
|
const fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.detectChanges();
|
|
|
|
const tabLinks = fixture.nativeElement.querySelectorAll('.mat-mdc-tab-link');
|
|
expect(tabLinks[0].getAttribute('aria-selected')).toBe('true');
|
|
expect(tabLinks[1].getAttribute('aria-selected')).toBe('false');
|
|
expect(tabLinks[2].getAttribute('aria-selected')).toBe('false');
|
|
|
|
tabLinks[1].click();
|
|
fixture.detectChanges();
|
|
|
|
expect(tabLinks[0].getAttribute('aria-selected')).toBe('false');
|
|
expect(tabLinks[1].getAttribute('aria-selected')).toBe('true');
|
|
expect(tabLinks[2].getAttribute('aria-selected')).toBe('false');
|
|
});
|
|
|
|
it('should activate a link when space is pressed', () => {
|
|
const fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.detectChanges();
|
|
|
|
const tabLinks = fixture.nativeElement.querySelectorAll('.mat-mdc-tab-link');
|
|
expect(tabLinks[1].classList.contains('mdc-tab--active')).toBe(false);
|
|
|
|
dispatchKeyboardEvent(tabLinks[1], 'keydown', SPACE);
|
|
fixture.detectChanges();
|
|
|
|
expect(tabLinks[1].classList.contains('mdc-tab--active')).toBe(true);
|
|
});
|
|
|
|
it('should activate a link when enter is pressed', () => {
|
|
const fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.detectChanges();
|
|
|
|
const tabLinks = fixture.nativeElement.querySelectorAll('.mat-mdc-tab-link');
|
|
expect(tabLinks[1].classList.contains('mdc-tab--active')).toBe(false);
|
|
|
|
dispatchKeyboardEvent(tabLinks[1], 'keydown', ENTER);
|
|
fixture.detectChanges();
|
|
|
|
expect(tabLinks[1].classList.contains('mdc-tab--active')).toBe(true);
|
|
});
|
|
|
|
it('should re-show the ink bar if the same tab is cleared and re-activated', fakeAsync(() => {
|
|
const getInkBars = () =>
|
|
fixture.nativeElement.querySelectorAll('.mdc-tab-indicator--active').length;
|
|
const fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.componentInstance.activeIndex = 0;
|
|
fixture.detectChanges();
|
|
tick(20);
|
|
expect(getInkBars()).toBe(1);
|
|
|
|
fixture.componentInstance.activeIndex = -1;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
tick(20);
|
|
expect(getInkBars()).toBe(0);
|
|
|
|
fixture.componentInstance.activeIndex = 0;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
tick(20);
|
|
expect(getInkBars()).toBe(1);
|
|
}));
|
|
|
|
describe('ripples', () => {
|
|
let fixture: ComponentFixture<SimpleTabNavBarTestApp>;
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.detectChanges();
|
|
});
|
|
|
|
it('should be disabled on all tab links when they are disabled on the nav bar', () => {
|
|
expect(fixture.componentInstance.tabLinks.toArray().every(tabLink => !tabLink.rippleDisabled))
|
|
.withContext('Expected every tab link to have ripples enabled')
|
|
.toBe(true);
|
|
|
|
fixture.componentInstance.disableRippleOnBar = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(fixture.componentInstance.tabLinks.toArray().every(tabLink => tabLink.rippleDisabled))
|
|
.withContext('Expected every tab link to have ripples disabled')
|
|
.toBe(true);
|
|
});
|
|
|
|
it('should have the `disableRipple` from the tab take precedence over the nav bar', () => {
|
|
const firstTab = fixture.componentInstance.tabLinks.first;
|
|
|
|
expect(firstTab.rippleDisabled)
|
|
.withContext('Expected ripples to be enabled on first tab')
|
|
.toBe(false);
|
|
|
|
firstTab.disableRipple = true;
|
|
fixture.componentInstance.disableRippleOnBar = false;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
expect(firstTab.rippleDisabled)
|
|
.withContext('Expected ripples to be disabled on first tab')
|
|
.toBe(true);
|
|
});
|
|
|
|
it('should show up for tab link elements on mousedown', () => {
|
|
const tabLink = fixture.debugElement.nativeElement.querySelector('.mat-mdc-tab-link');
|
|
|
|
dispatchMouseEvent(tabLink, 'mousedown');
|
|
dispatchMouseEvent(tabLink, 'mouseup');
|
|
|
|
expect(tabLink.querySelectorAll('.mat-ripple-element').length)
|
|
.withContext('Expected one ripple to show up if user clicks on tab link.')
|
|
.toBe(1);
|
|
});
|
|
|
|
it('should be able to disable ripples on an individual tab link', () => {
|
|
const tabLinkDebug = fixture.debugElement.query(By.css('a'));
|
|
const tabLinkElement = tabLinkDebug.nativeElement;
|
|
|
|
fixture.componentInstance.disableRippleOnLink = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
dispatchMouseEvent(tabLinkElement, 'mousedown');
|
|
dispatchMouseEvent(tabLinkElement, 'mouseup');
|
|
|
|
expect(tabLinkElement.querySelectorAll('.mat-ripple-element').length)
|
|
.withContext('Expected no ripple to show up if ripples are disabled.')
|
|
.toBe(0);
|
|
});
|
|
|
|
it('should be able to disable ripples through global options at runtime', () => {
|
|
expect(fixture.componentInstance.tabLinks.toArray().every(tabLink => !tabLink.rippleDisabled))
|
|
.withContext('Expected every tab link to have ripples enabled')
|
|
.toBe(true);
|
|
|
|
globalRippleOptions.disabled = true;
|
|
|
|
expect(fixture.componentInstance.tabLinks.toArray().every(tabLink => tabLink.rippleDisabled))
|
|
.withContext('Expected every tab link to have ripples disabled')
|
|
.toBe(true);
|
|
});
|
|
|
|
it('should have a focus indicator', () => {
|
|
const tabLinkNativeElements = [
|
|
...fixture.debugElement.nativeElement.querySelectorAll('.mat-mdc-tab-link'),
|
|
];
|
|
|
|
expect(
|
|
tabLinkNativeElements.every(element => element.classList.contains('mat-focus-indicator')),
|
|
).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('with the ink bar fit to content', () => {
|
|
let fixture: ComponentFixture<SimpleTabNavBarTestApp>;
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(SimpleTabNavBarTestApp);
|
|
fixture.componentInstance.fitInkBarToContent = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
});
|
|
|
|
it('should properly nest the ink bar when fit to content', () => {
|
|
const tabElement = fixture.nativeElement.querySelector('.mdc-tab');
|
|
const contentElement = tabElement.querySelector('.mdc-tab__content');
|
|
const indicatorElement = tabElement.querySelector('.mdc-tab-indicator');
|
|
expect(indicatorElement.parentElement).toBeTruthy();
|
|
expect(indicatorElement.parentElement).toBe(contentElement);
|
|
});
|
|
|
|
it('should be able to move the ink bar between content and full', () => {
|
|
fixture.componentInstance.fitInkBarToContent = false;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
const tabElement = fixture.nativeElement.querySelector('.mdc-tab');
|
|
const indicatorElement = tabElement.querySelector('.mdc-tab-indicator');
|
|
expect(indicatorElement.parentElement).toBeTruthy();
|
|
expect(indicatorElement.parentElement).toBe(tabElement);
|
|
|
|
fixture.componentInstance.fitInkBarToContent = true;
|
|
fixture.changeDetectorRef.markForCheck();
|
|
fixture.detectChanges();
|
|
|
|
const contentElement = tabElement.querySelector('.mdc-tab__content');
|
|
expect(indicatorElement.parentElement).toBeTruthy();
|
|
expect(indicatorElement.parentElement).toBe(contentElement);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('MatTabNavBar with a default config', () => {
|
|
let fixture: ComponentFixture<TabLinkWithNgIf>;
|
|
|
|
beforeEach(fakeAsync(() => {
|
|
TestBed.configureTestingModule({
|
|
imports: [MatTabsModule, BrowserAnimationsModule, TabLinkWithNgIf],
|
|
providers: [{provide: MAT_TABS_CONFIG, useValue: {fitInkBarToContent: true}}],
|
|
});
|
|
}));
|
|
|
|
beforeEach(() => {
|
|
fixture = TestBed.createComponent(TabLinkWithNgIf);
|
|
fixture.detectChanges();
|
|
});
|
|
|
|
it('should set whether the ink bar fits to content', () => {
|
|
const tabElement = fixture.nativeElement.querySelector('.mdc-tab');
|
|
const contentElement = tabElement.querySelector('.mdc-tab__content');
|
|
const indicatorElement = tabElement.querySelector('.mdc-tab-indicator');
|
|
expect(indicatorElement.parentElement).toBeTruthy();
|
|
expect(indicatorElement.parentElement).toBe(contentElement);
|
|
});
|
|
});
|
|
|
|
describe('MatTabNavBar with enabled animations', () => {
|
|
beforeEach(fakeAsync(() => {
|
|
TestBed.configureTestingModule({
|
|
imports: [MatTabsModule, BrowserAnimationsModule, TabsWithCustomAnimationDuration],
|
|
});
|
|
}));
|
|
|
|
it('should not throw when setting an animationDuration without units', fakeAsync(() => {
|
|
expect(() => {
|
|
let fixture = TestBed.createComponent(TabsWithCustomAnimationDuration);
|
|
fixture.detectChanges();
|
|
tick();
|
|
}).not.toThrow();
|
|
}));
|
|
|
|
it('should set appropiate css variable given a specified animationDuration', fakeAsync(() => {
|
|
let fixture = TestBed.createComponent(TabsWithCustomAnimationDuration);
|
|
fixture.detectChanges();
|
|
tick();
|
|
|
|
const tabNavBar = fixture.nativeElement.querySelector('.mat-mdc-tab-nav-bar');
|
|
expect(tabNavBar.style.getPropertyValue('--mat-tab-animation-duration')).toBe('500ms');
|
|
}));
|
|
});
|
|
|
|
@Component({
|
|
selector: 'test-app',
|
|
template: `
|
|
<nav mat-tab-nav-bar
|
|
[disableRipple]="disableRippleOnBar"
|
|
[fitInkBarToContent]="fitInkBarToContent"
|
|
[tabPanel]="tabPanel">
|
|
@for (tab of tabs; track tab; let index = $index) {
|
|
<a mat-tab-link
|
|
[active]="activeIndex === index"
|
|
[disabled]="disabled"
|
|
(click)="activeIndex = index"
|
|
[disableRipple]="disableRippleOnLink">Tab link {{label}}</a>
|
|
}
|
|
</nav>
|
|
<mat-tab-nav-panel #tabPanel id="tab-panel">Tab panel</mat-tab-nav-panel>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatTabsModule],
|
|
})
|
|
class SimpleTabNavBarTestApp {
|
|
@ViewChild(MatTabNav) tabNavBar: MatTabNav;
|
|
@ViewChildren(MatTabLink) tabLinks: QueryList<MatTabLink>;
|
|
|
|
label = '';
|
|
disabled = false;
|
|
disableRippleOnBar = false;
|
|
disableRippleOnLink = false;
|
|
tabs = [0, 1, 2];
|
|
fitInkBarToContent = false;
|
|
|
|
activeIndex = 0;
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<nav mat-tab-nav-bar [tabPanel]="tabPanel">
|
|
@if (!isDestroyed) {
|
|
<a mat-tab-link>Link</a>
|
|
}
|
|
</nav>
|
|
<mat-tab-nav-panel #tabPanel>Tab panel</mat-tab-nav-panel>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatTabsModule],
|
|
})
|
|
class TabLinkWithNgIf {
|
|
isDestroyed = false;
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<nav mat-tab-nav-bar [tabPanel]="tabPanel">
|
|
@for (tab of tabs; track tab) {
|
|
<a mat-tab-link [active]="false">Tab link {{label}}</a>
|
|
}
|
|
</nav>
|
|
<mat-tab-nav-panel #tabPanel>Tab panel</mat-tab-nav-panel>
|
|
`,
|
|
standalone: true,
|
|
imports: [MatTabsModule],
|
|
})
|
|
class TabBarWithInactiveTabsOnInit {
|
|
tabs = [0, 1, 2];
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<nav [animationDuration]="500" mat-tab-nav-bar [tabPanel]="tabPanel">
|
|
@for (link of links; track link) {
|
|
<a mat-tab-link>{{link}}</a>
|
|
}
|
|
</nav>
|
|
<mat-tab-nav-panel #tabPanel></mat-tab-nav-panel>,
|
|
`,
|
|
standalone: true,
|
|
imports: [MatTabsModule],
|
|
})
|
|
class TabsWithCustomAnimationDuration {
|
|
links = ['First', 'Second', 'Third'];
|
|
}
|