/// /// Copyright 2015-2026 Micro Focus or one of its affiliates. /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// import { Component, QueryList, ViewChildren } from '@angular/core'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { TreeGridItem, TreeGridModule, TreeGridRowDirective } from './index'; interface TreeGridTestItem extends TreeGridItem { title: string; children?: TreeGridTestItem[]; } @Component({ selector: 'tree-grid-test', template: ` @for (row of rows; track row) { }
{{ row.title }}
`, imports: [TreeGridModule], }) export class TreeGridTestComponent { items: TreeGridTestItem[] = []; rows: TreeGridTestItem[]; @ViewChildren(TreeGridRowDirective) rowDirectives: QueryList; // eslint-disable-next-line @typescript-eslint/no-empty-function expandedChange(row: TreeGridTestItem, expanded: boolean): void {} } describe('Tree Grid', () => { let component: TreeGridTestComponent; let fixture: ComponentFixture; let nativeElement: HTMLElement; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [TreeGridModule, TreeGridTestComponent], }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(TreeGridTestComponent); component = fixture.componentInstance; nativeElement = fixture.nativeElement; }); describe('with collapsed rows', () => { beforeEach(async () => { spyOn(component, 'expandedChange'); component.items = [ { title: 'Root 1', children: [ { title: 'Node 1', children: [ { title: 'Leaf 1', }, ], }, ], }, { title: 'Root 2', }, ]; fixture.detectChanges(); await fixture.whenStable(); }); it('should initially render top-level rows', () => { const titles = getRowTitles(); expect(titles.length).toBe(2); expect(titles[0]).toBe('Root 1'); expect(titles[1]).toBe('Root 2'); expect(component.expandedChange).toHaveBeenCalledTimes(0); }); it('should insert child rows when expanded', async () => { component.rowDirectives.first.expand(); fixture.detectChanges(); await fixture.whenStable(); const titles = getRowTitles(); expect(titles.length).toBe(3); expect(titles[0]).toBe('Root 1'); expect(titles[1]).toBe('Node 1'); expect(titles[2]).toBe('Root 2'); expect(component.expandedChange).toHaveBeenCalledTimes(1); }); it('should insert child rows when expanded programmatically', async () => { component.items[0].expanded = true; fixture.detectChanges(); await fixture.whenStable(); const titles = getRowTitles(); expect(titles.length).toBe(3); expect(titles[0]).toBe('Root 1'); expect(titles[1]).toBe('Node 1'); expect(titles[2]).toBe('Root 2'); expect(component.expandedChange).toHaveBeenCalledTimes(0); }); }); describe('with pre-expanded rows', () => { beforeEach(async () => { spyOn(component, 'expandedChange'); component.items = [ { title: 'Root', expanded: true, children: [ { title: 'Node 1', children: [ { title: 'Leaf 1', }, ], }, ], }, ]; fixture.detectChanges(); await fixture.whenStable(); }); it('should initially render children of pre-expanded rows', () => { const titles = getRowTitles(); expect(titles.length).toBe(2); expect(titles[0]).toBe('Root'); expect(titles[1]).toBe('Node 1'); expect(component.expandedChange).toHaveBeenCalledTimes(0); }); it('should remove child rows when collapsed', async () => { component.rowDirectives.first.collapse(); fixture.detectChanges(); await fixture.whenStable(); const titles = getRowTitles(); expect(titles.length).toBe(1); expect(titles[0]).toBe('Root'); expect(component.expandedChange).toHaveBeenCalledTimes(1); }); it('should remove child rows when collapsed programmatically', async () => { component.items[0].expanded = false; fixture.detectChanges(); await fixture.whenStable(); const titles = getRowTitles(); expect(titles.length).toBe(1); expect(titles[0]).toBe('Root'); expect(component.expandedChange).toHaveBeenCalledTimes(0); }); }); function getRowElements(): HTMLTableRowElement[] { return Array.from(nativeElement.querySelectorAll('tr')); } function getRowTitles(): string[] { return getRowElements().map(row => row.innerText); } });