///
/// 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);
}
});