import { Component, ViewChild } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { CommonModule } from "@angular/common";
import { RIGHT_ARROW, LEFT_ARROW, ENTER } from "@angular/cdk/keycodes";
import { MdTabHeader, MdTabLabelWrapper } from "./index";
@Component({
template: `
{{ label }}
`,
standalone: false,
})
class HostComponent {
selectedIndex = 0;
labels = ["One", "Two", "Three"];
disabledIndexes = new Set();
@ViewChild(MdTabHeader) tabHeader: MdTabHeader;
}
function dispatchKeydown(target: Element, keyCode: number): void {
const event = new KeyboardEvent("keydown", {
bubbles: true,
cancelable: true,
});
// jsdom's KeyboardEvent constructor does not honor a `keyCode` init
// property, so it must be defined explicitly to match what real browsers
// report for legacy `event.keyCode` consumers like `_handleKeydown`.
Object.defineProperty(event, "keyCode", { get: () => keyCode });
target.dispatchEvent(event);
}
describe("The Sam Tab Header component", () => {
let fixture: ComponentFixture;
let host: HostComponent;
let tabListContainer: HTMLElement;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [HostComponent, MdTabHeader, MdTabLabelWrapper],
imports: [CommonModule],
});
fixture = TestBed.createComponent(HostComponent);
host = fixture.componentInstance;
fixture.detectChanges();
fixture.detectChanges();
tabListContainer = fixture.nativeElement.querySelector(
".mat-tab-label-container"
);
});
it("should render a label wrapper for each label without throwing", () => {
const wrappers = fixture.nativeElement.querySelectorAll(
"[md-tab-label-wrapper]"
);
expect(wrappers.length).toBe(3);
});
it("should move focus to the next valid tab on ArrowRight", () => {
dispatchKeydown(tabListContainer, RIGHT_ARROW);
expect(host.tabHeader.focusIndex).toBe(1);
});
it("should move focus to the previous valid tab on ArrowLeft", () => {
host.tabHeader.focusIndex = 1;
dispatchKeydown(tabListContainer, LEFT_ARROW);
expect(host.tabHeader.focusIndex).toBe(0);
});
it("should emit selectFocusedIndex when Enter is pressed", () => {
const emitted: number[] = [];
host.tabHeader.selectFocusedIndex.subscribe((index) => emitted.push(index));
host.tabHeader.focusIndex = 2;
dispatchKeydown(tabListContainer, ENTER);
expect(emitted).toEqual([2]);
});
it("should skip disabled tabs when moving focus forward", () => {
host.disabledIndexes.add(1);
fixture.detectChanges();
dispatchKeydown(tabListContainer, RIGHT_ARROW);
expect(host.tabHeader.focusIndex).toBe(2);
});
it("should not move focus past the last tab", () => {
host.tabHeader.focusIndex = 2;
dispatchKeydown(tabListContainer, RIGHT_ARROW);
expect(host.tabHeader.focusIndex).toBe(2);
});
it("should update selectedIndex when set via the selectedIndex input", () => {
host.selectedIndex = 2;
fixture.detectChanges();
fixture.detectChanges();
expect(host.tabHeader.selectedIndex).toBe(2);
});
it("should coerce disableRipple to a boolean", () => {
host.tabHeader.disableRipple = "false" as unknown as boolean;
expect(host.tabHeader.disableRipple).toBe(false);
host.tabHeader.disableRipple = true;
expect(host.tabHeader.disableRipple).toBe(true);
});
it("should treat all tabs as valid when label wrappers are not yet available", () => {
expect(host.tabHeader._isValidIndex(0)).toBe(true);
});
});