UNPKG

igniteui-angular-sovn

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

2,111 lines 105 kB
import { configureTestSuite } from '../../test-utils/configure-suite';
import { TestBed, fakeAsync, tick, ComponentFixture, waitForAsync } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { IGridCreatedEventArgs } from './public_api';
import { ChangeDetectorRef, Component, ViewChild, AfterViewInit, QueryList } from '@angular/core';
import { IgxChildGridRowComponent, IgxHierarchicalGridComponent } from './hierarchical-grid.component';
import { wait, UIInteractions } from '../../test-utils/ui-interactions.spec';
import { IgxRowIslandComponent } from './row-island.component';
import { IgxHierarchicalRowComponent } from './hierarchical-row.component';
import { By } from '@angular/platform-browser';
import { DisplayDensity } from '../../core/density';
import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition';
import { IgxHeaderCollapsedIndicatorDirective, IgxHeaderExpandedIndicatorDirective, IgxRowCollapsedIndicatorDirective, IgxRowExpandedIndicatorDirective } from '../grid/public_api';
import { GridSelectionMode } from '../common/enums';
import { GridFunctions } from '../../test-utils/grid-functions.spec';
import { IgxGridCellComponent } from '../cell.component';
import { NgFor, NgIf } from '@angular/common';
import { IgxIconComponent } from '../../icon/icon.component';
import { IgxExcelStyleColumnOperationsTemplateDirective, IgxExcelStyleFilterOperationsTemplateDirective, IgxGridExcelStyleFilteringComponent } from '../filtering/excel-style/excel-style-filtering.component';
import { IgxExcelStyleHeaderComponent } from '../filtering/excel-style/excel-style-header.component';
import { IgxExcelStyleSortingComponent } from '../filtering/excel-style/excel-style-sorting.component';
import { IgxExcelStyleSearchComponent } from '../filtering/excel-style/excel-style-search.component';
import { IgxCellHeaderTemplateDirective } from '../columns/templates.directive';
import { CellType, ColumnType, IGridCellEventArgs, IgxColumnComponent, IgxRowEditActionsDirective, IgxRowEditTextDirective } from '../public_api';

describe('Basic IgxHierarchicalGrid #hGrid', () => {
    configureTestSuite();

    beforeAll(waitForAsync(() => {
        TestBed.configureTestingModule({
            imports: [
                NoopAnimationsModule,
                IgxHierarchicalGridTestBaseComponent,
                IgxHierarchicalGridMultiLayoutComponent,
                IgxHierarchicalGridSizingComponent,
                IgxHGridRemoteOnDemandComponent,
                IgxHierarchicalGridColumnsUpdateComponent,
                IgxHierarchicalGridHidingPinningColumnsComponent,
                IgxHierarchicalGridToggleRIComponent,
                IgxHierarchicalGridCustomRowEditOverlayComponent,
                IgxHierarchicalGridAutoSizeColumnsComponent,
                IgxHierarchicalGridCustomTemplateComponent,
                IgxHierarchicalGridCustomFilteringTemplateComponent,
                IgxHierarchicalGridToggleRIAndColsComponent
            ]
        }).compileComponents();
    }))

    describe('Init IgxHierarchicalGrid #hGrid', () => {
        let fixture;
        let hierarchicalGrid: IgxHierarchicalGridComponent;

        beforeEach(() => {
            fixture = TestBed.createComponent(IgxHierarchicalGridTestBaseComponent);
            fixture.detectChanges();
            hierarchicalGrid = fixture.componentInstance.hgrid;
        });

        it('should render expansion indicator as the first element of each expandable row.', () => {
            fixture.componentInstance.data = [
                {ID: 0, ProductName: 'Product: A0'},
                {ID: 1, ProductName: 'Product: A1', childData: fixture.componentInstance.generateDataUneven(1, 1)},
                {ID: 2, ProductName: 'Product: A2', childData: fixture.componentInstance.generateDataUneven(1, 1)}
            ];
            fixture.detectChanges();
            const row1 = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            expect(row1.hasChildren).toBe(true);
            const rowElems = fixture.debugElement.queryAll(By.directive(IgxHierarchicalRowComponent));
            expect(rowElems[0].query(By.css('igx-icon')).nativeElement.innerText).toEqual('chevron_right');
            const row2 = hierarchicalGrid.gridAPI.get_row_by_index(1) as IgxHierarchicalRowComponent;
            expect(row2.hasChildren).toBe(true);
            expect(rowElems[1].query(By.css('igx-icon')).nativeElement.innerText).toEqual('chevron_right');

            const row3 = hierarchicalGrid.gridAPI.get_row_by_index(1) as IgxHierarchicalRowComponent;
            expect(row3.hasChildren).toBe(true);
            expect(rowElems[2].query(By.css('igx-icon')).nativeElement.innerText).toEqual('chevron_right');
        });

        it('should allow expand/collapse rows through the UI', () => {
            const row1 = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            expect(row1.expanded).toBe(false);
            UIInteractions.simulateClickAndSelectEvent(row1.expander);
            fixture.detectChanges();
            expect(row1.expanded).toBe(true);
            expect(hierarchicalGrid.gridAPI.getChildGrids(false).length).toBe(1);
            expect(hierarchicalGrid.gridAPI.get_row_by_index(1) instanceof IgxChildGridRowComponent).toBe(true);
            UIInteractions.simulateClickAndSelectEvent(row1.expander);
            fixture.detectChanges();
            expect(row1.expanded).toBe(false);
            expect(hierarchicalGrid.gridAPI.get_row_by_index(1) instanceof IgxHierarchicalRowComponent).toBe(true);
        });

        it('should change expand/collapse indicators when state of the row changes', () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            const rowElem = fixture.debugElement.queryAll(By.directive(IgxHierarchicalRowComponent))[0];
            expect(rowElem.query(By.css('igx-icon')).nativeElement.innerText).toEqual('chevron_right');
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            expect(rowElem.query(By.css('igx-icon')).nativeElement.innerText).toEqual('expand_more');
        });

        it('should collapse all rows that belongs to a grid via header collapse icon', () => {
            const headerExpanderElem = fixture.debugElement.queryAll(By.css('.igx-grid__hierarchical-expander--header'))[0];
            let icon = headerExpanderElem.query(By.css('igx-icon')).componentInstance;
            let iconTxt = headerExpanderElem.query(By.css('igx-icon')).nativeElement.textContent.toLowerCase();
            expect(iconTxt).toBe('unfold_less');
            expect(icon.getActive).toBe(false);
            // expand row
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            icon = headerExpanderElem.query(By.css('igx-icon')).componentInstance;
            iconTxt = headerExpanderElem.query(By.css('igx-icon')).nativeElement.textContent.toLowerCase();
            expect(iconTxt).toBe('unfold_less');
            expect(icon.getActive).toBe(true);
            expect(hierarchicalGrid.expansionStates.size).toEqual(1);

            UIInteractions.simulateClickAndSelectEvent(icon.el);
            fixture.detectChanges();
            const rows = hierarchicalGrid.dataRowList.toArray() as IgxHierarchicalRowComponent[];
            rows.forEach((r) => {
                expect(r.expanded).toBe(false);
            });
            icon = headerExpanderElem.query(By.css('igx-icon')).componentInstance;
            iconTxt = headerExpanderElem.query(By.css('igx-icon')).nativeElement.textContent.toLowerCase();
            expect(iconTxt).toBe('unfold_less');
            expect(icon.getActive).toBe(false);
            expect(hierarchicalGrid.expansionStates.size).toEqual(0);
        });

        it ('checks if attributes are correctly assigned when grid has or does not have data', () => {

            // Checks if igx-grid__tbody-content attribute is null when there is data in the grid
            const container = fixture.nativeElement.querySelectorAll('.igx-grid__tbody-content')[0];
            expect(container.getAttribute('role')).toBe(null);

            //Filter grid so no results are available and grid is empty
            hierarchicalGrid.filter('index','111',IgxStringFilteringOperand.instance().condition('contains'),true);
            hierarchicalGrid.markForCheck();
            fixture.detectChanges();
            expect(container.getAttribute('role')).toMatch('row');

            // clear grid data and check if attribute is now 'row'
            hierarchicalGrid.clearFilter();
            fixture.componentInstance.clearData();
            fixture.detectChanges();

            expect(container.getAttribute('role')).toMatch('row');
        });

        it('should allow applying initial expansions state for certain rows through expansionStates option', () => {
            // set first row as expanded.
            const state = new Map<any, boolean>();
            state.set(fixture.componentInstance.data[0], true);
            hierarchicalGrid.expansionStates = state;
            hierarchicalGrid.cdr.detectChanges();
            const row1 = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            // verify row is expanded
            expect(row1.expanded).toBe(true);
            expect(hierarchicalGrid.gridAPI.getChildGrids(false).length).toBe(1);
            expect(hierarchicalGrid.gridAPI.get_row_by_index(1) instanceof IgxChildGridRowComponent).toBe(true);
        });

        it('should allow defining more than one nested row islands', () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const childGrid = hierarchicalGrid.gridAPI.getChildGrids(false)[0];
            const childRow = childGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(childRow.expander);
            fixture.detectChanges();

            // should have 3 level hierarchy
            const allChildren =  hierarchicalGrid.gridAPI.getChildGrids(true);
            expect(allChildren.length).toBe(2);
            expect(hierarchicalGrid.gridAPI.get_row_by_index(1) instanceof IgxChildGridRowComponent).toBe(true);
            expect(childGrid.gridAPI.get_row_by_index(1) instanceof IgxChildGridRowComponent).toBe(true);
        });

        it('should retain expansion states when scrolling', async () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            expect(row.expanded).toBe(true);
            // scroll to bottom
            hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1);
            await wait(100);
            fixture.detectChanges();
            // scroll to top
            hierarchicalGrid.verticalScrollContainer.scrollTo(0);
            await wait(100);
            fixture.detectChanges();
            expect((hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent).expanded).toBe(true);
        });

        it('should show header collapse button if grid has data and row island is defined.', () => {
            fixture.componentInstance.data = [
                {ID: 0, ProductName: 'Product: A0'}
            ];
            fixture.detectChanges();
            const headerExpanderElem = fixture.debugElement.queryAll(By.css('.igx-grid__hierarchical-expander--header'))[0];
            const icon = headerExpanderElem.query(By.css('igx-icon'));
            expect(icon).toBeDefined();
        });

        it('should render last cell of rows fully visible when columns does not have width specified and without scrollbar', () => {
            const firstRowCell: HTMLElement = (hierarchicalGrid.gridAPI.get_row_by_index(0).cells as QueryList<CellType>).first.nativeElement;
            const cellLeftOffset = firstRowCell.offsetLeft + firstRowCell.parentElement.offsetLeft + firstRowCell.offsetWidth;
            const gridWidth = hierarchicalGrid.nativeElement.offsetWidth;
            expect(cellLeftOffset).not.toBeGreaterThan(gridWidth);

            const hScroll = hierarchicalGrid.headerContainer.getScroll();
            expect((hScroll.firstElementChild as HTMLElement).offsetWidth).not.toBeGreaterThan(hScroll.offsetWidth);
        });

        it('should allow extracting child grids using hgridAPI', () => {
            // set first row as expanded.
            const state = new Map<any, boolean>();
            state.set(fixture.componentInstance.data[0], true);
            hierarchicalGrid.expansionStates = state;
            hierarchicalGrid.cdr.detectChanges();
            const row1 = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            // verify row is expanded
            expect(row1.expanded).toBe(true);
            const childGrid = hierarchicalGrid.gridAPI.getChildGrid([{ rowID: fixture.componentInstance.data[0], rowIslandKey: 'childData' }]);
            expect(childGrid).not.toBeNull();
            const childState = new Map<any, boolean>();
            childState.set(fixture.componentInstance.data[0].childData[0], true);
            childGrid.expansionStates = childState;
            childGrid.cdr.detectChanges();
            const grandChildGrid = hierarchicalGrid.gridAPI.getChildGrid([
                { rowID: fixture.componentInstance.data[0], rowIslandKey: 'childData' },
                { rowID: fixture.componentInstance.data[0].childData[0], rowIslandKey: 'childData' }
            ]);
            expect(grandChildGrid).not.toBeNull();

            const rowIsland1 = hierarchicalGrid.gridAPI.getChildRowIsland('childData');
            const rowIsland2 = hierarchicalGrid.allLayoutList.find(layout => layout.id === 'igx-row-island-childData-childData');
            expect(rowIsland1.key).toBe('childData');
            expect(rowIsland2.key).toBe('childData');
        });

        it('should allow setting expandChildren after bound to data', () => {
            // set first row as expanded.
            const state = new Map<any, boolean>();
            state.set(fixture.componentInstance.data[0], true);
            hierarchicalGrid.expansionStates = state;
            hierarchicalGrid.cdr.detectChanges();
            let row1 = hierarchicalGrid.gridAPI.get_row_by_index(0);
            // verify row is expanded
            expect(row1.expanded).toBe(true);
            hierarchicalGrid.expandChildren = false;
            hierarchicalGrid.cdr.detectChanges();
            row1 = hierarchicalGrid.gridAPI.get_row_by_index(0);
            expect(row1.expanded).toBe(false);
            const expandIcons = fixture.debugElement.queryAll(By.css('#igx-icon-15'));
            expect(expandIcons.length).toBe(0);
            let rows = hierarchicalGrid.dataRowList.toArray() as IgxHierarchicalRowComponent[];
            rows.forEach((r) => {
                expect(r.expanded).toBe(false);
            });
            hierarchicalGrid.expandChildren = true;
            hierarchicalGrid.cdr.detectChanges();
            rows = hierarchicalGrid.dataRowList.toArray() as IgxHierarchicalRowComponent[];
            rows.forEach((r) => {
                expect(r.expanded).toBe(true);
            });

            row1 = hierarchicalGrid.gridAPI.get_row_by_index(0);
            expect(row1.expanded).toBe(true);
        });

        it('should correctly expand children on init if parents have hasChild key', () => {
            hierarchicalGrid.expandChildren = true;
            hierarchicalGrid.hasChildrenKey = 'hasChild';
            fixture.componentInstance.data = [
                { ID: 1, ProductName: 'Product: A1', hasChild: false, childData: fixture.componentInstance.generateDataUneven(1, 1) },
                { ID: 2, ProductName: 'Product: A2', hasChild: true, childData: fixture.componentInstance.generateDataUneven(1, 1) }
            ];
            fixture.detectChanges();
            expect(hierarchicalGrid.gridAPI.get_row_by_index(0)).toBeInstanceOf(IgxHierarchicalRowComponent);
            expect(hierarchicalGrid.gridAPI.get_row_by_index(1)).toBeInstanceOf(IgxHierarchicalRowComponent);
            expect(hierarchicalGrid.gridAPI.get_row_by_index(2)).toBeInstanceOf(IgxChildGridRowComponent);
            const rowElems = fixture.debugElement.queryAll(By.directive(IgxHierarchicalRowComponent));
            expect(rowElems[0].query(By.css('igx-icon')).nativeElement.innerText).toEqual('');
            expect(rowElems[1].query(By.css('igx-icon')).nativeElement.innerText).toEqual('expand_more');
        });

        it('should allow setting expandChildren after bound to data to rowIsland', () => {
            // set first row as expanded.
            const state = new Map<any, boolean>();
            state.set(fixture.componentInstance.data[0], true);
            hierarchicalGrid.expansionStates = state;
            hierarchicalGrid.cdr.detectChanges();
            const row1 = hierarchicalGrid.gridAPI.get_row_by_index(0);
            // verify row is expanded
            expect(row1.expanded).toBe(true);
            // expand children for the rowIsland should be false by default
            expect(fixture.componentInstance.rowIsland.expandChildren).toBeFalsy();
            fixture.componentInstance.rowIsland.expandChildren = true;
            fixture.detectChanges();
            const childGrid = hierarchicalGrid.gridAPI.getChildGrid([{ rowID: fixture.componentInstance.data[0], rowIslandKey: 'childData' }]);
            const childRow = childGrid.getRowByIndex(0);
            expect(childRow.expanded).toBe(true);
            let rows = childGrid.dataRowList.toArray();
            rows.forEach((r) => {
                expect(r.expanded).toBe(true);
            });
            fixture.componentInstance.rowIsland.expandChildren = false;
            fixture.detectChanges();
            rows = childGrid.dataRowList.toArray();
            rows.forEach((r) => {
                expect(r.expanded).toBe(false);
            });

        });

        it('should be able to prevent exiting of edit mode when a row is toggled #10634', async () => {
            hierarchicalGrid.primaryKey = 'ID';
            hierarchicalGrid.rowEditable = true;
            hierarchicalGrid.rowToggle.subscribe((e) => {
                e.cancel = true;
            });
            fixture.detectChanges();
            wait();

            const masterGridFirstRow = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            expect(masterGridFirstRow.expanded).toBe(false);

            const masterGridSecondCell = masterGridFirstRow.cells.find((c: IgxGridCellComponent) => c.columnIndex === 1);
            expect(masterGridSecondCell.editMode).toBe(false);

            masterGridSecondCell.setEditMode(true);
            fixture.detectChanges();
            wait();

            expect(masterGridSecondCell.editMode).toBe(true);

            UIInteractions.simulateClickAndSelectEvent(masterGridFirstRow.expander);
            fixture.detectChanges();
            wait();

            expect(masterGridFirstRow.expanded).toBe(false);
            expect(masterGridSecondCell.editMode).toBe(true);

            hierarchicalGrid.rowToggle.subscribe((e) => {
                e.cancel = false;
            });
            UIInteractions.simulateClickAndSelectEvent(masterGridFirstRow.expander);
            fixture.detectChanges();
            wait();

            expect(masterGridFirstRow.expanded).toBe(true);
            expect(masterGridSecondCell.editMode).toBe(true);

            const childGrid = hierarchicalGrid.gridAPI.getChildGrids(false)[0] as IgxHierarchicalGridComponent;
            expect(childGrid).toBeDefined();

            childGrid.primaryKey = 'ID';
            childGrid.rowEditable = true;
            childGrid.rowToggle.subscribe((e) => {
                e.cancel = true;
            });
            fixture.detectChanges();
            wait();

            childGrid.columns.find(c => c.index === 1).editable = true;
            const childGridSecondRow = childGrid.gridAPI.get_row_by_index(1) as IgxHierarchicalRowComponent;
            expect(childGridSecondRow.expanded).toBe(false);

            const childGridSecondCell = childGridSecondRow.cells.find((c: IgxGridCellComponent) => c.columnIndex === 1);
            expect(childGridSecondCell.editMode).toBe(false);

            childGridSecondCell.setEditMode(true);
            fixture.detectChanges();
            wait();

            expect(childGridSecondCell.editMode).toBe(true);

            UIInteractions.simulateClickAndSelectEvent(childGridSecondRow.expander);
            fixture.detectChanges();
            wait();

            expect(childGrid.gridAPI.crudService.cellInEditMode).toBe(true);
            expect(childGridSecondRow.inEditMode).toBe(true);
        });

        it('should render correctly when display density is changed', () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            expect(hierarchicalGrid.displayDensity).toEqual(DisplayDensity.comfortable);
            expect(hierarchicalGrid.nativeElement.classList).toEqual(jasmine.arrayWithExactContents(['igx-grid']));

            hierarchicalGrid.displayDensity = DisplayDensity.cosy;
            fixture.detectChanges();

            expect(hierarchicalGrid.nativeElement.classList).toEqual(jasmine.arrayWithExactContents(['igx-grid--cosy']));
            expect(childGrid.displayDensity).toBe(DisplayDensity.cosy);

            hierarchicalGrid.displayDensity = DisplayDensity.compact;
            fixture.detectChanges();

            expect(hierarchicalGrid.nativeElement.classList).toEqual(jasmine.arrayWithExactContents(['igx-grid--compact']));
            expect(childGrid.displayDensity).toBe(DisplayDensity.compact);
        });

        it('should update child grid data when root grid data is changed.', () => {
            const newData1 = [
                {
                    ID: 0, ChildLevels: 0,  ProductName: 'Product: A', childData: [ {   ID: 1, ProductName: 'Product: Child A' } ]
                },
                {
                    ID: 1, ChildLevels: 0,  ProductName: 'Product: A1', childData: [ {   ID: 2, ProductName: 'Product: Child A' } ]
                },
                {
                    ID: 2, ChildLevels: 0,  ProductName: 'Product: A2', childData: [ {   ID: 3, ProductName: 'Product: Child A' } ]
                }
            ];
            fixture.componentInstance.data = newData1;
            fixture.detectChanges();
            let row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            let childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            let childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            expect(childGrid.data).toBe(newData1[0].childData);

            const newData2 = [
                {
                    ID: 0, ChildLevels: 0,  ProductName: 'Product: A', childData: [ {   ID: 10, ProductName: 'Product: New Child A' } ]
                },
                {
                    ID: 1, ChildLevels: 0,  ProductName: 'Product: A1', childData: [ {   ID: 20, ProductName: 'Product: New Child A' } ]
                },
                {
                    ID: 2, ChildLevels: 0,  ProductName: 'Product: A2', childData: [ {   ID: 30, ProductName: 'Product: New Child A' } ]
                }
            ];
            fixture.componentInstance.data = newData2;
            fixture.detectChanges();

            row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            expect(childGrid.data).toBe(newData2[0].childData);
        });

        it('when child width is in percents its width should be update if parent width changes while parent row is collapsed. ', async () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;
            expect(childGrid.calcWidth - 370).toBeLessThan(3);
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            fixture.componentInstance.width = '300px';
            fixture.detectChanges();
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            await wait();
            fixture.detectChanges();

            expect(childGrid.calcWidth - 170).toBeLessThan(3);
        });

        it('should exit edit mode on row expand/collapse through the UI', () => {
            hierarchicalGrid.primaryKey = 'ID';
            hierarchicalGrid.rowEditable = true;
            fixture.detectChanges();

            const masterGridFirstRow = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            expect(masterGridFirstRow.expanded).toBe(false);

            const masterGridSecondCell = masterGridFirstRow.cells.find((c: IgxGridCellComponent) => c.columnIndex === 1);
            expect(masterGridSecondCell.editMode).toBe(false);

            masterGridSecondCell.setEditMode(true);
            fixture.detectChanges();

            expect(masterGridSecondCell.editMode).toBe(true);

            UIInteractions.simulateClickAndSelectEvent(masterGridFirstRow.expander);
            fixture.detectChanges();

            expect(masterGridFirstRow.expanded).toBe(true);
            expect(masterGridSecondCell.editMode).toBe(true);

            const childGrid = hierarchicalGrid.gridAPI.getChildGrids(false)[0] as IgxHierarchicalGridComponent;
            expect(childGrid).toBeDefined();

            childGrid.columns.find(c => c.index === 1).editable = true;
            const childGridSecondRow = childGrid.gridAPI.get_row_by_index(1) as IgxHierarchicalRowComponent;
            expect(childGridSecondRow.expanded).toBe(false);

            const childGridSecondCell = childGridSecondRow.cells.find((c: IgxGridCellComponent) => c.columnIndex === 1);
            expect(childGridSecondCell.editMode).toBe(false);

            childGridSecondCell.setEditMode(true);
            fixture.detectChanges();

            expect(childGridSecondCell.editMode).toBe(true);

            UIInteractions.simulateClickAndSelectEvent(masterGridFirstRow.expander);
            fixture.detectChanges();

            expect(childGrid.gridAPI.crudService.cellInEditMode).toBe(true);
            expect(childGridSecondRow.inEditMode).toBe(false);
        });

        it('child grid width should be recalculated if parent no longer shows scrollbar.', fakeAsync(() => {
            hierarchicalGrid.height = '1000px';
            fixture.detectChanges();
            hierarchicalGrid.filter('ProductName', 'A0', IgxStringFilteringOperand.instance().condition('contains'), true);
            fixture.detectChanges();
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;
            expect(childGrid.calcWidth - 370 - childGrid.scrollSize).toBeLessThanOrEqual(5);

            hierarchicalGrid.clearFilter();
            // Required to recalculate and reflect child grid size
            tick();
            fixture.detectChanges();

            expect(childGrid.calcWidth - 370).toBeLessThan(3);
        }));

        it('should not expand children when hasChildrenKey is false for the row', () => {
            hierarchicalGrid.hasChildrenKey = 'hasChild';
            fixture.componentInstance.data = [
                {ID: 1, ProductName: 'Product: A1', hasChild: false, childData: fixture.componentInstance.generateDataUneven(1, 1)},
                {ID: 2, ProductName: 'Product: A2', hasChild: true, childData: fixture.componentInstance.generateDataUneven(1, 1)}
            ];
            fixture.detectChanges();
            const row1 = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            const rowElems = fixture.debugElement.queryAll(By.directive(IgxHierarchicalRowComponent));
            expect(rowElems[0].query(By.css('igx-icon')).nativeElement.innerText).toEqual('');
            const row2 = hierarchicalGrid.gridAPI.get_row_by_index(1) as IgxHierarchicalRowComponent;
            expect(rowElems[1].query(By.css('igx-icon')).nativeElement.innerText).toEqual('chevron_right');
            hierarchicalGrid.expandRow(row1.data);
            hierarchicalGrid.expandRow(row2.data);
            expect(row1.expanded).toBe(false);
            expect(row2.expanded).toBe(true);
            hierarchicalGrid.expandAll();
            expect(row1.expanded).toBe(false);
        });

        it('should not expand children when hasChildrenKey is false for the row and there is primaryKey', () => {
            hierarchicalGrid.hasChildrenKey = 'hasChild';
            hierarchicalGrid.primaryKey = 'ID';
            fixture.componentInstance.data = [
                {ID: 1, ProductName: 'Product: A1', hasChild: false, childData: fixture.componentInstance.generateDataUneven(1, 1)},
                {ID: 2, ProductName: 'Product: A2', hasChild: true, childData: fixture.componentInstance.generateDataUneven(1, 1)}
            ];
            fixture.detectChanges();
            const row1 = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            const rowElems = fixture.debugElement.queryAll(By.directive(IgxHierarchicalRowComponent));
            expect(rowElems[0].query(By.css('igx-icon')).nativeElement.innerText).toEqual('');
            const row2 = hierarchicalGrid.gridAPI.get_row_by_index(1) as IgxHierarchicalRowComponent;
            expect(rowElems[1].query(By.css('igx-icon')).nativeElement.innerText).toEqual('chevron_right');
            hierarchicalGrid.expandRow(1);
            hierarchicalGrid.expandRow(2);
            expect(row1.expanded).toBe(false);
            expect(row2.expanded).toBe(true);
        });

        it('should update aria-activeDescendants when navigating around', () => {
            hierarchicalGrid.cellSelection = 'single';
            expect(hierarchicalGrid.tbody.nativeElement.attributes['aria-activedescendant'].value).toEqual(hierarchicalGrid.id);

            let cellElem = (hierarchicalGrid.gridAPI.get_row_by_index(0).cells as QueryList<CellType>).toArray()[1];
            UIInteractions.simulatePointerOverElementEvent('pointerdown', cellElem.nativeElement);
            fixture.detectChanges();
            expect(hierarchicalGrid.tbody.nativeElement.attributes['aria-activedescendant'].value).toEqual(`${hierarchicalGrid.id}_0_1`);

            const row1 = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row1.expander);
            fixture.detectChanges();

            const childGrid = hierarchicalGrid.getChildGrids()[0];
            expect(childGrid.tbody.nativeElement.attributes['aria-activedescendant'].value).toEqual(childGrid.id);

            cellElem = (childGrid.gridAPI.get_row_by_index(0).cells as QueryList<CellType>).toArray()[1];
            UIInteractions.simulatePointerOverElementEvent('pointerdown', cellElem.nativeElement);
            fixture.detectChanges();

            expect(hierarchicalGrid.tbody.nativeElement.attributes['aria-activedescendant'].value).toEqual(hierarchicalGrid.id);
            expect(childGrid.tbody.nativeElement.attributes['aria-activedescendant'].value).toEqual(`${childGrid.id}_0_1`);
        });
    });

    describe('IgxHierarchicalGrid Row Islands #hGrid', () => {
        let fixture;
        let hierarchicalGrid: IgxHierarchicalGridComponent;

        beforeEach(() => {
            fixture = TestBed.createComponent(IgxHierarchicalGridMultiLayoutComponent);
            fixture.detectChanges();
            hierarchicalGrid = fixture.componentInstance.hgrid;
        });

        it('should allow defining row islands on the same level', () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            const childGrids = hierarchicalGrid.gridAPI.getChildGrids(false);
            const childRows = fixture.debugElement.queryAll(By.directive(IgxChildGridRowComponent));
            expect(childGrids.length).toBe(2);
            expect(childRows.length).toBe(2);
            const ri1 = fixture.componentInstance.rowIsland1;
            const ri2 = fixture.componentInstance.rowIsland2;
            expect(childRows[0].componentInstance.layout).toBe(ri1);
            expect(childRows[1].componentInstance.layout).toBe(ri2);
        });

        it('should display correct data for sibling row islands', () => {
            const uniqueData = [
                {
                    ID: 1,
                    ProductName : 'Parent Name',
                    childData: [
                        {
                            ID: 11,
                            ProductName : 'Child1 Name'
                        }
                    ],
                    childData2: [
                        {
                            ID: 12,
                            Col1: 'Child2 Col1',
                            Col2: 'Child2 Col2',
                            Col3: 'Child2 Col3'
                        }
                    ]
                }
            ];

            fixture.componentInstance.data = uniqueData;
            fixture.detectChanges();

            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            const childGrids = hierarchicalGrid.gridAPI.getChildGrids(false);

            // check if data for each is correct
            const child1 = childGrids[0] as IgxHierarchicalGridComponent;
            const child2 = childGrids[1] as IgxHierarchicalGridComponent;

            expect(child1.data).toBe(fixture.componentInstance.data[0].childData);
            expect(child2.data).toBe(fixture.componentInstance.data[0].childData2);

            expect(child1.getCellByColumn(0, 'ID').value).toBe(11);
            expect(child1.getColumnByVisibleIndex(0).field).toBe('ID');
            expect(child1.getCellByColumn(0, 'ProductName').value).toBe('Child1 Name');

            expect(child2.getCellByColumn(0, 'Col1').value).toBe('Child2 Col1');
            expect(child2.getCellByColumn(0, 'Col2').value).toBe('Child2 Col2');
            expect(child2.getCellByColumn(0, 'Col3').value).toBe('Child2 Col3');

        });

        it('should apply the set options on the row island to all of its related child grids.', () => {
            fixture.componentInstance.height = '200px';
            fixture.detectChanges();
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            const childGrids = hierarchicalGrid.gridAPI.getChildGrids(false) as IgxHierarchicalGridComponent [];
            expect(childGrids[0].height).toBe('200px');
            expect(childGrids[1].height).toBe('200px');
        });

        it('Should apply runtime option changes to all related child grids (both existing and not yet initialized).', () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const ri1 = fixture.componentInstance.rowIsland1;
            ri1.rowSelection = GridSelectionMode.multiple;
            fixture.detectChanges();

            // check rendered grid
            let childGrids = hierarchicalGrid.gridAPI.getChildGrids(false);
            expect(childGrids[0].rowSelection).toBe( GridSelectionMode.multiple);
            expect(childGrids[1].rowSelection).toBe(GridSelectionMode.none);

            // expand new row and check newly generated grid
            const row2 = hierarchicalGrid.gridAPI.get_row_by_index(3) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row2.expander);
            fixture.detectChanges();

            childGrids = hierarchicalGrid.gridAPI.getChildGrids(false);
            expect(childGrids[0].rowSelection).toBe( GridSelectionMode.multiple);
            expect(childGrids[1].rowSelection).toBe( GridSelectionMode.multiple);
            expect(childGrids[2].rowSelection).toBe(GridSelectionMode.none);
            expect(childGrids[3].rowSelection).toBe(GridSelectionMode.none);
        });

        it('should apply column settings applied to the row island to all related child grids.', () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const ri1 = fixture.componentInstance.rowIsland1 as IgxRowIslandComponent;
            const ri2 = fixture.componentInstance.rowIsland2 as IgxRowIslandComponent;

            const childGrids = hierarchicalGrid.gridAPI.getChildGrids(false);

            const child1Cols = childGrids[0].columns;
            const riCols = ri1.columns;
            expect(child1Cols.length).toEqual(riCols.length);
            for (const column of riCols) {
                const col = child1Cols.find((c) => c.field === column.field);
                expect(col).not.toBeNull();
            }
            const child2Cols = childGrids[1].columns;
            const ri2Cols = ri2.columns;
            expect(child2Cols.length).toEqual(ri2Cols.length);
            for (let j = 0; j < riCols.length; j++) {
                const col = child2Cols.find((c) => c.field === ri2Cols[j].field);
                expect(col).not.toBeNull();
            }
        });

        it('should allow setting different height/width in px/percent for row islands and grids should be rendered correctly.', () => {
            const ri1 = fixture.componentInstance.rowIsland1;

            // test px
            ri1.height = '200px';
            ri1.width = '200px';

            fixture.detectChanges();

            let row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            let childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            let childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            // check sizes are applied
            expect(childGrid.width).toBe(ri1.width);
            expect(childGrid.height).toBe(ri1.height);
            expect(childGrid.nativeElement.style.height).toBe(ri1.height);
            expect(childGrid.nativeElement.style.width).toBe(ri1.width);
            // check virtualization state
            expect(childGrid.verticalScrollContainer.state.chunkSize).toBe(4);
            expect(childGrid.verticalScrollContainer.getScroll().scrollHeight).toBe(357);

            let hVirt = childGrid.gridAPI.get_row_by_index(0).virtDirRow;
            expect(hVirt.state.chunkSize).toBe(2);
            expect(hVirt.getScroll().scrollWidth).toBe(272);
            // collapse row
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            // test %
            ri1.height = '50%';
            ri1.width = '50%';

            fixture.detectChanges();
            row = hierarchicalGrid.gridAPI.get_row_by_index(1) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();


            childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            // check sizes are applied
            expect(childGrid.width).toBe(ri1.width);
            expect(childGrid.height).toBe(ri1.height);
            expect(childGrid.nativeElement.style.height).toBe(ri1.height);
            expect(childGrid.nativeElement.style.width).toBe(ri1.width);
            // check virtualization state
            expect(childGrid.verticalScrollContainer.state.chunkSize).toBe(11);
            expect(childGrid.verticalScrollContainer.getScroll().scrollHeight).toBe(714);
            hVirt = childGrid.gridAPI.get_row_by_index(0).virtDirRow;
            expect(hVirt.getScroll().scrollWidth).toBe(272);
        });

        it('should destroy cached instances of child grids when root grid is destroyed', async () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const children = hierarchicalGrid.gridAPI.getChildGrids(true);
            expect(children.length).toBe(2);
            const child1 = children[0] as IgxHierarchicalGridComponent;
            const child2 = children[1] as IgxHierarchicalGridComponent;
            expect(child1._destroyed).toBeFalsy();
            expect(child2._destroyed).toBeFalsy();
            hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1);
            await wait();
            fixture.detectChanges();

            // check that we have child is not destroyed
            expect(child1._destroyed).toBeFalsy();
            expect(child2._destroyed).toBeFalsy();

            // destroy hgrid
            fixture.destroy();

            expect(child1._destroyed).toBeTruthy();
            expect(child2._destroyed).toBeTruthy();
        });

        it('should emit child grid events with the related child grid instance as an event arg.', () => {
            hierarchicalGrid.cellSelection = 'single';
            fixture.detectChanges();
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;
            const cellElem = childGrid.gridAPI.get_row_by_index(0).cells.toArray()[0];
            const cell = childGrid.getRowByIndex(0).cells[0] as CellType;
            const ri1 = fixture.componentInstance.rowIsland1;

            expect(cell.active).toBeFalse();
            expect(cell.selected).toBeFalse();

            spyOn(ri1.cellClick, 'emit').and.callThrough();

            const event = new Event('click');
            cellElem.nativeElement.dispatchEvent(event);
            const args: IGridCellEventArgs = {
                cell,
                event,
                owner: childGrid
            };

            fixture.detectChanges();
            expect(ri1.cellClick.emit).toHaveBeenCalledTimes(1);
            expect(ri1.cellClick.emit).toHaveBeenCalledWith(args);

            cell.selected = true;
            fixture.detectChanges();

            expect(cell.selected).toBeTrue();
            expect(childGrid.selectedCells[0].row.index).toEqual(cell.row.index);
            expect(childGrid.selectedCells[0].column.field).toEqual(cell.column.field);
        });

        it('should filter correctly on row island', () => {
            const uniqueData = [
                {
                    ID: 1,
                    ProductName : 'Parent Name',
                    childData: [
                        {
                            ID: 11,
                            ProductName : 'Child11 ProductName'
                        },
                        {
                            ID: 12,
                            ProductName : 'Child12 ProductName'
                        }
                    ],
                    childData2: [
                        {
                            ID: 21,
                            Col1: 'Child21 Col1',
                            Col2: 'Child21 Col2',
                            Col3: 'Child21 Col3'
                        },
                        {
                            ID: 22,
                            Col1: 'Child22 Col1',
                            Col2: 'Child22 Col2',
                            Col3: 'Child22 Col3'
                        }
                    ]
                }
            ];
            fixture.componentInstance.data = uniqueData;
            fixture.detectChanges();

            const rowIsland1 = fixture.componentInstance.rowIsland1 as IgxRowIslandComponent;
            rowIsland1.filter('ProductName', 'Child12', IgxStringFilteringOperand.instance().condition('contains'), true);

            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid1 = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;
            expect(childGrid1.data.length).toEqual(2);
            expect(childGrid1.filteredData.length).toEqual(1);
            expect(childGrid1.rowList.length).toEqual(1);
            expect(childGrid1.gridAPI.get_cell_by_index(0, 'ProductName').nativeElement.innerText).toEqual('Child12 ProductName');
        });

        it('should allow binding to complex object.', () => {
            const rowIsland1 = fixture.componentInstance.rowIsland1 as IgxRowIslandComponent;
            const rowIsland2 = fixture.componentInstance.rowIsland2 as IgxRowIslandComponent;
            rowIsland1.key = 'childData.Records';
            rowIsland2.key = 'childData2.Records';

            hierarchicalGrid.childLayoutKeys = ['childData.Records', 'childData2.Records'];
            const complexObjData = [
                {
                    ID: 1,
                    ProductName : 'Parent Name',
                    childData: {
                        Records: [
                            {
                                ID: 11,
                                ProductName : 'Child11 ProductName'
                            },
                            {
                                ID: 12,
                                ProductName : 'Child12 ProductName'
                            }
                        ]
                    },
                    childData2: {
                        Records: [
                        {
                            ID: 21,
                            Col1: 'Child21 Col1',
                            Col2: 'Child21 Col2',
                            Col3: 'Child21 Col3'
                        },
                        {
                            ID: 22,
                            Col1: 'Child22 Col1',
                            Col2: 'Child22 Col2',
                            Col3: 'Child22 Col3'
                        }
                        ]
                    }
                }
            ];
            fixture.componentInstance.data = complexObjData;
            fixture.detectChanges();

            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid1 = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;
            const childGrid2 = childGrids[1].query(By.css('igx-hierarchical-grid')).componentInstance;
            expect(childGrid1.data.length).toEqual(2);
            expect(childGrid2.data.length).toEqual(2);

            expect(childGrid1.data[0].ID).toBe(11);
            expect(childGrid2.data[0].ID).toBe(21);
        });
    });

    describe('IgxHierarchicalGrid Children Sizing #hGrid', () => {
        let fixture: ComponentFixture<IgxHierarchicalGridSizingComponent>;
        let hierarchicalGrid: IgxHierarchicalGridComponent;
        const TBODY_CLASS = '.igx-grid__tbody-content';

        beforeEach(() => {
            fixture = TestBed.createComponent(IgxHierarchicalGridSizingComponent);
            fixture.detectChanges();
            hierarchicalGrid = fixture.componentInstance.hgrid;
        });

        it('should create a child grid with null height when its data is unset then set to a number under 10', () => {
            fixture.detectChanges();
            // expansion
            const row = hierarchicalGrid.rowList.first as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            let defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            expect(defaultHeight).toBeFalsy();
            expect(childGrid.calcHeight).toBeNull();
            childGrid.data = fixture.componentInstance.data;
            fixture.detectChanges();

            defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            expect(defaultHeight).toBeFalsy();
            expect(childGrid.calcHeight).toBeNull();
            expect(childGrid.data.length).toEqual(1);
            expect(childGrid.rowList.length).toEqual(1);
        });

        it('should create a child grid with auto-size when its data is unset then set to a number above 10', () => {
            fixture.detectChanges();
            // expansion
            const row = hierarchicalGrid.rowList.first as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            let defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            expect(defaultHeight).toBeFalsy();
            expect(childGrid.calcHeight).toBeNull();
            childGrid.data = fixture.componentInstance.fullData;
            fixture.detectChanges();

            defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            expect(defaultHeight).toBe('510px');
            expect(childGrid.calcHeight).toBe(510);
            expect(childGrid.data.length).toEqual(100000);
            expect(childGrid.rowList.length).toEqual(11);
        });

        it('should create a child grid with auto-size when its data is unset then set to a number above 10 and height is 50%', () => {
            fixture.componentInstance.childHeight = '50%';
            fixture.detectChanges();
            // expansion
            const row = hierarchicalGrid.rowList.first as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            let defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            expect(defaultHeight).toBeFalsy();
            expect(childGrid.calcHeight).toBeNull();
            childGrid.data = fixture.componentInstance.fullData;
            fixture.detectChanges();

            defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            expect(defaultHeight).toBe('510px');
            expect(childGrid.calcHeight).toBe(510);
            expect(childGrid.data.length).toEqual(100000);
            expect(childGrid.rowList.length).toEqual(11);
        });

        it('should create a child grid fixed size when height is set to px', () => {
            fixture.componentInstance.childHeight = '600px';
            fixture.detectChanges();
            // expansion
            const row = hierarchicalGrid.rowList.first as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            let defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            let defaultHeightNum = parseInt(defaultHeight, 10);
            expect(defaultHeightNum).toBeGreaterThan(500);
            expect(defaultHeightNum).toBeLessThan(600);
            expect(childGrid.calcHeight).toBeGreaterThan(500);
            expect(childGrid.calcHeight).toBeLessThan(600);
            expect(childGrid.rowList.length).toEqual(0);
            childGrid.data = fixture.componentInstance.fullData;
            fixture.detectChanges();

            defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            defaultHeightNum = parseInt(defaultHeight, 10);
            expect(defaultHeightNum).toBeGreaterThan(500);
            expect(defaultHeightNum).toBeLessThan(600);
            expect(childGrid.calcHeight).toBeGreaterThan(500);
            expect(childGrid.calcHeight).toBeLessThan(600);
            expect(childGrid.data.length).toEqual(100000);
            expect(childGrid.rowList.length).toEqual(12);
        });

        it('should create a child grid null height regardless of data when height is set to null', () => {
            fixture.componentInstance.childHeight = null;
            fixture.detectChanges();
            // expansion
            const row = hierarchicalGrid.rowList.first as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();
            const childGrids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            let defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            expect(defaultHeight).toBeFalsy();
            expect(childGrid.calcHeight).toBeNull();
            childGrid.data = fixture.componentInstance.semiData;
            fixture.detectChanges();

            defaultHeight = childGrids[0].query(By.css(TBODY_CLASS)).styles.height;
            expect(defaultHeight).toBeFalsy();
            expect(childGrid.calcHeight).toBeNull();
            expect(childGrid.data.length).toEqual(15);
            expect(childGrid.rowList.length).toEqual(15);
        });
    });

    describe('IgxHierarchicalGrid Remote Scenarios #hGrid', () => {
        let fixture: ComponentFixture<IgxHGridRemoteOnDemandComponent>;
        const TBODY_CLASS = '.igx-grid__tbody-content';
        const THEAD_CLASS = '.igx-grid-thead';

        beforeEach(() => {
            fixture = TestBed.createComponent(IgxHGridRemoteOnDemandComponent);
            fixture.detectChanges();
        });

        // To investigate why it times out
        it('should render loading indicator when loading and autoGenerate are enabled', fakeAsync(() => {
            fixture.detectChanges();

            const grid = fixture.componentInstance.instance;
            const gridBody = fixture.debugElement.query(By.css(TBODY_CLASS));
            const gridHead = fixture.debugElement.query(By.css(THEAD_CLASS));
            let loadingIndicator = gridBody.query(By.css('.igx-grid__loading'));
            let colHeaders = gridHead.queryAll(By.css('igx-grid-header'));

            expect(loadingIndicator).not.toBeNull();
            expect(colHeaders.length).toBe(0);
            expect(gridBody.nativeElement.textContent).not.toEqual(grid.emptyFilteredGridMessage);

            // Check for loaded rows in grid's container
            grid.shouldGenerate = true;
            fixture.componentInstance.databind();
            fixture.detectChanges();

            loadingIndicator = gridBody.query(By.css('.igx-grid__loading'));
            colHeaders = gridHead.queryAll(By.css('igx-grid-header'));
            expect(colHeaders.length).toBeGreaterThan(0);
            expect(loadingIndicator).toBeNull();

            const row = grid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            // Tick is required for height to be recalculated and rerendered
            tick();
            fixture.detectChanges();

            const rowIslandDOM = fixture.debugElement.query(By.css('.igx-grid__hierarchical-indent .igx-grid'));
            const rowIslandBody = rowIslandDOM.query(By.css('.igx-grid__tbody-content'));
            expect(parseInt(window.getComputedStyle(rowIslandBody.nativeElement).height, 10)).toBe(255);
        }));

        it('should render disabled collapse all icon for child grid even when it has no data but with child row island', () => {
            const hierarchicalGrid = fixture.componentInstance.instance;

            fixture.componentInstance.databind();
            fixture.detectChanges();

            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const gridHead = fixture.debugElement.queryAll(By.css(THEAD_CLASS))[1];
            const headerExpanderElem = gridHead.queryAll(By.css('.igx-grid__hierarchical-expander--header'))[0];
            const icon = headerExpanderElem.query(By.css('igx-icon')).componentInstance;
            const iconTxt = headerExpanderElem.query(By.css('igx-icon')).nativeElement.textContent.toLowerCase();
            expect(iconTxt).toBe('unfold_less');
            expect(icon.getActive).toBe(false);
        });
    });

    describe('IgxHierarchicalGrid Template Changing Scenarios #hGrid', () => {
        const THEAD_CLASS = '.igx-grid-thead';
        let fixture: ComponentFixture<IgxHierarchicalGridColumnsUpdateComponent>;
        let hierarchicalGrid: IgxHierarchicalGridComponent;

        beforeEach(() => {
            fixture = TestBed.createComponent(IgxHierarchicalGridColumnsUpdateComponent);
            fixture.detectChanges();
            hierarchicalGrid = fixture.componentInstance.hgrid;
        });

        it('should render correct columns when setting columns for child in AfterViewInit using ngFor', () => {
            const gridHead = fixture.debugElement.query(By.css(THEAD_CLASS));
            const colHeaders = gridHead.queryAll(By.css('igx-grid-header'));
            expect(colHeaders.length).toEqual(2);
            expect(colHeaders[0].nativeElement.innerText).toEqual('ID');
            expect(colHeaders[1].nativeElement.innerText).toEqual('ProductName');

            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const child1Grids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const child1Grid = child1Grids[0].query(By.css('igx-hierarchical-grid'));
            const child1Headers = child1Grid.queryAll(By.css('igx-grid-header'));

            expect(child1Headers.length).toEqual(5);
            expect(child1Headers[0].nativeElement.innerText).toEqual('ID');
            expect(child1Headers[1].nativeElement.innerText).toEqual('ProductName');
            expect(child1Headers[2].nativeElement.innerText).toEqual('Col1');
            expect(child1Headers[3].nativeElement.innerText).toEqual('Col2');
            expect(child1Headers[4].nativeElement.innerText).toEqual('Col3');

            const row1 = child1Grid.componentInstance.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row1.expander);
            fixture.detectChanges();

            const child2Grids =  child1Grid.queryAll(By.css('igx-child-grid-row'));
            const child2Grid = child2Grids[0].query(By.css('igx-hierarchical-grid'));
            const child2Headers = child2Grid.queryAll(By.css('igx-grid-header'));

            expect(child2Headers.length).toEqual(3);
            expect(child2Headers[0].nativeElement.innerText).toEqual('ID');
            expect(child2Headers[1].nativeElement.innerText).toEqual('ProductName');
            expect(child2Headers[2].nativeElement.innerText).toEqual('Col1');
        });

        it('should render correct columns when setting columns for parent and child post init using ngFor', fakeAsync(() => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const child1Grids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const child1Grid = child1Grids[0].query(By.css('igx-hierarchical-grid')).componentInstance;

            fixture.componentInstance.parentCols = ['Col1', 'Col2'];
            fixture.componentInstance.islandCols1 = ['ID', 'ProductName', 'Col1'];
            fixture.detectChanges();
            tick();

            // check parent cols
            expect(hierarchicalGrid.columns.length).toBe(4);
            expect(hierarchicalGrid.columns[0].field).toBe('ID');
            expect(hierarchicalGrid.columns[1].field).toBe('ProductName');
            expect(hierarchicalGrid.columns[2].field).toBe('Col1');
            expect(hierarchicalGrid.columns[3].field).toBe('Col2');
            // check child cols
            expect(child1Grid.columns.length).toBe(3);
            expect(child1Grid.columns[0].field).toBe('ID');
            expect(child1Grid.columns[1].field).toBe('ProductName');
            expect(child1Grid.columns[2].field).toBe('Col1');
        }));

        it('should update columns for expanded child when adding column to row island', fakeAsync(() => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const child1Grids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const child1Grid = child1Grids[0].query(By.css('igx-hierarchical-grid'));

            const row1 = child1Grid.componentInstance.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row1.expander);
            fixture.detectChanges();

            const child2Grids =  child1Grid.queryAll(By.css('igx-child-grid-row'));
            const child2Grid = child2Grids[0].query(By.css('igx-hierarchical-grid'));
            let child2Headers = child2Grid.queryAll(By.css('igx-grid-header'));

            expect(child2Headers.length).toEqual(3);
            expect(child2Headers[0].nativeElement.innerText).toEqual('ID');
            expect(child2Headers[1].nativeElement.innerText).toEqual('ProductName');
            expect(child2Headers[2].nativeElement.innerText).toEqual('Col1');

            fixture.componentInstance.islandCols2.push('Col2');
            fixture.detectChanges();
            tick();
            fixture.detectChanges();

            child2Headers = child2Grid.queryAll(By.css('igx-grid-header'));
            expect(child2Headers.length).toEqual(4);
            expect(child2Headers[0].nativeElement.innerText).toEqual('ID');
            expect(child2Headers[1].nativeElement.innerText).toEqual('ProductName');
            expect(child2Headers[2].nativeElement.innerText).toEqual('Col1');
            expect(child2Headers[3].nativeElement.innerText).toEqual('Col2');

            const child1Headers = child1Grid.query(By.css(THEAD_CLASS)).queryAll(By.css('igx-grid-header'));
            expect(child1Headers.length).toEqual(5);
            expect(child1Headers[0].nativeElement.innerText).toEqual('ID');
            expect(child1Headers[1].nativeElement.innerText).toEqual('ProductName');
            expect(child1Headers[2].nativeElement.innerText).toEqual('Col1');
            expect(child1Headers[3].nativeElement.innerText).toEqual('Col2');
            expect(child1Headers[4].nativeElement.innerText).toEqual('Col3');

            const gridHead = fixture.debugElement.query(By.css(THEAD_CLASS));
            const colHeaders = gridHead.queryAll(By.css('igx-grid-header'));
            expect(colHeaders.length).toEqual(2);
            expect(colHeaders[0].nativeElement.innerText).toEqual('ID');
            expect(colHeaders[1].nativeElement.innerText).toEqual('ProductName');
        }));

        it('should update columns for rendered child that is collapsed when adding column to row island', fakeAsync(() => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const child1Grids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const child1Grid = child1Grids[0].query(By.css('igx-hierarchical-grid'));

            const row1 = child1Grid.componentInstance.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row1.expander);
            fixture.detectChanges();

            const child2Grids =  child1Grid.queryAll(By.css('igx-child-grid-row'));
            const child2Grid = child2Grids[0].query(By.css('igx-hierarchical-grid'));
            let child2Headers = child2Grid.queryAll(By.css('igx-grid-header'));

            expect(child2Headers.length).toEqual(3);
            expect(child2Headers[0].nativeElement.innerText).toEqual('ID');
            expect(child2Headers[1].nativeElement.innerText).toEqual('ProductName');
            expect(child2Headers[2].nativeElement.innerText).toEqual('Col1');

            UIInteractions.simulateClickAndSelectEvent(row1.expander);
            fixture.detectChanges();

            fixture.componentInstance.islandCols2.push('Col2');
            fixture.detectChanges();
            tick();
            fixture.detectChanges();

            UIInteractions.simulateClickAndSelectEvent(row1.expander);
            fixture.detectChanges();

            child2Headers = child2Grid.queryAll(By.css('igx-grid-header'));
            expect(child2Headers.length).toEqual(4);
            expect(child2Headers[0].nativeElement.innerText).toEqual('ID');
            expect(child2Headers[1].nativeElement.innerText).toEqual('ProductName');
            expect(child2Headers[2].nativeElement.innerText).toEqual('Col1');
            expect(child2Headers[3].nativeElement.innerText).toEqual('Col2');
        }));

        it('test getRowByIndex API methods', () => {
            const nonExistingRow = hierarchicalGrid.getRowByKey('nonexisting');
            expect(nonExistingRow).toBeUndefined();

            const nonExistingRow2 = hierarchicalGrid.getRowByIndex(-1);
            expect(nonExistingRow2).toBeUndefined();

            const cell00 = hierarchicalGrid.getCellByColumn(0, 'ID');
            expect(cell00.row.index).toBe(0);
            expect(cell00.column.visibleIndex).toBe(0);

            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const child1Grids =  fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const child1Grid = child1Grids[0].query(By.css('igx-hierarchical-grid'));

            const firstRow = child1Grid.componentInstance.getRowByIndex(0);
            firstRow.expanded = true;

            expect(firstRow.hasChildren).toBe(true);
            expect(firstRow.children).toBeUndefined();
            expect(firstRow.viewIndex).toEqual(0);
            expect(firstRow.key).toBeDefined();
            expect(firstRow.data.ID).toEqual('00');
            expect(firstRow.pinned).toBe(false);
            expect(firstRow.selected).toBe(false);
            expect(firstRow.expanded).toBe(true);
            expect(firstRow.deleted).toBe(false);
            expect(firstRow.inEditMode).toBe(false);

            // Toggle expanded state
            firstRow.expanded = false;
            expect(firstRow.expanded).toBe(false);
        });
    });

    describe('IgxHierarchicalGrid hide child columns', () => {
        let fixture: ComponentFixture<IgxHierarchicalGridHidingPinningColumnsComponent>;
        let hierarchicalGrid: IgxHierarchicalGridComponent;

        beforeEach(() => {
            fixture = TestBed.createComponent(IgxHierarchicalGridHidingPinningColumnsComponent);
            fixture.detectChanges();
            hierarchicalGrid = fixture.componentInstance.hgrid;
        });

        it('should fire hiddenChange and pinnedChange events for child grid.', () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            const child1Grids = fixture.debugElement.queryAll(By.css('igx-child-grid-row'));
            const child1Grid = child1Grids[0].query(By.css('igx-hierarchical-grid'));

            // Pinning

            const childHeader1 = GridFunctions.getColumnHeaders(fixture)[2];

            const firstHeaderIcon = childHeader1.query(By.css('.igx-icon'));

            spyOn(child1Grid.componentInstance.columns[0].pinnedChange, 'emit').and.callThrough();

            expect(GridFunctions.isHeaderPinned(childHeader1.parent)).toBeFalsy();
            expect(child1Grid.componentInstance.columns[0].pinned).toBeFalsy();
            expect(firstHeaderIcon).toBeDefined();

            UIInteractions.simulateClickAndSelectEvent(firstHeaderIcon);
            fixture.detectChanges();

            expect(child1Grid.componentInstance.columns[0].pinnedChange.emit).toHaveBeenCalledTimes(1);
            expect(child1Grid.componentInstance.columns[0].pinned).toBeTruthy();

            // Hiding

            const childHeader2 = GridFunctions.getColumnHeaders(fixture)[4];

            const secondHeaderIcon = childHeader2.query(By.css('.igx-icon'));

            const lastIndex = child1Grid.componentInstance.columns.length - 1;
            spyOn(child1Grid.componentInstance.columns[lastIndex].hiddenChange, 'emit').and.callThrough();

            expect(child1Grid.componentInstance.columns[lastIndex].hidden).toBeFalsy();
            expect(secondHeaderIcon).toBeDefined();

            UIInteractions.simulateClickAndSelectEvent(secondHeaderIcon);
            fixture.detectChanges();

            expect(child1Grid.componentInstance.columns[lastIndex].hiddenChange.emit).toHaveBeenCalledTimes(1);
            expect(child1Grid.componentInstance.columns[lastIndex].hidden).toBeTruthy();
        });
    });

    describe('IgxHierarchicalGrid Runtime Row Island change Scenarios #hGrid', () => {
        let fixture: ComponentFixture<IgxHierarchicalGridToggleRIComponent>;
        let hierarchicalGrid: IgxHierarchicalGridComponent;

        beforeEach(() => {
            fixture = TestBed.createComponent(IgxHierarchicalGridToggleRIComponent);
            fixture.detectChanges();
            hierarchicalGrid = fixture.componentInstance.hgrid;
        });

        it('should allow changing row islands runtime in root grid.', () => {
            let row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            let hGrids = fixture.debugElement.queryAll(By.css('igx-hierarchical-grid'));
            let childGrids = hierarchicalGrid.gridAPI.getChildGrids();
            expect(childGrids.length).toBe(1);
            expect(hGrids.length).toBe(2);

            fixture.componentInstance.toggleRI = false;
            fixture.detectChanges();

            hGrids = fixture.debugElement.queryAll(By.css('igx-hierarchical-grid'));
            childGrids = hierarchicalGrid.gridAPI.getChildGrids();
            expect(childGrids.length).toBe(0);
            expect(hGrids.length).toBe(1);
            expect(row.expander).toBe(undefined);

            fixture.componentInstance.toggleRI = true;
            fixture.detectChanges();

            hGrids = fixture.debugElement.queryAll(By.css('igx-hierarchical-grid'));
            childGrids = hierarchicalGrid.gridAPI.getChildGrids();
            row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            expect(childGrids.length).toBe(1);
            expect(hGrids.length).toBe(2);
            expect(row.expander).not.toBe(undefined);
        });

        it('should allow changing row islands runtime in child grid.', () => {
            const row = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(row.expander);
            fixture.detectChanges();

            let childGrid = hierarchicalGrid.gridAPI.getChildGrids()[0];
            const childRow = childGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(childRow.expander);
            fixture.detectChanges();

            let hGrids = fixture.debugElement.queryAll(By.css('igx-hierarchical-grid'));
            expect(hGrids.length).toBe(3);
            expect(childGrid.gridAPI.getChildGrids().length).toBe(1);

            fixture.componentInstance.toggleChildRI = false;
            fixture.detectChanges();

            hGrids = fixture.debugElement.queryAll(By.css('igx-hierarchical-grid'));
            childGrid = hierarchicalGrid.gridAPI.getChildGrids()[0];
            expect(hGrids.length).toBe(2);
            expect(childGrid.gridAPI.getChildGrids().length).toBe(0);

            fixture.componentInstance.toggleChildRI = true;
            fixture.detectChanges();

            hGrids = fixture.debugElement.queryAll(By.css('igx-hierarchical-grid'));
            childGrid = hierarchicalGrid.gridAPI.getChildGrids()[0];
            expect(hGrids.length).toBe(3);
            expect(childGrid.gridAPI.getChildGrids().length).toBe(1);

        });

        it(`Should apply template to both parent and child grids`, () => {
            const customFixture = TestBed.createComponent(IgxHierarchicalGridCustomRowEditOverlayComponent);
            customFixture.detectChanges();
            hierarchicalGrid = customFixture.componentInstance.hgrid;
            hierarchicalGrid.primaryKey = 'ID';
            hierarchicalGrid.rowEditable = true;

            let cellElem = hierarchicalGrid.gridAPI.get_cell_by_index(0, 'ProductName');
            let row = hierarchicalGrid.gridAPI.get_row_by_index(0);

            UIInteractions.simulateDoubleClickAndSelectEvent(cellElem);
            customFixture.detectChanges();
            expect(row.inEditMode).toBe(true);

            const mainGridOverlay = GridFunctions.getRowEditingOverlay(customFixture);
            expect(mainGridOverlay).not.toBeNull();

            const mainGridOverlayTextContent = mainGridOverlay.querySelector('.igx-banner__text').textContent;
            const mainGridOverlayActionsContent = mainGridOverlay.querySelector('.igx-banner__actions').textContent;

            expect(mainGridOverlayTextContent).toBe(' You have 0 changes in this row and 0 hidden columns\n');
            expect(mainGridOverlayActionsContent).toBe('CancelDone');

            hierarchicalGrid.expandRow(hierarchicalGrid.getRowByIndex(0).key);
            customFixture.detectChanges();

            const secondLevelGrid = hierarchicalGrid.gridAPI.getChildGrids()[0];
            expect(secondLevelGrid).not.toBeNull();

            secondLevelGrid.primaryKey = 'ID';
            customFixture.detectChanges();

            expect(GridFunctions.getRowEditingOverlay(customFixture)).toBeDefined();

            cellElem = secondLevelGrid.gridAPI.get_cell_by_index(0, 'ProductName');
            row = secondLevelGrid.gridAPI.get_row_by_index(0);

            UIInteractions.simulateDoubleClickAndSelectEvent(cellElem);
            customFixture.detectChanges();
            expect(row.inEditMode).toBe(true);

            const nestedGridOverlay = GridFunctions.getRowEditingOverlay(customFixture);
            expect(nestedGridOverlay).not.toBeNull();

            const nestedGridOverlayTextContent = nestedGridOverlay.querySelector('.igx-banner__text').textContent;
            const nestedGridOverlayActionsContent = nestedGridOverlay.querySelector('.igx-banner__actions').textContent;

            expect(nestedGridOverlayTextContent).toBe('Row Edit Text');
            expect(nestedGridOverlayActionsContent).toBe('Row Edit Actions');
        });

        it(`Should set ID column's width property to auto on init`, () => {
            const customFixture = TestBed.createComponent(IgxHierarchicalGridAutoSizeColumnsComponent);
            hierarchicalGrid.primaryKey = 'ID';
            hierarchicalGrid = customFixture.componentInstance.hgrid;
            customFixture.detectChanges();

            expect(hierarchicalGrid).not.toBeNull();
            expect(hierarchicalGrid).not.toBeUndefined();
        });

        it(`Should keep the overlay when scrolling an igxHierarchicalGrid with an opened
                row island with <= 2 data records`, async () => {
            hierarchicalGrid.primaryKey = 'ID';
            hierarchicalGrid.rowEditable = true;
            hierarchicalGrid.getRowByIndex(0).expanded = true;
            fixture.detectChanges();

            const secondLevelGrid = hierarchicalGrid.gridAPI.getChildGrids()[0];
            expect(secondLevelGrid).not.toBeNull();
            secondLevelGrid.getRowByIndex(0).expanded = true;
            fixture.detectChanges();

            const thirdLevelGrid = secondLevelGrid.gridAPI.getChildGrids()[0];
            thirdLevelGrid.primaryKey = 'ID';
            thirdLevelGrid.rowEditable = true;
            fixture.detectChanges();

            expect(thirdLevelGrid).not.toBeNull();
            expect(thirdLevelGrid.data.length).toBe(2);

            const cellElem = thirdLevelGrid.gridAPI.get_cell_by_index(0, 'ChildLevels');
            const row = thirdLevelGrid.gridAPI.get_row_by_index(0);

            UIInteractions.simulateDoubleClickAndSelectEvent(cellElem);
            fixture.detectChanges();
            expect(row.inEditMode).toBe(true);
            fixture.detectChanges();

            let overlay = GridFunctions.getRowEditingOverlay(fixture);
            expect(overlay).not.toBeNull();

            await hierarchicalGrid.dragScroll({ left: 0, top: 10 });
            fixture.detectChanges();
            await wait(30);

            overlay = GridFunctions.getRowEditingOverlay(fixture);
            expect(overlay).not.toBeNull();
        });

    });

    describe('Columns and row islands runtime change', () => {
        let fixture: ComponentFixture<IgxHierarchicalGridToggleRIAndColsComponent>;
        let hierarchicalGrid: IgxHierarchicalGridComponent;

        it('should allow changing columns runtime in root grid when there are no row islands.', fakeAsync(() => {
            fixture = TestBed.createComponent(IgxHierarchicalGridToggleRIAndColsComponent);
            fixture.detectChanges();
            hierarchicalGrid = fixture.componentInstance.hgrid;
            expect(hierarchicalGrid.childLayoutList.length).toBe(0);
            expect(hierarchicalGrid.columns.length).toBe(0);
            fixture.componentInstance.toggleColumns = true;
            fixture.detectChanges();
            tick();

            expect(hierarchicalGrid.columns.length).toBe(2);

            fixture.componentInstance.toggleRI = true;
            fixture.detectChanges();
            expect(hierarchicalGrid.childLayoutList.length).toBe(1);
        }));
    });

    describe('IgxHierarchicalGrid custom template #hGrid', () => {

        it('should allow setting custom template for expand/collapse icons', () => {
            const fixture = TestBed.createComponent(IgxHierarchicalGridCustomTemplateComponent);
            fixture.detectChanges();

            const hierarchicalGrid = fixture.componentInstance.hgrid;

            let rows = hierarchicalGrid.dataRowList.toArray();
            for (const row of rows) {
                const expander =  row.nativeElement.querySelector('.igx-grid__hierarchical-expander');
                expect((expander as HTMLElement).innerText).toBe('COLLAPSED');
            }
            hierarchicalGrid.expandChildren = true;
            fixture.detectChanges();
            rows = hierarchicalGrid.dataRowList.toArray();
            for (const row of rows) {
                const expander =  row.nativeElement.querySelector('.igx-grid__hierarchical-expander');
                expect((expander as HTMLElement).innerText).toBe('EXPANDED');
            }

            const childGrid = hierarchicalGrid.gridAPI.getChildGrids(false)[0];
            const childRows = childGrid.dataRowList.toArray();
            for (const row of childRows) {
                const expander =  row.nativeElement.querySelector('.igx-grid__hierarchical-expander');
                expect((expander as HTMLElement).innerText).toBe('COLLAPSED');
            }

            expect((hierarchicalGrid as any).headerHierarchyExpander.nativeElement.innerText).toBe('EXPANDED');
            expect((childGrid as any).headerHierarchyExpander.nativeElement.innerText).toBe('COLLAPSED');

            childRows[0].toggle();
            fixture.detectChanges();
            expect((childGrid as any).headerHierarchyExpander.nativeElement.innerText).toBe('EXPANDED');
            hierarchicalGrid.expandChildren = false;
            fixture.detectChanges();
            expect((hierarchicalGrid as any).headerHierarchyExpander.nativeElement.innerText).toBe('COLLAPSED');
        });

        it('should allow setting custom template for excel style filtering on row island.', () => {
            const fixture = TestBed.createComponent(IgxHierarchicalGridCustomFilteringTemplateComponent);
            fixture.detectChanges();

            const hierarchicalGrid = fixture.componentInstance.hgrid;
            const ri = fixture.componentInstance.rowIsland;
            const firstRow = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(firstRow.expander);
            fixture.detectChanges();

            const childGrid = hierarchicalGrid.gridAPI.getChildGrids()[0] as IgxHierarchicalGridComponent;
            expect(childGrid.excelStyleFilteringComponent).toBe(ri.excelStyleFilteringComponent);
        });

        it('should correctly filter templated row island in hierarchical grid', fakeAsync(() => {
            const fixture = TestBed.createComponent(IgxHierarchicalGridCustomFilteringTemplateComponent);
            fixture.detectChanges();

            const hierarchicalGrid = fixture.componentInstance.hgrid;
            const firstRow = hierarchicalGrid.gridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent;
            UIInteractions.simulateClickAndSelectEvent(firstRow.expander);
            fixture.detectChanges();

            GridFunctions.clickExcelFilterIconFromCode(fixture, hierarchicalGrid, 'ProductName');

            const searchComponent = GridFunctions.getExcelStyleSearchComponent(fixture, null, 'igx-hierarchical-grid');
            const inputNativeElement = GridFunctions.getExcelStyleSearchComponentInput(fixture, searchComponent, 'igx-hierarchical-grid');
            UIInteractions.clickAndSendInputElementValue(inputNativeElement, 'A4', fixture);

            GridFunctions.clickApplyExcelStyleFiltering(fixture, null, 'igx-hierarchical-grid');
            fixture.detectChanges();

            const gridCellValues = GridFunctions.getColumnCells(fixture, 'ProductName', 'igx-hierarchical-grid-cell')
                .map(c => c.nativeElement.innerText)
                .sort();

            expect(gridCellValues.length).toBe(1);
        }));
    });

});

@Component({
    template: `
    <igx-hierarchical-grid #grid1 [data]="data"
     [autoGenerate]="false" [height]="'400px'" [width]="width" #hierarchicalGrid>
     <igx-column field="ID"></igx-column>
     <igx-column field="ProductName"></igx-column>
        <igx-row-island [key]="'childData'" [autoGenerate]="false" #rowIsland>
            <igx-column field="ID"></igx-column>
            <igx-column field="ProductName"></igx-column>
            <igx-column field="Col1"></igx-column>
            <igx-column field="Col2"></igx-column>
            <igx-column field="Col3"></igx-column>
            <igx-row-island [key]="'childData'" [autoGenerate]="true" #rowIsland2 >
            </igx-row-island>
        </igx-row-island>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent]
})
export class IgxHierarchicalGridTestBaseComponent {
    @ViewChild('hierarchicalGrid', { read: IgxHierarchicalGridComponent, static: true }) public hgrid: IgxHierarchicalGridComponent;
    @ViewChild('rowIsland', { read: IgxRowIslandComponent, static: true }) public rowIsland: IgxRowIslandComponent;
    @ViewChild('rowIsland2', { read: IgxRowIslandComponent, static: true }) public rowIsland2: IgxRowIslandComponent;
    public data;
    public width = '500px';

    constructor() {
        // 3 level hierarchy
        this.data = this.generateDataUneven(20, 3);
    }
    public generateDataUneven(count: number, level: number, parentID: string = null) {
        const prods = [];
        const currLevel = level;
        let children;
        for (let i = 0; i < count; i++) {
            const rowID = parentID ? parentID + i : i.toString();
            if (level > 0 ) {
               // Have child grids for row with even id less rows by not multiplying by 2
               children = this.generateDataUneven((i % 2 + 1) * Math.round(count / 3) , currLevel - 1, rowID);
            }
            prods.push({
                ID: rowID, ChildLevels: currLevel,  ProductName: 'Product: A' + i, Col1: i,
                Col2: i, Col3: i, childData: children, childData2: children });
        }
        return prods;
    }

    public clearData(){
        this.data = [];
    }
}

@Component({
    template: `
    <igx-hierarchical-grid #grid1 [data]="data" [autoGenerate]="false" [height]="'400px'" [width]="'500px'" #hierarchicalGrid>
    <igx-column field="ID"></igx-column>
    <igx-column field="ProductName"></igx-column>
        <igx-row-island [key]="'childData'" [autoGenerate]="false" [height]="height" #rowIsland1>
            <igx-column field="ID"></igx-column>
            <igx-column field="ProductName"></igx-column>
        </igx-row-island>
        <igx-row-island [key]="'childData2'" [autoGenerate]="false" [height]="height" #rowIsland2>
            <igx-column field="Col1"></igx-column>
            <igx-column field="Col2"></igx-column>
            <igx-column field="Col3"></igx-column>
        </igx-row-island>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent]
})
export class IgxHierarchicalGridMultiLayoutComponent extends IgxHierarchicalGridTestBaseComponent {
    @ViewChild('rowIsland1', { read: IgxRowIslandComponent, static: true }) public rowIsland1: IgxRowIslandComponent;
    @ViewChild('rowIsland2', { read: IgxRowIslandComponent, static: true }) public override rowIsland2: IgxRowIslandComponent;
    public height = '100px';
}

@Component({
    template: `
        <igx-hierarchical-grid [data]="data" [isLoading]="true" [autoGenerate]="true" [height]="'600px'">
            <igx-row-island [key]="'childData'" [autoGenerate]="false" #rowIsland1 (gridCreated)="gridCreated($event, rowIsland1)">
                <igx-column field="ID"></igx-column>
                <igx-column field="ProductName"></igx-column>
                <igx-row-island [key]="'childData2'" [autoGenerate]="true" #rowIsland2>
                </igx-row-island>
            </igx-row-island>
        </igx-hierarchical-grid>
    `,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent]
})
export class IgxHGridRemoteOnDemandComponent {
    @ViewChild(IgxHierarchicalGridComponent, { read: IgxHierarchicalGridComponent, static: true })
    public instance: IgxHierarchicalGridComponent;

    @ViewChild('rowIsland1', { read: IgxRowIslandComponent, static: true })
    public rowIsland: IgxRowIslandComponent;

    @ViewChild('rowIsland2', { read: IgxRowIslandComponent, static: true })
    public rowIsland2: IgxRowIslandComponent;

    public data;

    constructor(public cdr: ChangeDetectorRef) { }

    public generateDataUneven(count: number, level: number, parendID: string = null) {
        const prods = [];
        const currLevel = level;
        for (let i = 0; i < count; i++) {
            const rowID = parendID ? parendID + i : i.toString();
            prods.push({
                ID: rowID, ChildLevels: currLevel,  ProductName: 'Product: A' + i, Col1: i,
                Col2: i, Col3: i });
        }
        return prods;
    }

    public databind() {
        this.data = this.generateDataUneven(20, 3);
    }

    public generateRowIslandData(count: number) {
        const prods = [];
        for (let i = 0; i < count; i++) {
            prods.push({ ID: i, ProductName: 'Product: A' + i });
        }
        return prods;
    }

    public gridCreated(event: IGridCreatedEventArgs, _rowIsland: IgxRowIslandComponent) {
        setTimeout(() => {
            event.grid.data = this.generateRowIslandData(5);
            event.grid.cdr.detectChanges();
        });
    }
}

@Component({
    template: `
    <igx-hierarchical-grid #hierarchicalGrid [data]="data" [autoGenerate]="false" [height]="'500px'" [width]="'800px'" >
        <igx-column field="ID"></igx-column>
        <igx-column field="ProductName"></igx-column>
        <igx-column *ngFor="let colField of parentCols" [field]="colField"></igx-column>
        <igx-row-island key="childData" [autoGenerate]="false" #rowIsland [height]="'350px'">
            <igx-column *ngFor="let colField of islandCols1" [field]="colField"></igx-column>
            <igx-row-island key="childData" [autoGenerate]="false" #rowIsland2 [height]="'200px'">
                <igx-column *ngFor="let colField of islandCols2" [field]="colField"></igx-column>
            </igx-row-island>
        </igx-row-island>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent, NgFor]
})
export class IgxHierarchicalGridColumnsUpdateComponent extends IgxHierarchicalGridTestBaseComponent implements AfterViewInit {
    public cols1 = ['ID', 'ProductName', 'Col1', 'Col2', 'Col3'];
    public cols2 =  ['ID', 'ProductName', 'Col1'];
    public parentCols = [];
    public islandCols1 = [];
    public islandCols2 = [];
    constructor(public cdr: ChangeDetectorRef) {
        super();
    }

    public ngAfterViewInit() {
        this.islandCols1 = this.cols1;
        this.islandCols2 = this.cols2;
        this.cdr.detectChanges();
    }
}

@Component({
    template: `
    <igx-hierarchical-grid #grid1 [data]="data"
        [autoGenerate]="false" [height]="'600px'" [width]="'700px'" #hierarchicalGrid>
        <igx-column field="ID"></igx-column>
        <igx-column field="ProductName"></igx-column>
        <igx-row-island key="childData" [autoGenerate]="false" [width]="'500px'" [height]="childHeight" #rowIsland>
            <igx-column field="ID"></igx-column>
            <igx-column field="ProductName"></igx-column>
        </igx-row-island>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent]
})
export class IgxHierarchicalGridSizingComponent {
    @ViewChild('hierarchicalGrid', { read: IgxHierarchicalGridComponent, static: true })
    public hgrid: IgxHierarchicalGridComponent;

    @ViewChild('rowIsland', { read: IgxRowIslandComponent, static: true })
    public rowIsland: IgxRowIslandComponent;

    public childHeight = '100%';
    public data = [
        {
            ID: 1,
            ProductName: 'Car'
        }
    ];
    public fullData = Array.from({ length: 100000 }, (_, i) => ({ ID: i, ProductName: 'PN' + i }));
    public semiData = Array.from({ length: 15 }, (_, i) => ({ ID: i, ProductName: 'PN' + i }));
}

@Component({
    template: `
    <igx-hierarchical-grid #grid1 [data]="data"
     [autoGenerate]="true" [height]="'400px'" [width]="'500px'" #hierarchicalGrid>
     <igx-row-island *ngIf="toggleRI" key="childData" [autoGenerate]="true">
        <igx-row-island *ngIf="toggleChildRI" key="childData" [autoGenerate]="true">
        </igx-row-island>
     </igx-row-island>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent, NgIf]
})
export class IgxHierarchicalGridToggleRIComponent  extends IgxHierarchicalGridTestBaseComponent {
public toggleRI = true;
public toggleChildRI = true;
}

@Component({
    template: `
    <igx-hierarchical-grid #hierarchicalGrid [data]="data"
     [autoGenerate]="false" [height]="'400px'" [width]="'500px'">
     <igx-column field="ID" *ngIf="toggleColumns"></igx-column>
     <igx-column field="ProductName" *ngIf="toggleColumns"></igx-column>
     <igx-row-island *ngIf="toggleRI" [key]="'childData'" [autoGenerate]="true">
     </igx-row-island>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent, NgIf]
})
export class IgxHierarchicalGridToggleRIAndColsComponent  extends IgxHierarchicalGridToggleRIComponent {
    public override toggleRI = false;
    public toggleColumns = false;
}

@Component({
    template: `
    <igx-hierarchical-grid #grid1 [data]="data" [showExpandAll]='true'
     [autoGenerate]="false" [height]="'400px'" [width]="width" #hierarchicalGrid>
     <igx-column field="ID"></igx-column>
     <igx-column field="ProductName"></igx-column>
        <igx-row-island [showExpandAll]="true" key="childData" [autoGenerate]="false" #rowIsland>
            <igx-column field="ID"></igx-column>
            <igx-column field="ProductName"></igx-column>
            <igx-row-island key="childData" [autoGenerate]="true" #rowIsland2 >
            </igx-row-island>
        </igx-row-island>
        <ng-template igxRowExpandedIndicator>
                <span>EXPANDED</span>
        </ng-template>
        <ng-template igxRowCollapsedIndicator>
                <span>COLLAPSED</span>
        </ng-template>
        <ng-template igxHeaderCollapsedIndicator>
            <span>COLLAPSED</span>
        </ng-template>
        <ng-template igxHeaderExpandedIndicator>
            <span>EXPANDED</span>
        </ng-template>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent, IgxRowExpandedIndicatorDirective, IgxRowCollapsedIndicatorDirective, IgxHeaderExpandedIndicatorDirective, IgxHeaderCollapsedIndicatorDirective]
})
export class IgxHierarchicalGridCustomTemplateComponent extends IgxHierarchicalGridTestBaseComponent {}

@Component({
    template: `
    <igx-hierarchical-grid #grid1 [data]="data" [showExpandAll]='true'
        [autoGenerate]="false" [height]="'400px'" [width]="width" [allowFiltering]="true" filterMode="excelStyleFilter" #hierarchicalGrid>
     <igx-column field="ID"></igx-column>
     <igx-column field="ProductName"></igx-column>
    <igx-row-island [showExpandAll]='true' [key]="'childData'" [autoGenerate]="false"
        [allowFiltering]="true" filterMode="excelStyleFilter" #rowIsland>
        <ng-template igxExcelStyleHeaderIcon>
            <igx-icon>filter_alt</igx-icon>
        </ng-template>
        <igx-grid-excel-style-filtering [minHeight]="'280px'" [maxHeight]="'300px'">
            <igx-excel-style-column-operations>
                <igx-excel-style-header
                    [showPinning]="true"
                    [showHiding]="true"
                >
                </igx-excel-style-header>
                <igx-excel-style-sorting></igx-excel-style-sorting>
            </igx-excel-style-column-operations>
            <igx-excel-style-filter-operations>
                <igx-excel-style-search></igx-excel-style-search>
            </igx-excel-style-filter-operations>
        </igx-grid-excel-style-filtering>
        <igx-column field="ID"></igx-column>
        <igx-column field="ProductName"></igx-column>
        <igx-row-island [key]="'childData'" [autoGenerate]="true" #rowIsland2 >
        </igx-row-island>
    </igx-row-island>
        <ng-template igxRowExpandedIndicator>
                <span>EXPANDED</span>
        </ng-template>
        <ng-template igxRowCollapsedIndicator>
                <span>COLLAPSED</span>
        </ng-template>
        <ng-template igxHeaderCollapsedIndicator>
            <span>COLLAPSED</span>
        </ng-template>
        <ng-template igxHeaderExpandedIndicator>
            <span>EXPANDED</span>
        </ng-template>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [
        IgxHierarchicalGridComponent,
        IgxColumnComponent,
        IgxRowIslandComponent,
        IgxIconComponent,
        IgxGridExcelStyleFilteringComponent,
        IgxExcelStyleColumnOperationsTemplateDirective,
        IgxExcelStyleHeaderComponent,
        IgxExcelStyleSortingComponent,
        IgxExcelStyleFilterOperationsTemplateDirective,
        IgxExcelStyleSearchComponent,
        IgxRowExpandedIndicatorDirective,
        IgxRowCollapsedIndicatorDirective,
        IgxHeaderExpandedIndicatorDirective,
        IgxHeaderCollapsedIndicatorDirective
    ]
})
export class IgxHierarchicalGridCustomFilteringTemplateComponent extends IgxHierarchicalGridTestBaseComponent {}

@Component({
    template: `
    <ng-template igxHeader let-column #pinTemplate>
        <div class="title-inner">
            <span style="float:left">{{column.header || column.field}}</span>
            <igx-icon fontSet="material"(click)="pinColumn(column)">lock</igx-icon>
        </div>
    </ng-template>
    <ng-template igxHeader let-column #hideTemplate>
        <div class="title-inner">
            <span style="float:left">{{column.header || column.field}}</span>
            <igx-icon (click)="hideColumn(column)">hide_source</igx-icon>
        </div>
    </ng-template>
    <igx-hierarchical-grid #hierarchicalGrid [data]="data" [autoGenerate]="false" [height]="'500px'" [width]="'800px'" >
        <igx-column field="ID"></igx-column>
        <igx-column field="ProductName"></igx-column>
        <igx-row-island [key]="'childData'" [autoGenerate]="false" #rowIsland [height]="'350px'">
            <igx-column field="ID" [headerTemplate]="pinTemplate"></igx-column>
            <igx-column field="ProductName"></igx-column>
            <igx-column field="Col1" [headerTemplate]="hideTemplate"></igx-column>
        </igx-row-island>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent, IgxIconComponent, IgxCellHeaderTemplateDirective]
})
export class IgxHierarchicalGridHidingPinningColumnsComponent extends IgxHierarchicalGridTestBaseComponent {
    constructor(public cdr: ChangeDetectorRef) {
        super();
    }

    public pinColumn(col: ColumnType) {
        col.pin();
    }

    public hideColumn(col: ColumnType){
        col.hidden = true;
    }
}

@Component({
    template: `
    <igx-hierarchical-grid #grid1 [data]="data" [autoGenerate]="false"
    [height]="'400px'" [width]="width" [rowEditable]="true" #hierarchicalGrid>
     <igx-column field="ID"></igx-column>
     <igx-column field="ProductName"></igx-column>
        <igx-row-island key="childData" [autoGenerate]="false" [rowEditable]="true"
            #rowIsland>
            <igx-column field="ID"></igx-column>
            <igx-column field="ProductName"></igx-column>
            <igx-row-island key="childData" [autoGenerate]="true" #rowIsland2 >
            </igx-row-island>
            <ng-template igxRowEditText let-rowChangesCount>
                <span>Row Edit Text</span>
            </ng-template>
            <ng-template igxRowEditActions let-endRowEdit>
                <span>Row Edit Actions</span>
            </ng-template>
        </igx-row-island>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent, IgxRowEditTextDirective, IgxRowEditActionsDirective]
})
export class IgxHierarchicalGridCustomRowEditOverlayComponent extends IgxHierarchicalGridTestBaseComponent{}

@Component({
    template: `
    <igx-hierarchical-grid #grid1 [data]="data" [autoGenerate]="false"
    [height]="'400px'" [width]="width" [rowEditable]="true" #hierarchicalGrid>
     <igx-column field="ID" width="auto"></igx-column>
     <igx-column field="ProductName" width="auto"></igx-column>
        <igx-row-island [key]="'childData'" [autoGenerate]="false" [rowEditable]="true"
            #rowIsland>
            <igx-column field="ID"></igx-column>
            <igx-column field="ProductName"></igx-column>
            <igx-row-island [key]="'childData'" [autoGenerate]="true" #rowIsland2 >
            </igx-row-island>
            <ng-template igxRowEditText let-rowChangesCount>
                <span>Row Edit Text</span>
            </ng-template>
            <ng-template igxRowEditActions let-endRowEdit>
                <span>Row Edit Actions</span>
            </ng-template>
        </igx-row-island>
    </igx-hierarchical-grid>`,
    standalone: true,
    imports: [IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent, IgxRowEditTextDirective, IgxRowEditActionsDirective]
})
export class IgxHierarchicalGridAutoSizeColumnsComponent extends IgxHierarchicalGridTestBaseComponent {}