import { TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing'; import { IgxTreeGridComponent } from './tree-grid.component'; import { IgxTreeGridSimpleComponent, IgxTreeGridCellSelectionComponent, IgxTreeGridSelectionRowEditingComponent, IgxTreeGridSelectionWithTransactionComponent, IgxTreeGridRowEditingTransactionComponent, IgxTreeGridCustomRowSelectorsComponent, IgxTreeGridCascadingSelectionComponent, IgxTreeGridCascadingSelectionTransactionComponent, IgxTreeGridPrimaryForeignKeyCascadeSelectionComponent } from '../../test-utils/tree-grid-components.spec'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { TreeGridFunctions, TREE_ROW_SELECTION_CSS_CLASS, ROW_EDITING_BANNER_OVERLAY_CLASS, TREE_ROW_DIV_SELECTION_CHECKBOX_CSS_CLASS } from '../../test-utils/tree-grid-functions.spec'; import { IgxStringFilteringOperand, IgxNumberFilteringOperand } from '../../data-operations/filtering-condition'; import { configureTestSuite } from '../../test-utils/configure-suite'; import { wait, UIInteractions } from '../../test-utils/ui-interactions.spec'; import { IgxActionStripComponent } from '../../action-strip/public_api'; import { GridFunctions } from '../../test-utils/grid-functions.spec'; import { GridSelectionMode } from '../common/enums'; import { By } from '@angular/platform-browser'; import { FilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree'; import { FilteringLogic } from '../../data-operations/filtering-expression.interface'; import { IRowSelectionEventArgs } from '../common/events'; import { SortingDirection } from '../../data-operations/sorting-strategy'; import { IgxGridCell } from '../public_api'; describe('IgxTreeGrid - Selection #tGrid', () => { configureTestSuite(); let fix; let treeGrid: IgxTreeGridComponent; let actionStrip: IgxActionStripComponent; const endTransition = () => { // transition end needs to be simulated const animationElem = fix.nativeElement.querySelector('.igx-grid__tr--inner'); const endEvent = new AnimationEvent('animationend'); animationElem.dispatchEvent(endEvent); }; beforeAll(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ NoopAnimationsModule, IgxTreeGridSimpleComponent, IgxTreeGridCellSelectionComponent, IgxTreeGridSelectionRowEditingComponent, IgxTreeGridSelectionWithTransactionComponent, IgxTreeGridRowEditingTransactionComponent, IgxTreeGridCustomRowSelectorsComponent, IgxTreeGridCascadingSelectionComponent, IgxTreeGridCascadingSelectionTransactionComponent, IgxTreeGridPrimaryForeignKeyCascadeSelectionComponent ] }).compileComponents(); })); describe('API Row Selection', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridSimpleComponent); treeGrid = fix.componentInstance.treeGrid; treeGrid.rowSelection = GridSelectionMode.multiple; fix.detectChanges(); }); it('should have checkbox on each row if rowSelection is not none', () => { const rows = TreeGridFunctions.getAllRows(fix); expect(rows.length).toBe(10); rows.forEach((row) => { const checkBoxElement = row.nativeElement.querySelector(TREE_ROW_DIV_SELECTION_CHECKBOX_CSS_CLASS); expect(checkBoxElement).not.toBeNull(); }); treeGrid.rowSelection = GridSelectionMode.none; fix.detectChanges(); expect(rows.length).toBe(10); rows.forEach((row) => { const checkBoxElement = row.nativeElement.querySelector(TREE_ROW_DIV_SELECTION_CHECKBOX_CSS_CLASS); expect(checkBoxElement).toBeNull(); }); }); it('should be able to select/deselect all rows', () => { treeGrid.selectAllRows(); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], true); expect(treeGrid.selectedRows.length).toEqual(10); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); treeGrid.deselectAllRows(); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([]); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it('when all items are selected and then some of the selected rows are deleted, still all the items should be selected', () => { treeGrid.selectAllRows(); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); treeGrid.deleteRowById(treeGrid.selectedRows[0]); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); treeGrid.deleteRowById(treeGrid.selectedRows[0]); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); treeGrid.deleteRowById(treeGrid.selectedRows[0]); fix.detectChanges(); // When deleting the last selected row, header checkbox will be unchecked. TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it('should be able to select row of any level', () => { treeGrid.selectRows([treeGrid.gridAPI.get_row_by_index(0).key], true); fix.detectChanges(); // Verify selection. TreeGridFunctions.verifyDataRowsSelection(fix, [0], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.selectRows([treeGrid.gridAPI.get_row_by_index(2).key], false); fix.detectChanges(); // Verify new selection by keeping the old one. TreeGridFunctions.verifyDataRowsSelection(fix, [0, 2], true); treeGrid.selectRows([treeGrid.gridAPI.get_row_by_index(1).key, treeGrid.gridAPI.get_row_by_index(3).key, treeGrid.gridAPI.get_row_by_index(6).key, treeGrid.gridAPI.get_row_by_index(8).key], true); fix.detectChanges(); // Verify new selection by NOT keeping the old one. TreeGridFunctions.verifyDataRowsSelection(fix, [0, 2], false); TreeGridFunctions.verifyDataRowsSelection(fix, [1, 3, 6, 8], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('should be able to deselect row of any level', () => { treeGrid.selectRows([treeGrid.gridAPI.get_row_by_index(1).key, treeGrid.gridAPI.get_row_by_index(3).key, treeGrid.gridAPI.get_row_by_index(6).key, treeGrid.gridAPI.get_row_by_index(8).key, treeGrid.gridAPI.get_row_by_index(9).key], true); fix.detectChanges(); treeGrid.deselectRows([treeGrid.gridAPI.get_row_by_index(1).key, treeGrid.gridAPI.get_row_by_index(3).key]); fix.detectChanges(); // Verify modified selection TreeGridFunctions.verifyDataRowsSelection(fix, [1, 3], false); TreeGridFunctions.verifyDataRowsSelection(fix, [6, 8, 9], true); }); it('should persist the selection after sorting', () => { treeGrid.selectRows([treeGrid.gridAPI.get_row_by_index(0).key, treeGrid.gridAPI.get_row_by_index(4).key], true); fix.detectChanges(); treeGrid.sort({ fieldName: 'Age', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); // Verification indices are different since the sorting changes rows' positions. TreeGridFunctions.verifyDataRowsSelection(fix, [2, 7], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.clearSort(); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 4], true); }); it('should persist the selection after filtering', fakeAsync(() => { treeGrid.selectRows([treeGrid.gridAPI.get_row_by_index(0).key, treeGrid.gridAPI.get_row_by_index(5).key, treeGrid.gridAPI.get_row_by_index(8).key], true); fix.detectChanges(); treeGrid.filter('Age', 40, IgxNumberFilteringOperand.instance().condition('greaterThan')); fix.detectChanges(); tick(); // Verification indices are different since the sorting changes rows' positions. TreeGridFunctions.verifyDataRowsSelection(fix, [0, 2, 4], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.clearFilter(); fix.detectChanges(); tick(); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 5, 8], true); })); it('should be able to select and select only filtered data', () => { treeGrid.selectRows([299, 147]); fix.detectChanges(); treeGrid.filter('Age', 40, IgxNumberFilteringOperand.instance().condition('greaterThan')); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([299, 147]); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.selectAllRows(true); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([299, 147, 317, 998, 19, 847]); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); treeGrid.deselectAllRows(true); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([299]); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); treeGrid.clearFilter(); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([299]); TreeGridFunctions.verifyDataRowsSelection(fix, [6], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('should persist the selection after expand/collapse', () => { treeGrid.selectRows([treeGrid.gridAPI.get_row_by_index(0).key, treeGrid.gridAPI.get_row_by_index(3).key, treeGrid.gridAPI.get_row_by_index(5).key], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); // Collapse row and verify visible selected rows treeGrid.toggleRow(treeGrid.gridAPI.get_row_by_index(0).key); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); // Expand same row and verify visible selected rows treeGrid.toggleRow(treeGrid.gridAPI.get_row_by_index(0).key); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 3, 5], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('should persist selection after paging', fakeAsync(() => { treeGrid.selectRows([treeGrid.gridAPI.get_row_by_index(0).key, treeGrid.gridAPI.get_row_by_index(3).key, treeGrid.gridAPI.get_row_by_index(5).key], true); fix.detectChanges(); tick(16); fix.componentInstance.paging = true; fix.detectChanges(); treeGrid.paginator.perPage = 4; fix.detectChanges(); tick(16); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 0, true); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 1, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 2, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, true); treeGrid.paginator.page = 1; fix.detectChanges(); tick(16); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 0, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 1, true); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 2, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, false); treeGrid.paginator.page = 2; fix.detectChanges(); tick(16); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 0, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 1, false); })); it('Should bind selectedRows properly', () => { fix.componentInstance.selectedRows = [147, 19, 957]; fix.detectChanges(); expect(treeGrid.gridAPI.get_row_by_index(0).selected).toBeTrue(); expect(treeGrid.gridAPI.get_row_by_index(7).selected).toBeTrue(); expect(treeGrid.gridAPI.get_row_by_index(4).selected).toBeFalse(); fix.componentInstance.selectedRows = [847, 711]; fix.detectChanges(); expect(treeGrid.gridAPI.get_row_by_index(0).selected).toBeFalse(); expect(treeGrid.gridAPI.get_row_by_index(4).selected).toBeTrue(); expect(treeGrid.gridAPI.get_row_by_index(8).selected).toBeTrue(); }); }); describe('UI Row Selection', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridSimpleComponent); treeGrid = fix.componentInstance.treeGrid; treeGrid.rowSelection = GridSelectionMode.multiple; fix.detectChanges(); }); it('should be able to select/deselect all rows', () => { TreeGridFunctions.clickHeaderRowSelectionCheckbox(fix); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); TreeGridFunctions.clickHeaderRowSelectionCheckbox(fix); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [], true); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it('Header checkbox should NOT select/deselect all rows when selectionMode is single', () => { spyOn(treeGrid.rowSelectionChanging, 'emit').and.callThrough(); treeGrid.rowSelection = GridSelectionMode.single; fix.detectChanges(); TreeGridFunctions.clickHeaderRowSelectionCheckbox(fix); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); TreeGridFunctions.verifyDataRowsSelection(fix, [], false); expect(treeGrid.selectedRows).toEqual([]); expect(treeGrid.rowSelectionChanging.emit).toHaveBeenCalledTimes(0); TreeGridFunctions.clickHeaderRowSelectionCheckbox(fix); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); TreeGridFunctions.verifyDataRowsSelection(fix, [], false); expect(treeGrid.selectedRows).toEqual([]); expect(treeGrid.rowSelectionChanging.emit).toHaveBeenCalledTimes(0); }); it('should be able to select row of any level', () => { TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [0], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); TreeGridFunctions.clickRowSelectionCheckbox(fix, 2); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 2], true); // Deselect rows TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); TreeGridFunctions.clickRowSelectionCheckbox(fix, 2); fix.detectChanges(); // Select new rows TreeGridFunctions.clickRowSelectionCheckbox(fix, 1); TreeGridFunctions.clickRowSelectionCheckbox(fix, 3); TreeGridFunctions.clickRowSelectionCheckbox(fix, 6); TreeGridFunctions.clickRowSelectionCheckbox(fix, 8); fix.detectChanges(); // Verify new selection TreeGridFunctions.verifyDataRowsSelection(fix, [0, 2], false); TreeGridFunctions.verifyDataRowsSelection(fix, [1, 3, 6, 8], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('should be able to deselect row of any level', () => { // Select rows TreeGridFunctions.clickRowSelectionCheckbox(fix, 1); TreeGridFunctions.clickRowSelectionCheckbox(fix, 3); TreeGridFunctions.clickRowSelectionCheckbox(fix, 6); TreeGridFunctions.clickRowSelectionCheckbox(fix, 8); TreeGridFunctions.clickRowSelectionCheckbox(fix, 9); fix.detectChanges(); // Deselect rows TreeGridFunctions.clickRowSelectionCheckbox(fix, 1); TreeGridFunctions.clickRowSelectionCheckbox(fix, 3); fix.detectChanges(); // Verify modified selection TreeGridFunctions.verifyDataRowsSelection(fix, [1, 3], false); TreeGridFunctions.verifyDataRowsSelection(fix, [6, 8, 9], true); }); it('Rows would be selected only from checkboxes if selectRowOnClick is disabled', () => { expect(treeGrid.selectRowOnClick).toBe(true); const firstRow = treeGrid.gridAPI.get_row_by_index(1); const secondRow = treeGrid.gridAPI.get_row_by_index(4); expect(treeGrid.selectedRows).toEqual([]); // selectRowOnClick = true; UIInteractions.simulateClickEvent(firstRow.nativeElement); fix.detectChanges(); UIInteractions.simulateClickEvent(secondRow.nativeElement, false, true); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [1, 4], true); TreeGridFunctions.clickRowSelectionCheckbox(fix, 1); fix.detectChanges(); TreeGridFunctions.clickRowSelectionCheckbox(fix, 4); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([]); // selectRowOnClick = false treeGrid.selectRowOnClick = false; UIInteractions.simulateClickEvent(firstRow.nativeElement); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [1], false); TreeGridFunctions.clickRowSelectionCheckbox(fix, 1); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [1], true); TreeGridFunctions.clickRowSelectionCheckbox(fix, 4); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [1, 4], true); }); it('should persist the selection after sorting', () => { TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); TreeGridFunctions.clickRowSelectionCheckbox(fix, 4); treeGrid.columnList.filter(c => c.field === 'Age')[0].sortable = true; fix.detectChanges(); treeGrid.sort({ fieldName: 'Age', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); // Verification indices are different since the sorting changes rows' positions. TreeGridFunctions.verifyDataRowsSelection(fix, [2, 7], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.clearSort(); fix.detectChanges(); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 4], true); }); it('should persist the selection after filtering', fakeAsync(() => { TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); TreeGridFunctions.clickRowSelectionCheckbox(fix, 5); TreeGridFunctions.clickRowSelectionCheckbox(fix, 8); treeGrid.filter('Age', 40, IgxNumberFilteringOperand.instance().condition('greaterThan')); fix.detectChanges(); tick(100); // Verification indices are different since the sorting changes rows' positions. TreeGridFunctions.verifyDataRowsSelection(fix, [0, 2, 4], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.clearFilter(); fix.detectChanges(); tick(100); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 5, 8], true); })); it('should update header checkbox when reselecting all filtered-in rows', fakeAsync(() => { treeGrid.filter('Age', 30, IgxNumberFilteringOperand.instance().condition('lessThan')); tick(100); TreeGridFunctions.clickHeaderRowSelectionCheckbox(fix); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); // Verify header checkbox is selected TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); // Unselect row fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // Verify header checkbox is indeterminate TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); // Reselect same row fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); // Verify header checkbox is selected })); it('should persist the selection after expand/collapse', () => { TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); TreeGridFunctions.clickRowSelectionCheckbox(fix, 3); TreeGridFunctions.clickRowSelectionCheckbox(fix, 5); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); // Collapse row and verify visible selected rows TreeGridFunctions.clickRowIndicator(fix, 0); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); // Expand same row and verify visible selected rows TreeGridFunctions.clickRowIndicator(fix, 0); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 3, 5], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('should persist selection after paging', fakeAsync(() => { TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); TreeGridFunctions.clickRowSelectionCheckbox(fix, 3); TreeGridFunctions.clickRowSelectionCheckbox(fix, 5); fix.detectChanges(); fix.componentInstance.paging = true; fix.detectChanges(); treeGrid.paginator.perPage = 4; fix.detectChanges(); tick(16); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 0, true); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 1, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 2, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, true); treeGrid.paginator.page = 1; fix.detectChanges(); tick(16); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 0, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 1, true); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 2, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, false); treeGrid.paginator.page = 2; fix.detectChanges(); tick(16); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 0, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 1, false); })); it('Should update selectedRows when selecting rows from UI', () => { TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); TreeGridFunctions.clickRowSelectionCheckbox(fix, 3); TreeGridFunctions.clickRowSelectionCheckbox(fix, 5); fix.detectChanges(); expect(treeGrid.selectedRows.length).toBe(3); }); }); describe('Row Selection with transactions - Hierarchical DS', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridSelectionWithTransactionComponent); treeGrid = fix.componentInstance.treeGrid; treeGrid.rowSelection = GridSelectionMode.multiple; fix.detectChanges(); }); it('should deselect row when delete its parent', () => { treeGrid.selectRows([treeGrid.gridAPI.get_row_by_index(3).key, treeGrid.gridAPI.get_row_by_index(5).key], true); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, true); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 5, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.deleteRow(147); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 5, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); expect(treeGrid.selectedRows).toEqual([]); // try to select deleted row UIInteractions.simulateClickEvent(treeGrid.gridAPI.get_row_by_index(0).nativeElement); TreeGridFunctions.clickRowSelectionCheckbox(fix, 3); TreeGridFunctions.clickRowSelectionCheckbox(fix, 5); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 0, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 5, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); expect(treeGrid.selectedRows).toEqual([]); // undo transaction treeGrid.transactions.undo(); fix.detectChanges(); // select rows UIInteractions.simulateClickEvent(treeGrid.gridAPI.get_row_by_index(0).nativeElement); TreeGridFunctions.clickRowSelectionCheckbox(fix, 3); TreeGridFunctions.clickRowSelectionCheckbox(fix, 5); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 0, true); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, true); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 5, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); expect(treeGrid.selectedRows).toEqual([147, 317, 998]); // redo transaction treeGrid.transactions.redo(); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 0, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 5, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); expect(treeGrid.selectedRows).toEqual([]); }); it('should have correct header checkbox when delete a row', () => { treeGrid.selectAllRows(); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); treeGrid.deleteRow(317); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); expect(treeGrid.selectedRows.includes(317)).toEqual(false); expect(treeGrid.selectedRows.includes(711)).toEqual(false); expect(treeGrid.selectedRows.includes(998)).toEqual(false); // undo transaction treeGrid.transactions.undo(); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 4, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 5, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // redo transaction treeGrid.transactions.redo(); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 3, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 4, false); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 5, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); }); it('should have correct header checkbox when add a row', () => { treeGrid.selectAllRows(); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); treeGrid.addRow({ ID: 13, Name: 'Michael Cooper', Age: 33, OnPTO: false }, 317); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 6, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); expect(treeGrid.selectedRows.includes(13)).toEqual(false); // undo transaction treeGrid.transactions.undo(); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); }); it('should have correct header checkbox when add a row and then selectAll rows', () => { treeGrid.addRow({ ID: 13, Name: 'Michael Cooper', Age: 33, OnPTO: false }, 317); fix.detectChanges(); TreeGridFunctions.clickHeaderRowSelectionCheckbox(fix); fix.detectChanges(); expect(treeGrid.selectedRows.length).toBeGreaterThan(treeGrid.flatData.length); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); }); it('should have correct header checkbox when add a row and undo transaction', fakeAsync(() => { treeGrid.addRow({ ID: 13, Name: 'Michael Cooper', Age: 33, OnPTO: false }, 317); tick(); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); TreeGridFunctions.clickRowSelectionCheckbox(fix, 6); fix.detectChanges(); TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, 6, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // undo transaction treeGrid.transactions.undo(); tick(); fix.detectChanges(); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); expect(treeGrid.selectedRows.includes(13)).toEqual(false); })); it('Should be able to select deleted rows through API - Hierarchical DS', () => { treeGrid.deleteRowById(663); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([]); treeGrid.selectRows([663]); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([663]); /** Select row with deleted parent */ treeGrid.deleteRowById(147); fix.detectChanges(); // 147 -> 475 treeGrid.selectRows([475]); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([663, 475]); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it('Should not be able to select deleted rows through API with selectAllRows - Hierarchical DS', () => { treeGrid.deleteRowById(663); treeGrid.deleteRowById(147); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([]); treeGrid.selectAllRows(); fix.detectChanges(); expect(treeGrid.selectedRows.includes(663)).toBe(false); expect(treeGrid.selectedRows.includes(147)).toBe(false); expect(treeGrid.selectedRows.includes(475)).toBe(false); expect(treeGrid.selectedRows.includes(19)).toBe(true); expect(treeGrid.selectedRows.includes(847)).toBe(true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); }); }); describe('Row Selection with transactions - flat DS', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridRowEditingTransactionComponent); treeGrid = fix.componentInstance.treeGrid; treeGrid.rowSelection = GridSelectionMode.multiple; fix.detectChanges(); }); it('Should select deleted rows through API', () => { treeGrid.deleteRowById(6); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([]); treeGrid.selectRows([6]); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([6]); /** Select row with deleted parent */ treeGrid.deleteRowById(10); fix.detectChanges(); // 10 -> 9 treeGrid.selectRows([9]); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([6, 9]); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it('Should not be able to select deleted rows through API with selectAllRows', () => { treeGrid.deleteRowById(6); treeGrid.deleteRowById(10); fix.detectChanges(); expect(treeGrid.selectedRows).toEqual([]); treeGrid.selectAllRows(); fix.detectChanges(); expect(treeGrid.selectedRows.includes(6)).toBe(false); expect(treeGrid.selectedRows.includes(10)).toBe(false); expect(treeGrid.selectedRows.includes(9)).toBe(false); expect(treeGrid.selectedRows.includes(1)).toBe(true); expect(treeGrid.selectedRows.includes(2)).toBe(true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, true); }); }); describe('Cell Selection', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridCellSelectionComponent); fix.detectChanges(); treeGrid = fix.componentInstance.treeGrid; }); it('should return the correct type of cell when clicking on a cells', () => { const rows = TreeGridFunctions.getAllRows(fix); const normalCells = TreeGridFunctions.getNormalCells(rows[0]); UIInteractions.simulateClickAndSelectEvent(normalCells[0]); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); let treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); // perform 2 clicks and check selection again treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); }); it('should return the correct type of cell when clicking on child cells', () => { const rows = TreeGridFunctions.getAllRows(fix); // level 1 let treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(147); // level 2 treeGridCell = TreeGridFunctions.getTreeCell(rows[1]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(475); // level 3 treeGridCell = TreeGridFunctions.getTreeCell(rows[2]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(957); }); it('should not persist selection after paging', () => { let rows = TreeGridFunctions.getAllRows(fix); let treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(TreeGridFunctions.verifyGridCellHasSelectedClass(treeGridCell)).toBe(true); // Clicking on the pager buttons triggers a blur event. GridFunctions.navigateToNextPage(treeGrid.nativeElement); treeGridCell.nativeElement.dispatchEvent(new Event('blur')); fix.detectChanges(); GridFunctions.navigateToFirstPage(treeGrid.nativeElement); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(0); rows = TreeGridFunctions.getAllRows(fix); treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(TreeGridFunctions.verifyGridCellHasSelectedClass(treeGridCell)).toBe(true); GridFunctions.navigateToLastPage(treeGrid.nativeElement); treeGridCell.nativeElement.dispatchEvent(new Event('blur')); fix.detectChanges(); GridFunctions.navigateToFirstPage(treeGrid.nativeElement); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(0); }); it('should persist selection after filtering', fakeAsync(() => { const rows = TreeGridFunctions.getAllRows(fix); const treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); treeGrid.filter('ID', '14', IgxStringFilteringOperand.instance().condition('startsWith'), true); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(TreeGridFunctions.verifyGridCellHasSelectedClass(treeGridCell)).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(147); // set new filtering treeGrid.clearFilter('ProductName'); treeGrid.filter('ID', '8', IgxStringFilteringOperand.instance().condition('startsWith'), true); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(TreeGridFunctions.verifyGridCellHasSelectedClass(treeGridCell)).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(847); })); it('should persist selection after scrolling', async () => { const rows = TreeGridFunctions.getAllRows(fix); const treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); // scroll down 150 pixels treeGrid.verticalScrollContainer.getScroll().scrollTop = 150; treeGrid.headerContainer.getScroll().dispatchEvent(new Event('scroll')); await wait(100); fix.detectChanges(); // then scroll back to top treeGrid.verticalScrollContainer.getScroll().scrollTop = 0; treeGrid.headerContainer.getScroll().dispatchEvent(new Event('scroll')); await wait(100); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(147); }); it('should persist selection after sorting', () => { const rows = TreeGridFunctions.getAllRows(fix); const treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(147); treeGrid.sort({ fieldName: 'ID', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(847); }); it('should persist selection after row delete', () => { const rows = TreeGridFunctions.getAllRows(fix); const treeGridCell = TreeGridFunctions.getTreeCell(rows[0]); UIInteractions.simulateClickAndSelectEvent(treeGridCell); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(147); treeGrid.deleteRow(847); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(147); treeGrid.deleteRow(147); fix.detectChanges(); expect(treeGrid.selectedCells.length).toBe(1); expect(treeGrid.selectedCells[0] instanceof IgxGridCell).toBe(true); expect(treeGrid.selectedCells[0].value).toBe(19); }); }); describe('Cell/Row Selection With Row Editing', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridSelectionRowEditingComponent); treeGrid = fix.componentInstance.treeGrid; fix.detectChanges(); }); it('should display the banner correctly on row selection', fakeAsync(() => { const targetCell = treeGrid.getCellByColumn(1, 'Name'); treeGrid.rowSelection = GridSelectionMode.multiple; treeGrid.rowEditable = true; // select the second row treeGrid.selectRows([targetCell.id.rowID], true); tick(16); fix.detectChanges(); // check if any rows were selected expect(treeGrid.selectedRows.length).toBeGreaterThan(0); // enter edit mode targetCell.editMode = true; tick(16); fix.detectChanges(); // the banner should appear const banner = document.getElementsByClassName(ROW_EDITING_BANNER_OVERLAY_CLASS); expect(banner).toBeTruthy(); expect(banner[0]).toBeTruthy(); })); it('should display the banner correctly on cell selection', fakeAsync(() => { treeGrid.rowEditable = true; const allRows = TreeGridFunctions.getAllRows(fix); const treeGridCells = TreeGridFunctions.getNormalCells(allRows[0]); // select a cell const targetCell = treeGridCells[0]; UIInteractions.simulateClickAndSelectEvent(targetCell); fix.detectChanges(); // there should be at least one selected cell expect(treeGrid.selectedCells.length).toBeGreaterThan(0); // enter edit mode targetCell.triggerEventHandler('dblclick', new Event('dblclick')); tick(16); fix.detectChanges(); // the banner should appear const banner = document.getElementsByClassName(ROW_EDITING_BANNER_OVERLAY_CLASS); expect(banner).toBeTruthy(); expect(banner[0]).toBeTruthy(); })); }); describe('Cascading Row Selection - Child collection data', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridCascadingSelectionComponent); fix.detectChanges(); treeGrid = fix.componentInstance.treeGrid; actionStrip = fix.componentInstance.actionStrip; }); it('Should select/deselect all leaf nodes and set the correct state to their checkboxes on parent rows checkbox click', () => { TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(7); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // Deselect rows TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it('Should be able to select/deselect row when primaryKey is not set', () => { treeGrid.primaryKey = undefined; fix.detectChanges(); expect(treeGrid.primaryKey).not.toBeDefined(); TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(7); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // Deselect rows TreeGridFunctions.clickRowSelectionCheckbox(fix, 0); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); treeGrid.selectRows([treeGrid.getRowByIndex(1).data, treeGrid.getRowByIndex(2).data, treeGrid.getRowByIndex(3).data], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(7); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('Should select/deselect parent row by selecting/deselecting all its children', () => { treeGrid.selectRows([475, 957, 711, 998, 299], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(7); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // Deselect rows treeGrid.deselectRows([475, 957, 711, 998, 299]); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it('Should select/deselect parent row by selecting/deselecting the last deselected/selected child', () => { treeGrid.selectRows([475, 957, 711, 998], true); fix.detectChanges(); TreeGridFunctions.clickRowSelectionCheckbox(fix, 6); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(7); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // Deselect rows treeGrid.deselectRows([475, 957, 711, 998]); fix.detectChanges(); TreeGridFunctions.clickRowSelectionCheckbox(fix, 6); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it(`Should set parent row checkbox to indeterminate by selecting/deselecting a child row when all child rows are deselected/selected`, () => { TreeGridFunctions.clickRowSelectionCheckbox(fix, 6); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // Deselect one row treeGrid.selectRows([475, 957, 711, 998, 299], true); fix.detectChanges(); TreeGridFunctions.clickRowSelectionCheckbox(fix, 6); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('Should select all children of record on Shift + click even if they are not in the selected range. ', () => { const firstRow = treeGrid.gridAPI.get_row_by_index(1); const secondRow = treeGrid.gridAPI.get_row_by_index(4); const mockEvent = new MouseEvent('click', { shiftKey: true }); UIInteractions.simulateClickEvent(firstRow.nativeElement); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toEqual(1); TreeGridFunctions.verifyDataRowsSelection(fix, [1], true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // Click on other row holding Shift key secondRow.nativeElement.dispatchEvent(mockEvent); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(7); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('Should select only the newly clicked parent row and its children and deselect the previous selection.', () => { treeGrid.selectRows([19, 847], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); const firstRow = treeGrid.gridAPI.get_row_by_index(0); UIInteractions.simulateClickEvent(firstRow.nativeElement); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(7); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('Should add a row and its children to the selected rows collection using Ctrl + click.', () => { treeGrid.selectRows([847], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); // select a child of the first parent and all of its children const firstRow = treeGrid.gridAPI.get_row_by_index(3); UIInteractions.simulateClickEvent(firstRow.nativeElement, false, true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(6); TreeGridFunctions.verifyDataRowsSelection(fix, [3, 4, 5, 6, 8, 9], true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); // select the first parent and all of its children const secondRow = treeGrid.gridAPI.get_row_by_index(0); UIInteractions.simulateClickEvent(secondRow.nativeElement, false, true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(9); TreeGridFunctions.verifyDataRowsSelection(fix, [0, 1, 2, 3, 4, 5, 6, 8, 9], true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('Should deselect a selected row and its children using Ctrl + click.', () => { treeGrid.selectRows([847], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); // select a child of the first parent and all of its children const firstRow = treeGrid.gridAPI.get_row_by_index(3); UIInteractions.simulateClickEvent(firstRow.nativeElement, false, true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(6); const firstChildRow = treeGrid.gridAPI.get_row_by_index(4); UIInteractions.simulateClickEvent(firstChildRow.nativeElement, false, true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); const secondRow = treeGrid.gridAPI.get_row_by_index(8); UIInteractions.simulateClickEvent(secondRow.nativeElement, false, true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); }); it('After adding a new child row to a selected parent its checkbox state SHOULD be indeterminate.', async () => { treeGrid.selectRows([847], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 8, true, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); const row = treeGrid.gridAPI.get_row_by_index(8); actionStrip.show(row); fix.detectChanges(); // add new child through the UI const editActions = fix.debugElement.queryAll(By.css(`igx-grid-action-button`)); const addChildBtn = editActions[2].componentInstance; addChildBtn.actionClick.emit(); fix.detectChanges(); endTransition(); const addRow = treeGrid.gridAPI.get_row_by_index(9); expect(addRow.addRowUI).toBeTrue(); treeGrid.gridAPI.crudService.endEdit(true); await wait(100); fix.detectChanges(); const addedRow = treeGrid.gridAPI.get_row_by_index(10); expect(addedRow.data.Name).toBe(undefined); TreeGridFunctions.verifyDataRowsSelection(fix, [9], true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 8, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('After adding child to a selected parent with no children, parent checkbox state SHOULD NOT be selected.', async () => { treeGrid.selectRows([957], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.addRow({ ID: -1, Name: undefined, HireDate: undefined, Age: undefined }, 957); fix.detectChanges(); await wait(100); fix.detectChanges(); const addedRow = treeGrid.gridAPI.get_row_by_index(3); expect(addedRow.data.Name).toBe(undefined); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 2, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it('If parent has one non-selected child and we delete it, the parent checkbox state SHOULD be selected.', async () => { treeGrid.selectRows([711, 299], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); expect(treeGrid.dataRowList.length).toBe(10); const childRow = treeGrid.gridAPI.get_row_by_index(5); actionStrip.show(childRow); fix.detectChanges(); // delete the child through the UI const editActions = fix.debugElement.queryAll(By.css(`igx-grid-action-button`)); const deleteBtn = editActions[2].componentInstance; deleteBtn.actionClick.emit(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(treeGrid.dataRowList.length).toBe(9); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('If we delete the only selected child of a parent row, the parent checkbox state SHOULD be deselected', async () => { treeGrid.selectRows([711], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); expect(treeGrid.dataRowList.length).toBe(10); // delete the child through the API const childRow = treeGrid.gridAPI.get_row_by_index(4); childRow.delete(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(treeGrid.dataRowList.length).toBe(9); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it(`If there is only one selected leaf row for a particular parent and we filter it out parent's checkbox state -> non-selected. All non-direct parents’ checkbox states should be set correctly as well`, async () => { treeGrid.selectRows([711], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); treeGrid.filter('ID', 711, IgxNumberFilteringOperand.instance().condition('doesNotEqual')); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); }); it(`If there is only one non-selected row for a particular parent and we filter it out parent's checkbox state -> selected. All non-direct parents’ checkbox states should be set correctly as well`, async () => { treeGrid.selectRows([711, 998], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 6, false, false); treeGrid.filter('ID', 299, IgxNumberFilteringOperand.instance().condition('doesNotEqual')); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true); }); it(`No rows are selected. Filter out all children for certain parent. Select this parent. It should be the only one within the selectedRows collection. Remove filtering. The selectedRows collection should be empty. All non-direct parents’ checkbox states should be set correctly as well`, async () => { const expressionTree = new FilteringExpressionsTree(FilteringLogic.And, 'ID'); expressionTree.filteringOperands = [ { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 711 }, { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 998 }, { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 299 } ]; treeGrid.filter('ID', null, expressionTree); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); treeGrid.selectRows([317], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); treeGrid.clearFilter(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); }); it(`Filter out all selected children for a certain parent and explicitly deselect it. Remove filtering. Parent row should be selected again. All non-direct parents’ checkbox states should be set correctly as well`, async () => { treeGrid.selectRows([317], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); const expressionTree = new FilteringExpressionsTree(FilteringLogic.And, 'ID'); expressionTree.filteringOperands = [ { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 711 }, { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 998 }, { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 299 } ]; treeGrid.filter('ID', null, expressionTree); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); treeGrid.deselectRows([317]); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); treeGrid.clearFilter(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); }); it(`Parent in indeterminate state. Filter out its children -> parent not selected. Select parent and add new child. Parent -> not selected. Revert filtering so that previous records are back in the view and parent should become in indeterminate state because one of it children is selected`, fakeAsync(() => { treeGrid.selectRows([998], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); const expressionTree = new FilteringExpressionsTree(FilteringLogic.And, 'ID'); expressionTree.filteringOperands = [ { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 711 }, { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 998 }, { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 299 } ]; treeGrid.filter('ID', null, expressionTree); fix.detectChanges(); tick(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); treeGrid.selectRows([317]); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); treeGrid.addRow({ ID: -1, Name: undefined, HireDate: undefined, Age: undefined }, 317); fix.detectChanges(); tick(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); treeGrid.clearFilter(); fix.detectChanges(); tick(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); })); it(`Selected parent. Filter out some of the children and delete otheres. Parent should be not selected`, fakeAsync(() => { treeGrid.selectRows([317], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); const expressionTree = new FilteringExpressionsTree(FilteringLogic.And, 'ID'); expressionTree.filteringOperands = [ { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 711 }, { condition: IgxNumberFilteringOperand.instance().condition('doesNotEqual'), fieldName: 'ID', searchVal: 998 } ]; treeGrid.filter('ID', null, expressionTree); fix.detectChanges(); tick(100); fix.detectChanges(); treeGrid.deleteRow(299); fix.detectChanges(); tick(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); })); it(`Set nested child row, that has its own children, as initially selected and verify that both direct and indirect parent's checkboxes are set in the correct state.`, fakeAsync(() => { treeGrid.selectedRows = [317]; fix.detectChanges(); tick(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 6, true, true); })); it(`Setting true to the cancel property of the rowSelectionChanging event should not modify the selected rows collection`, () => { treeGrid.rowSelectionChanging.subscribe((e: IRowSelectionEventArgs) => { e.cancel = true; }); spyOn(treeGrid.rowSelectionChanging, 'emit').and.callThrough(); treeGrid.selectionService.selectRowsWithNoEvent([317]); fix.detectChanges(); treeGrid.selectionService.deselectRow(299); fix.detectChanges(); const args: IRowSelectionEventArgs = { oldSelection: [ treeGrid.getRowData(317), treeGrid.getRowData(711), treeGrid.getRowData(998), treeGrid.getRowData(299)], newSelection: [treeGrid.getRowData(711), treeGrid.getRowData(998)], added: [], removed: [treeGrid.getRowData(317), treeGrid.getRowData(299)], event: undefined, cancel: true, owner: treeGrid }; expect(treeGrid.rowSelectionChanging.emit).toHaveBeenCalledWith(args); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 6, true, true); }); it(`selectionService clearRowSelection method should work correctly`, () => { treeGrid.selectionService.selectRowsWithNoEvent([711]); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); expect(treeGrid.selectionService.indeterminateRows.size).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 1, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 2, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); treeGrid.selectionService.clearRowSelection(); treeGrid.cdr.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); expect(treeGrid.selectionService.indeterminateRows.size).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 1, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 2, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, false, false); }); it(`selectionService selectAllRows method should work correctly`, () => { treeGrid.selectionService.selectRowsWithNoEvent([711]); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); expect(treeGrid.selectionService.indeterminateRows.size).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 1, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 2, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); treeGrid.selectionService.selectAllRows(); treeGrid.cdr.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(10); expect(treeGrid.selectionService.indeterminateRows.size).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 1, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 2, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); }); it('selectRowById event SHOULD be emitted correctly with valid arguments.', () => { spyOn(treeGrid.rowSelectionChanging, 'emit').and.callThrough(); treeGrid.selectionService.selectRowsWithNoEvent([317]); fix.detectChanges(); expect(treeGrid.rowSelectionChanging.emit).toHaveBeenCalledTimes(0); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 6, true, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.selectionService.selectRowById(847, true); const args: IRowSelectionEventArgs = { oldSelection: [ treeGrid.getRowData(317), treeGrid.getRowData(711), treeGrid.getRowData(998), treeGrid.getRowData(299)], newSelection: [treeGrid.getRowData(847), treeGrid.getRowData(663)], added: [treeGrid.getRowData(847), treeGrid.getRowData(663)], removed: [ treeGrid.getRowData(317), treeGrid.getRowData(711), treeGrid.getRowData(998), treeGrid.getRowData(299)], event: undefined, cancel: false, owner: treeGrid }; expect(treeGrid.rowSelectionChanging.emit).toHaveBeenCalledWith(args); treeGrid.cdr.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 6, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 8, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 9, true, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('After changing the newSelection arguments of onSelectedRowChange, the arguments SHOULD be correct.', () => { treeGrid.rowSelectionChanging.subscribe((e: IRowSelectionEventArgs) => { e.newSelection = [treeGrid.getRowData(847), treeGrid.getRowData(663)]; }); spyOn(treeGrid.rowSelectionChanging, 'emit').and.callThrough(); treeGrid.selectionService.selectRowsWithNoEvent([317], true); fix.detectChanges(); treeGrid.selectionService.selectRowById(19, true); const selectionArgs: IRowSelectionEventArgs = { oldSelection: [ treeGrid.getRowData(317), treeGrid.getRowData(711), treeGrid.getRowData(998), treeGrid.getRowData(299)], newSelection: [treeGrid.getRowData(847), treeGrid.getRowData(663)], added: [treeGrid.getRowData(19)], removed: [treeGrid.getRowData(317), treeGrid.getRowData(711), treeGrid.getRowData(998), treeGrid.getRowData(299)], event: undefined, cancel: false, owner: treeGrid }; expect(treeGrid.rowSelectionChanging.emit).toHaveBeenCalledWith(selectionArgs); treeGrid.cdr.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 8, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 9, true, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); }); describe('Cascading Row Selection - Primary/Foreign key data', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridPrimaryForeignKeyCascadeSelectionComponent); fix.detectChanges(); treeGrid = fix.componentInstance.treeGrid; actionStrip = fix.componentInstance.actionStrip; }); it(`Filter out all children for a certain parent, except for one. Select it. Parent should also become selected. Clear filters. Parent should become in indeterminate state as there are non-selected children.`, async () => { treeGrid.filter('ID', 475, IgxNumberFilteringOperand.instance().condition('equals')); await wait(100); fix.detectChanges(); treeGrid.selectRows([475], true); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 1, true, true); treeGrid.clearFilter(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 1, true, true); }); it(`If there is only one selected leaf row for a particular parent and we filter it out parent's checkbox state -> non-selected. All non-direct parents’ checkbox states should be set correctly as well`, async () => { treeGrid.selectRows([711], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); treeGrid.filter('ID', 711, IgxNumberFilteringOperand.instance().condition('doesNotEqual')); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); }); it(`If there is only one non-selected row for a particular parent and we filter it out parent's checkbox state -> selected. All non-direct parents’ checkbox states should be set correctly as well`, async () => { treeGrid.selectRows([711, 998], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 6, false, false); treeGrid.filter('ID', 299, IgxNumberFilteringOperand.instance().condition('doesNotEqual')); fix.detectChanges(); await wait(200); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true); }); it('After adding a new child row to a selected parent its checkbox state SHOULD be indeterminate.', async () => { treeGrid.selectRows([847], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 8, true, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); const row = treeGrid.gridAPI.get_row_by_index(8); actionStrip.show(row); fix.detectChanges(); // add new child through the UI const editActions = fix.debugElement.queryAll(By.css(`igx-grid-action-button`)); const addChildBtn = editActions[2].componentInstance; addChildBtn.actionClick.emit(); fix.detectChanges(); endTransition(); const addRow = treeGrid.gridAPI.get_row_by_index(9); expect(addRow.addRowUI).toBeTrue(); treeGrid.gridAPI.crudService.endEdit(true); await wait(100); fix.detectChanges(); const addedRow = treeGrid.gridAPI.get_row_by_index(10); expect(addedRow.data.Name).toBe(undefined); TreeGridFunctions.verifyDataRowsSelection(fix, [9], true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 8, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('If parent and its children are selected and we delete a child, parent SHOULD be still selected.', async () => { treeGrid.selectRows([147], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(7); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, true, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); expect(treeGrid.dataRowList.length).toBe(10); const childRow = treeGrid.gridAPI.get_row_by_index(5); actionStrip.show(childRow); fix.detectChanges(); // delete the child through the UI const editActions = fix.debugElement.queryAll(By.css(`igx-grid-action-button`)); const deleteBtn = editActions[2].componentInstance; deleteBtn.actionClick.emit(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(treeGrid.dataRowList.length).toBe(9); expect(getVisibleSelectedRows(fix).length).toBe(6); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, true, true); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('If we delete the only selected child of a parent row, the parent checkbox state SHOULD be deselected', async () => { treeGrid.selectRows([711], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); expect(treeGrid.dataRowList.length).toBe(10); // delete the child through the API const childRow = treeGrid.gridAPI.get_row_by_index(4); childRow.delete(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(treeGrid.dataRowList.length).toBe(9); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); it(`Set nested child row, that has its own children, as initially selected and verify that both direct and indirect parent's checkboxes are set in the correct state.`, fakeAsync(() => { treeGrid.selectedRows = [317]; fix.detectChanges(); tick(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 6, true, true); })); }); describe('Cascading Row Selection with Transaction', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridCascadingSelectionTransactionComponent); fix.detectChanges(); treeGrid = fix.componentInstance.treeGrid; actionStrip = fix.componentInstance.actionStrip; }); it('Add a new leaf row to a selected parent and revert the transaction. The parent SHOULD be selected.', async () => { const trans = treeGrid.transactions; treeGrid.selectRows([317], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.addRow({ ID: -1, Name: undefined, HireDate: undefined, Age: undefined }, 317); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); trans.undo(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('Add a new row to a selected parent and commit the transaction.The parent checkbox state SHOULD be indeterminate', async () => { const trans = treeGrid.transactions; treeGrid.selectRows([317], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); treeGrid.addRow({ ID: -1, Name: undefined, HireDate: undefined, Age: undefined }, 317); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); trans.commit(treeGrid.data); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('Delete one of the children of selected parent. Parent checkbox state SHOULD be selected.', async () => { const trans = treeGrid.transactions; treeGrid.selectRows([317], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(4); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); const childRow = treeGrid.gridAPI.get_row_by_index(4); childRow.delete(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); trans.undo(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); trans.redo(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('After delete the only non-selected child, the parent checkbox state SHOULD be selected.', async () => { treeGrid.selectRows([711, 299], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(2); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); const childRow = treeGrid.gridAPI.get_row_by_index(5); actionStrip.show(childRow); fix.detectChanges(); // delete the child through the UI const editActions = fix.debugElement.queryAll(By.css(`igx-grid-action-button`)); const deleteBtn = editActions[2].componentInstance; deleteBtn.actionClick.emit(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(3); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); }); it('Delete the only selected child of a parent row. Parent checkbox state SHOULD NOT be selected.', async () => { treeGrid.selectRows([998], true); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(1); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null); const row = treeGrid.gridAPI.get_row_by_index(5); row.delete(); fix.detectChanges(); await wait(100); fix.detectChanges(); expect(getVisibleSelectedRows(fix).length).toBe(0); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false); TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false); TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false); }); }); describe('Custom row selectors', () => { beforeEach(() => { fix = TestBed.createComponent(IgxTreeGridCustomRowSelectorsComponent); fix.detectChanges(); treeGrid = fix.componentInstance.treeGrid; }); it('Should have the correct properties in the custom row selector template', () => { const firstRow = treeGrid.gridAPI.get_row_by_index(0); const firstCheckbox = firstRow.nativeElement.querySelector('.igx-checkbox__composite'); const context = { index: 0, rowID: 1, key: 1, selected: false }; const contextUnselect = { index: 0, rowID: 1, key: 1, selected: true }; spyOn(fix.componentInstance, 'onRowCheckboxClick').and.callThrough(); (firstCheckbox as HTMLElement).click(); fix.detectChanges(); expect(fix.componentInstance.onRowCheckboxClick).toHaveBeenCalledTimes(1); expect(fix.componentInstance.onRowCheckboxClick).toHaveBeenCalledWith(fix.componentInstance.rowCheckboxClick, context); // Verify correct properties when unselecting a row (firstCheckbox as HTMLElement).click(); fix.detectChanges(); expect(fix.componentInstance.onRowCheckboxClick).toHaveBeenCalledTimes(2); expect(fix.componentInstance.onRowCheckboxClick).toHaveBeenCalledWith(fix.componentInstance.rowCheckboxClick, contextUnselect); }); it('Should have the correct properties in the custom row selector header template', () => { const context = { selectedCount: 0, totalCount: 8 }; const contextUnselect = { selectedCount: 8, totalCount: 8 }; const headerCheckbox = treeGrid.theadRow.nativeElement.querySelector('.igx-checkbox__composite') as HTMLElement; spyOn(fix.componentInstance, 'onHeaderCheckboxClick').and.callThrough(); headerCheckbox.click(); fix.detectChanges(); expect(fix.componentInstance.onHeaderCheckboxClick).toHaveBeenCalledTimes(1); expect(fix.componentInstance.onHeaderCheckboxClick).toHaveBeenCalledWith(fix.componentInstance.headerCheckboxClick, context); headerCheckbox.click(); fix.detectChanges(); expect(fix.componentInstance.onHeaderCheckboxClick).toHaveBeenCalledTimes(2); expect(fix.componentInstance.onHeaderCheckboxClick). toHaveBeenCalledWith(fix.componentInstance.headerCheckboxClick, contextUnselect); }); it('Should have correct indices on all pages', () => { treeGrid.paginator.nextPage(); fix.detectChanges(); const firstRootRow = treeGrid.gridAPI.get_row_by_index(0); expect(firstRootRow.nativeElement.querySelector('.rowNumber').textContent).toEqual('5'); }); }); }); const getVisibleSelectedRows = (fix) => TreeGridFunctions.getAllRows(fix).filter( (row) => row.nativeElement.classList.contains(TREE_ROW_SELECTION_CSS_CLASS));