Skip to content

Commit aadba31

Browse files
committed
test(aria/tabs): generate additional tests for Tab directives and patterns
1 parent 26409c0 commit aadba31

3 files changed

Lines changed: 112 additions & 12 deletions

File tree

src/aria/private/tabs/tabs.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,4 +420,21 @@ describe('Tabs Pattern', () => {
420420
expect(tabPanelPatterns[2].labelledBy()).toBe('tab-3-id');
421421
});
422422
});
423+
424+
describe('ActiveDescendant mode', () => {
425+
beforeEach(() => {
426+
tabListInputs.focusMode.set('activedescendant');
427+
tabListPattern.setDefaultState();
428+
});
429+
430+
it('should update activeDescendant when navigating', () => {
431+
expect(tabListPattern.activeDescendant()).toBe('tab-1-id');
432+
433+
tabListPattern.onKeydown(right());
434+
expect(tabListPattern.activeDescendant()).toBe('tab-2-id');
435+
436+
tabListPattern.onKeydown(right());
437+
expect(tabListPattern.activeDescendant()).toBe('tab-3-id');
438+
});
439+
});
423440
});

src/aria/tabs/tabs.spec.ts

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -495,23 +495,23 @@ describe('Tabs', () => {
495495
],
496496
});
497497

498-
const tabsDebugElement = fixture.debugElement.query(By.directive(Tabs));
499-
const tabsDirective = tabsDebugElement.injector.get(Tabs);
500-
501-
let orderedItems = tabsDirective._collection.orderedItems();
502-
expect(orderedItems.length).toBe(3);
503-
expect(orderedItems[0].value()).toBe('tab1');
504-
expect(orderedItems[2].value()).toBe('tab3');
498+
// Verify initial DOM order
499+
expect(tabElements.length).toBe(3);
500+
expect(tabElements[0].textContent?.trim()).toBe('Tab 1');
501+
expect(tabElements[2].textContent?.trim()).toBe('Tab 3');
505502

503+
// Shuffle (reverse) data
506504
const items = testComponent.tabsData().reverse();
507505
testComponent.tabsData.set([...items]);
508506
fixture.detectChanges();
509507
await waitForMicrotasks();
510508

511-
orderedItems = tabsDirective._collection.orderedItems();
512-
expect(orderedItems.length).toBe(3);
513-
expect(orderedItems[0].value()).toBe('tab3');
514-
expect(orderedItems[2].value()).toBe('tab1');
509+
// Re-query elements to check new DOM order
510+
defineTestVariables();
511+
512+
expect(tabElements.length).toBe(3);
513+
expect(tabElements[0].textContent?.trim()).toBe('Tab 3');
514+
expect(tabElements[2].textContent?.trim()).toBe('Tab 1');
515515
});
516516
});
517517

@@ -740,6 +740,72 @@ describe('Tabs', () => {
740740
expect(tabPanelElements[2].hasAttribute('inert')).toBe(true);
741741
});
742742
});
743+
744+
describe('Dynamic tabs', () => {
745+
beforeEach(() => {
746+
setupTestTabs();
747+
updateTabs({
748+
initialTabs: [
749+
{value: 'tab1', label: 'Tab 1', content: 'Content 1'},
750+
{value: 'tab2', label: 'Tab 2', content: 'Content 2'},
751+
{value: 'tab3', label: 'Tab 3', content: 'Content 3'},
752+
],
753+
selectedTab: 'tab2',
754+
});
755+
});
756+
757+
it('should update selection when active tab is removed', () => {
758+
expect(testComponent.selectedTab()).toBe('tab2');
759+
760+
testComponent.tabsData.set([
761+
{value: 'tab1', label: 'Tab 1', content: 'Content 1'},
762+
{value: 'tab3', label: 'Tab 3', content: 'Content 3'},
763+
]);
764+
fixture.detectChanges();
765+
defineTestVariables();
766+
767+
expect(testComponent.selectedTab()).toBeUndefined();
768+
});
769+
770+
it('should maintain selection when a new tab is added', () => {
771+
expect(testComponent.selectedTab()).toBe('tab2');
772+
773+
testComponent.tabsData.set([
774+
{value: 'tab1', label: 'Tab 1', content: 'Content 1'},
775+
{value: 'tab2', label: 'Tab 2', content: 'Content 2'},
776+
{value: 'tab3', label: 'Tab 3', content: 'Content 3'},
777+
{value: 'tab4', label: 'Tab 4', content: 'Content 4'},
778+
]);
779+
fixture.detectChanges();
780+
defineTestVariables();
781+
782+
expect(testComponent.selectedTab()).toBe('tab2');
783+
});
784+
});
785+
786+
describe('Custom IDs', () => {
787+
let customIdFixture: ComponentFixture<TestTabsCustomIdComponent>;
788+
789+
beforeEach(() => {
790+
TestBed.configureTestingModule({
791+
providers: [provideFakeDirectionality('ltr')],
792+
});
793+
customIdFixture = TestBed.createComponent(TestTabsCustomIdComponent);
794+
fixture = customIdFixture as any;
795+
customIdFixture.detectChanges();
796+
});
797+
798+
it('should use custom ID for tab and link to panel', async () => {
799+
const tabEl = customIdFixture.nativeElement.querySelector('#custom-tab-id');
800+
const panelEl = customIdFixture.nativeElement.querySelector('#custom-panel-id');
801+
802+
expect(tabEl).toBeTruthy();
803+
expect(panelEl).toBeTruthy();
804+
805+
expect(tabEl.getAttribute('aria-controls')).toBe('custom-panel-id');
806+
expect(panelEl.getAttribute('aria-labelledby')).toBe('custom-tab-id');
807+
});
808+
});
743809
});
744810

745811
@Component({
@@ -798,3 +864,21 @@ class TestTabsComponent {
798864
focusMode = signal<'roving' | 'activedescendant'>('roving');
799865
selectionMode = signal<'follow' | 'explicit'>('follow');
800866
}
867+
868+
@Component({
869+
template: `
870+
<div ngTabs>
871+
<ul ngTabList [(selectedTab)]="selectedTab">
872+
<li ngTab value="tab1" id="custom-tab-id">Tab 1</li>
873+
</ul>
874+
<div ngTabPanel value="tab1" id="custom-panel-id">
875+
<ng-template ngTabContent>Content 1</ng-template>
876+
</div>
877+
</div>
878+
`,
879+
imports: [Tabs, TabList, Tab, TabPanel, TabContent],
880+
changeDetection: ChangeDetectionStrategy.Eager,
881+
})
882+
class TestTabsCustomIdComponent {
883+
selectedTab = signal('tab1');
884+
}

src/aria/tabs/testing/tabs-harness.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ describe('TabsHarness', () => {
137137
<li ngTab value="tab3" [disabled]="true">Tab 3</li>
138138
</ul>
139139
140-
141140
<div ngTabPanel value="tab1">
142141
<ng-template ngTabContent>
143142
<div class="test-content">Content 1</div>

0 commit comments

Comments
 (0)