UNPKG

igniteui-angular-sovn

Version:

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

1,152 lines (973 loc) 170 kB
import { Component, ViewChild, TemplateRef, QueryList } from '@angular/core'; import { formatNumber } from '@angular/common' import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; import { IgxColumnComponent } from '../columns/column.component'; import { IgxGridComponent } from './grid.component'; import { IgxGroupAreaDropDirective, IgxGroupByRowTemplateDirective, IgxHeaderCollapsedIndicatorDirective, IgxHeaderExpandedIndicatorDirective, IgxRowCollapsedIndicatorDirective, IgxRowExpandedIndicatorDirective } from './grid.directives'; import { IgxColumnMovingDragDirective } from '../moving/moving.drag.directive'; import { IgxGridRowComponent } from './grid-row.component'; import { IgxChipComponent } from '../../chips/chip.component'; import { wait, UIInteractions } from '../../test-utils/ui-interactions.spec'; import { DefaultSortingStrategy, ISortingExpression, SortingDirection } from '../../data-operations/sorting-strategy'; import { configureTestSuite } from '../../test-utils/configure-suite'; import { DataParent, SampleTestData } from '../../test-utils/sample-test-data.spec'; import { MultiColumnHeadersWithGroupingComponent } from '../../test-utils/grid-samples.spec'; import { GridSelectionFunctions, GridFunctions, GRID_SCROLL_CLASS } from '../../test-utils/grid-functions.spec'; import { GridSelectionMode } from '../common/enums'; import { ControlsFunction } from '../../test-utils/controls-functions.spec'; import { IGroupingExpression } from '../../data-operations/grouping-expression.interface'; import { IgxPaginatorComponent } from '../../paginator/paginator.component'; import { NgFor, NgIf } from '@angular/common'; import { IgxCheckboxComponent } from '../../checkbox/checkbox.component'; import { IgxGroupByRowSelectorDirective } from '../selection/row-selectors'; import { IgxGrouping } from '../public_api'; describe('IgxGrid - GroupBy #grid', () => { const COLUMN_HEADER_CLASS = '.igx-grid-th'; const COLUMN_HEADER_GROUP_CLASS = '.igx-grid-thead__item'; const GRID_RESIZE_CLASS = '.igx-grid-th__resize-line'; const SORTING_ICON_ASC_CONTENT = 'arrow_upward'; const DISABLED_CHIP = 'igx-chip--disabled'; const CHIP = 'igx-chip'; configureTestSuite((() => { return TestBed.configureTestingModule({ imports: [ NoopAnimationsModule, DefaultGridComponent, GroupableGridComponent, CustomTemplateGridComponent, GroupByDataMoreColumnsComponent, GroupByEmptyColumnFieldComponent, GridGroupByRowCustomSelectorsComponent, GridGroupByCaseSensitiveComponent, GridGroupByTestDateTimeDataComponent, MultiColumnHeadersWithGroupingComponent ] }); })); const checkGroups = (groupRows, expectedGroupOrder, grExpr?) => { // verify group rows are sorted correctly, their indexes in the grid are correct and their group records match the group value. let count = 0; const maxLevel = grExpr ? grExpr.length - 1 : 0; for (const groupRow of groupRows) { const recs = groupRow.groupRow.records; const val = groupRow.groupRow.value; const index = groupRow.index; const field = groupRow.groupRow.expression.fieldName; const level = groupRow.groupRow.level; expect(level).toEqual(grExpr ? grExpr.indexOf(groupRow.groupRow.expression) : 0); expect(index).toEqual(count); count++; expect(val).toEqual(expectedGroupOrder[groupRows.indexOf(groupRow)]); for (const rec of recs) { if (level === maxLevel) { count++; } if (groupRow.groupRow.expression.ignoreCase) { expect(rec[field]?.toString().toLowerCase()).toEqual(val?.toString().toLowerCase()); } else { expect(rec[field]).toEqual(val); } } } }; const checkChips = (chips: QueryList<IgxChipComponent>, grouping: IGroupingExpression[]) => { chips.forEach((chip, index) => { const content = chip.nativeElement.querySelector('.igx-chip__content').textContent.trim(); const icon = chip.nativeElement.querySelector('[igxsuffix]').textContent.trim(); expect(content).toBe(grouping[index].fieldName); if (icon === SORTING_ICON_ASC_CONTENT) { expect(grouping[index].dir).toBe(SortingDirection.Asc); } else { expect(grouping[index].dir).toBe(SortingDirection.Desc); } }); }; it('should allow grouping by different data types.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); fix.detectChanges(); // group by string column const grid = fix.componentInstance.instance; grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); // verify grouping expressions const grExprs = grid.groupingExpressions; expect(grExprs.length).toEqual(1); expect(grExprs[0].fieldName).toEqual('ProductName'); // verify rows let groupRows = grid.groupsRowList.toArray(); let dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(5); expect(dataRows.length).toEqual(8); checkGroups(groupRows, ['NetAdvantage', 'Ignite UI for JavaScript', 'Ignite UI for Angular', '', null]); // ungroup grid.clearGrouping('ProductName'); tick(); fix.detectChanges(); // verify no groups are present expect(grid.groupsRowList.toArray().length).toEqual(0); // group by number grid.groupBy({ fieldName: 'Downloads', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(6); expect(dataRows.length).toEqual(8); checkGroups(groupRows, [1000, 254, 100, 20, 0, null]); // ungroup and group by boolean column grid.clearGrouping('Downloads'); tick(); fix.detectChanges(); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(3); expect(dataRows.length).toEqual(8); checkGroups(groupRows, [true, false, null]); // ungroup and group by date column grid.clearGrouping('Released'); tick(); fix.detectChanges(); grid.groupBy({ fieldName: 'ReleaseDate', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(4); expect(dataRows.length).toEqual(8); const expectedValue1 = groupRows[1].nativeElement.nextElementSibling.querySelectorAll('igx-grid-cell')[3].textContent; const actualValue1 = groupRows[1].element.nativeElement.querySelector('.igx-group-label__text').textContent; const expectedValue2 = groupRows[2].nativeElement.nextElementSibling.querySelectorAll('igx-grid-cell')[3].textContent; const actualValue2 = groupRows[2].element.nativeElement.querySelector('.igx-group-label__text').textContent; const expectedValue3 = groupRows[3].nativeElement.nextElementSibling.querySelectorAll('igx-grid-cell')[3].textContent; const actualValue3 = groupRows[3].element.nativeElement.querySelector('.igx-group-label__text').textContent; expect(actualValue1).toEqual(expectedValue1); expect(actualValue2).toEqual(expectedValue2); expect(actualValue3).toEqual(expectedValue3); checkGroups( groupRows, [null, fix.componentInstance.prevDay, fix.componentInstance.today, fix.componentInstance.nextDay]); })); it('should only account for year, month and day when grouping by \'date\' dataType column', fakeAsync(() => { const fix = TestBed.createComponent(GridGroupByTestDateTimeDataComponent); fix.detectChanges(); const grid = fix.componentInstance.grid; fix.detectChanges(); grid.groupBy({ fieldName: 'DateField', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); expect(groupRows.length).toEqual(3); const targetTestVal = new Date(2012, 1, 12); const index = groupRows.findIndex(gr => new Date(gr.groupRow.value).getTime() === targetTestVal.getTime()); expect(groupRows[index].groupRow.records.length).toEqual(2); // compare the date values in the target group which are two identical dates with different time values const field = groupRows[index].groupRow.expression.fieldName; const record1 = groupRows[index].groupRow.records[0]; const record2 = groupRows[index].groupRow.records[1]; const rec1Date = new Date(record1[field]); const rec2Date = new Date(record2[field]); // the time portions of the two records differ, so the Dates are not equal even though they are in the same group expect(rec1Date.getTime()).not.toEqual(rec2Date.getTime()); // the date portions are the same, so they are in the same group, as the column type is `date` expect(rec1Date.getDate()).toEqual(rec2Date.getDate()); expect(rec1Date.getMonth()).toEqual(rec2Date.getMonth()); expect(rec1Date.getFullYear()).toEqual(rec2Date.getFullYear()); })); it('should only account for hours, minutes, seconds and ms when grouping by \'time\' dataType column', fakeAsync(() => { const fix = TestBed.createComponent(GridGroupByTestDateTimeDataComponent); fix.detectChanges(); const grid = fix.componentInstance.grid; grid.groupBy({ fieldName: 'TimeField', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); expect(groupRows.length).toEqual(3); const targetTestVal = new Date(new Date().setHours(3, 20, 0, 1)); const index = groupRows.findIndex(gr => new Date(gr.groupRow.value).getHours() === targetTestVal.getHours() && new Date(gr.groupRow.value).getMinutes() === targetTestVal.getMinutes() && new Date(gr.groupRow.value).getSeconds() === targetTestVal.getSeconds() && new Date(gr.groupRow.value).getMilliseconds() === targetTestVal.getMilliseconds()); expect(groupRows[index].groupRow.records.length).toEqual(3); // compare the date values in the target group which are three different dates with same time values const field = groupRows[index].groupRow.expression.fieldName; const record1 = groupRows[index].groupRow.records[0]; const record2 = groupRows[index].groupRow.records[1]; const record3 = groupRows[index].groupRow.records[2]; const rec1Date = new Date(record1[field]); const rec2Date = new Date(record2[field]); const rec3Date = new Date(record3[field]); // the date portions of the following records differ, so the Dates are not equal even though they are in the same group expect(rec1Date.getTime()).not.toEqual(rec2Date.getTime()); // the below are equal by date as well expect(rec2Date.getTime()).toEqual(rec3Date.getTime()); // the time portions of the not equal dates are the same, so they are in the same group, as the column type is `time` expect(rec1Date.getHours()).toEqual(rec2Date.getHours()); expect(rec1Date.getMinutes()).toEqual(rec2Date.getMinutes()); expect(rec1Date.getSeconds()).toEqual(rec2Date.getSeconds()); expect(rec1Date.getMilliseconds()).toEqual(rec2Date.getMilliseconds()); })); it('should account for all date values when grouping by \'dateTime\' dataType column', fakeAsync(() => { const fix = TestBed.createComponent(GridGroupByTestDateTimeDataComponent); fix.detectChanges(); const grid = fix.componentInstance.grid; grid.groupBy({ fieldName: 'DateTimeField', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); // there are two identical DateTime values, so 4 groups out of 5 data records const groupRows = grid.groupsRowList.toArray(); expect(groupRows.length).toEqual(4); const targetTestVal = new Date(new Date('2003-03-17').setHours(3, 20, 0, 1)); const index = groupRows.findIndex(gr => new Date(gr.groupRow.value).getTime() === targetTestVal.getTime()); expect(groupRows[index].groupRow.records.length).toEqual(2); // compare the date values in the target group which are two identical dates - date and time portions const field = groupRows[index].groupRow.expression.fieldName; const record1 = groupRows[index].groupRow.records[0]; const record2 = groupRows[index].groupRow.records[1]; const rec1Date = new Date(record1[field]); const rec2Date = new Date(record2[field]); expect(rec1Date.getTime()).toEqual(rec2Date.getTime()); })); it('should display time value in the group by row when grouped by a \'time\' column', fakeAsync(() => { const fix = TestBed.createComponent(GridGroupByTestDateTimeDataComponent); fix.detectChanges(); const grid = fix.componentInstance.grid; grid.groupBy({ fieldName: 'TimeField', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); const expectedValue1 = groupRows[0].nativeElement.nextElementSibling.querySelectorAll('igx-grid-cell')[3].textContent; const actualValue1 = groupRows[0].element.nativeElement.querySelector('.igx-group-label__text').textContent; expect(expectedValue1).toEqual(actualValue1); })); it('should display time value in the group by row when grouped by a \'dateTime\' column', fakeAsync(() => { const fix = TestBed.createComponent(GridGroupByTestDateTimeDataComponent); fix.detectChanges(); const grid = fix.componentInstance.grid; grid.groupBy({ fieldName: 'DateTimeField', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); const expectedValue1 = groupRows[0].nativeElement.nextElementSibling.querySelectorAll('igx-grid-cell')[4].textContent; const actualValue1 = groupRows[0].element.nativeElement.querySelector('.igx-group-label__text').textContent; expect(expectedValue1).toEqual(actualValue1); })); it('should allow grouping by multiple columns.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); fix.detectChanges(); fix.componentInstance.height = null; tick(); fix.detectChanges(); // group by 2 columns const grid = fix.componentInstance.instance; grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); let groupRows = grid.groupsRowList.toArray(); let dataRows = grid.dataRowList.toArray(); // verify groups and data rows count expect(groupRows.length).toEqual(13); expect(dataRows.length).toEqual(8); // verify groups checkGroups(groupRows, ['NetAdvantage', true, false, 'Ignite UI for JavaScript', true, false, 'Ignite UI for Angular', false, null, '', true, null, true], grid.groupingExpressions); // group by 3rd column grid.groupBy({ fieldName: 'Downloads', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); // verify groups and data rows count expect(groupRows.length).toEqual(21); expect(dataRows.length).toEqual(8); // verify groups checkGroups(groupRows, ['NetAdvantage', true, 1000, false, 1000, 'Ignite UI for JavaScript', true, null, false, 254, 'Ignite UI for Angular', false, 20, null, 1000, '', true, 100, null, true, 0], grid.groupingExpressions); })); it('should allow grouping with a custom comparer', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); fix.detectChanges(); fix.componentInstance.data[0].ReleaseDate = new Date(2017, 1, 1, 15, 30, 0, 0); fix.componentInstance.data[1].ReleaseDate = new Date(2017, 1, 1, 20, 30, 0, 0); fix.componentInstance.height = null; const grid = fix.componentInstance.instance; fix.detectChanges(); grid.groupBy({ fieldName: 'ReleaseDate', dir: SortingDirection.Desc, groupingComparer: (a: Date, b: Date) => { if (a instanceof Date && b instanceof Date && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate()) { return 0; } return DefaultSortingStrategy.instance().compareValues(a, b); } }); tick(); fix.detectChanges(); let groupRows = grid.groupsRowList.toArray(); // verify groups count expect(groupRows.length).toEqual(5); // now click the chip to change sorting, the grouping expression should hold // the comparer and reapply the same grouping again const chips = grid.groupArea.chips; // click grouping direction arrow grid.groupArea.handleClick(chips.get(0).id); tick(); fix.detectChanges(); // chips = fix.nativeElement.querySelectorAll('igx-chip'); expect(chips.length).toBe(1); checkChips(chips, grid.groupingExpressions); expect(chips.get(0).nativeElement.querySelectorAll('igx-icon')[0].textContent.trim()).toBe('arrow_upward'); groupRows = grid.groupsRowList.toArray(); expect(groupRows.length).toEqual(5); })); it('should allows expanding/collapsing groups.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; grid.primaryKey = 'ID'; fix.detectChanges(); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); let groupRows = grid.groupsRowList.toArray(); let dataRows = grid.dataRowList.toArray(); // verify groups and data rows count expect(groupRows.length).toEqual(3); expect(dataRows.length).toEqual(8); // toggle grouprow - collapse expect(groupRows[0].expanded).toEqual(true); grid.toggleGroup(groupRows[0].groupRow); tick(); fix.detectChanges(); expect(groupRows[0].expanded).toEqual(false); groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(3); expect(dataRows.length).toEqual(4); // verify collapsed group sub records are not rendered // behavioral change! row should not be returned, as its parent is collapsed for (const rec of groupRows[0].groupRow.records) { expect(grid.getRowByKey(rec.ID)).toBeUndefined(); } // toggle grouprow - expand grid.toggleGroup(groupRows[0].groupRow); tick(); fix.detectChanges(); expect(groupRows[0].expanded).toEqual(true); for (const rec of groupRows[0].groupRow.records) { expect(grid.getRowByKey(rec.ID)).not.toBeUndefined(); } groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(3); expect(dataRows.length).toEqual(8); // verify expanded group sub records are rendered for (const rec of groupRows[0].groupRow.records) { expect(grid.getRowByKey(rec.ID)).not.toBeUndefined(); } const groupRow = grid.getRowByIndex(0); expect(groupRow.isGroupByRow).toBe(true); expect(groupRow.expanded).toBe(true); groupRow.expanded = false; tick(); fix.detectChanges(); expect(groupRow.expanded).toBe(false); grid.clearGrouping(); tick(); grid.groupBy({ fieldName: 'ReleaseDate', dir: SortingDirection.Desc }); fix.detectChanges(); grid.toggleGroup(grid.groupsRowList.first.groupRow); tick(); fix.detectChanges(); expect(groupRows[0].expanded).toEqual(false); })); it('should allow changing the order of the groupBy columns.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); fix.detectChanges(); // set groupingExpressions const grid = fix.componentInstance.instance; const exprs: ISortingExpression[] = [ { fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: true }, { fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: true } ]; grid.groupingExpressions = exprs; tick(); fix.detectChanges(); let groupRows = grid.groupsRowList.toArray(); let dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(13); expect(dataRows.length).toEqual(8); // verify groups checkGroups(groupRows, ['NetAdvantage', true, false, 'Ignite UI for JavaScript', true, false, 'Ignite UI for Angular', false, null, '', true, null, true], grid.groupingExpressions); // change order grid.groupingExpressions = [ { fieldName: 'Released', dir: SortingDirection.Asc, ignoreCase: true }, { fieldName: 'ProductName', dir: SortingDirection.Asc, ignoreCase: true } ]; tick(); grid.sortingExpressions = [ { fieldName: 'Released', dir: SortingDirection.Asc, ignoreCase: true }, { fieldName: 'ProductName', dir: SortingDirection.Asc, ignoreCase: true } ]; tick(); fix.detectChanges(); groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(11); expect(dataRows.length).toEqual(8); // verify groups checkGroups(groupRows, [null, 'Ignite UI for Angular', false, 'Ignite UI for Angular', 'Ignite UI for JavaScript', 'NetAdvantage', true, null, '', 'Ignite UI for JavaScript', 'NetAdvantage'], grid.groupingExpressions); })); it('should group records correctly when ignoreCase is set to true.', fakeAsync(() => { const fix = TestBed.createComponent(GridGroupByCaseSensitiveComponent); fix.detectChanges(); // set groupingExpressions const grid = fix.componentInstance.instance; const exprs: ISortingExpression[] = [ { fieldName: 'ContactTitle', dir: SortingDirection.Asc, ignoreCase: true } ]; grid.groupingExpressions = exprs; tick(); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); const dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(2); expect(dataRows.length).toEqual(5); // verify groups checkGroups(groupRows, ['Order Administrator', 'Owner'], grid.groupingExpressions); })); it('should allow setting expand/collapse state', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; grid.primaryKey = 'ID'; fix.detectChanges(); grid.groupsExpanded = false; grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); let groupRows = grid.groupsRowList.toArray(); let dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(3); expect(dataRows.length).toEqual(0); for (const grRow of groupRows) { expect(grRow.expanded).toBe(false); } grid.groupsExpanded = true; tick(); grid.cdr.detectChanges(); groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); expect(groupRows.length).toEqual(3); expect(dataRows.length).toEqual(8); for (const grRow of groupRows) { expect(grRow.expanded).toBe(true); } })); it('should trigger an groupingDone event when a column is grouped with the correct params.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; grid.primaryKey = 'ID'; fix.detectChanges(); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); const currExpr = fix.componentInstance.currentSortExpressions; expect(currExpr.expressions.length).toEqual(1); expect(currExpr.expressions[0].fieldName).toEqual('Released'); expect(currExpr.groupedColumns.length).toEqual(1); expect(currExpr.groupedColumns[0].field).toEqual('Released'); expect(currExpr.ungroupedColumns.length).toEqual(0); })); it('should trigger an groupingDone event when a column is ungrouped with the correct params.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; grid.primaryKey = 'ID'; fix.detectChanges(); grid.groupBy([ { fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }, { fieldName: 'ReleaseDate', dir: SortingDirection.Desc, ignoreCase: false } ]); tick(); fix.detectChanges(); grid.clearGrouping('Released'); tick(); fix.detectChanges(); const currExpr = fix.componentInstance.currentSortExpressions; expect(currExpr.expressions.length).toEqual(1); expect(currExpr.expressions[0].fieldName).toEqual('ReleaseDate'); expect(currExpr.groupedColumns.length).toEqual(0); expect(currExpr.ungroupedColumns.length).toEqual(1); expect(currExpr.ungroupedColumns[0].field).toEqual('Released'); })); it('should trigger an groupingDone event when multiple columns are grouped with the correct params.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; grid.primaryKey = 'ID'; fix.detectChanges(); grid.groupBy([ { fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }, { fieldName: 'ProductName', dir: SortingDirection.Asc, ignoreCase: false }, { fieldName: 'ReleaseDate', dir: SortingDirection.Desc, ignoreCase: false } ]); tick(); fix.detectChanges(); const currExpr = fix.componentInstance.currentSortExpressions; expect(currExpr.expressions.length).toEqual(3); expect(currExpr.expressions[0].fieldName).toEqual('Released'); expect(currExpr.expressions[1].fieldName).toEqual('ProductName'); expect(currExpr.expressions[2].fieldName).toEqual('ReleaseDate'); expect(currExpr.groupedColumns.length).toEqual(3); expect(currExpr.groupedColumns[0].field).toEqual('Released'); expect(currExpr.groupedColumns[1].field).toEqual('ProductName'); expect(currExpr.groupedColumns[2].field).toEqual('ReleaseDate'); expect(currExpr.ungroupedColumns.length).toEqual(0); })); it('should trigger an groupingDone event when multiple columns are ungrouped with the correct params.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; grid.primaryKey = 'ID'; fix.detectChanges(); grid.groupBy([ { fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }, { fieldName: 'ReleaseDate', dir: SortingDirection.Desc, ignoreCase: false }, { fieldName: 'ProductName', dir: SortingDirection.Asc, ignoreCase: false }, { fieldName: 'Downloads', dir: SortingDirection.Asc, ignoreCase: false } ]); tick(); fix.detectChanges(); grid.clearGrouping(['Released', 'ProductName', 'Downloads']); tick(); fix.detectChanges(); const currExpr = fix.componentInstance.currentSortExpressions; expect(currExpr.expressions.length).toEqual(1); expect(currExpr.expressions[0].fieldName).toEqual('ReleaseDate'); expect(currExpr.groupedColumns.length).toEqual(0); expect(currExpr.ungroupedColumns.length).toEqual(3); expect(currExpr.ungroupedColumns[0].field).toEqual('Released'); expect(currExpr.ungroupedColumns[1].field).toEqual('ProductName'); expect(currExpr.ungroupedColumns[2].field).toEqual('Downloads'); })); it(`should trigger an groupingDone event when the user pushes a new array of grouping expressions, which results in both grouping and ungrouping at the same time.`, fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; grid.primaryKey = 'ID'; fix.detectChanges(); grid.groupBy([ { fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }, { fieldName: 'ReleaseDate', dir: SortingDirection.Desc, ignoreCase: false }, { fieldName: 'ProductName', dir: SortingDirection.Asc, ignoreCase: false } ]); tick(); fix.detectChanges(); const newExpressions = [ { fieldName: 'ReleaseDate', dir: SortingDirection.Desc, ignoreCase: false }, { fieldName: 'ProductName', dir: SortingDirection.Asc, ignoreCase: false }, { fieldName: 'Downloads', dir: SortingDirection.Asc, ignoreCase: false } ]; grid.groupingExpressions = newExpressions; tick(); fix.detectChanges(); const currExpr = fix.componentInstance.currentSortExpressions; expect(currExpr.expressions.length).toEqual(3); expect(currExpr.expressions[0].fieldName).toEqual('ReleaseDate'); expect(currExpr.expressions[1].fieldName).toEqual('ProductName'); expect(currExpr.expressions[2].fieldName).toEqual('Downloads'); expect(currExpr.ungroupedColumns.length).toEqual(1); expect(currExpr.ungroupedColumns[0].field).toEqual('Released'); expect(currExpr.groupedColumns.length).toEqual(1); expect(currExpr.groupedColumns[0].field).toEqual('Downloads'); })); it('should allow setting custom template for group row content and expand/collapse icons.', fakeAsync(() => { const fix = TestBed.createComponent(CustomTemplateGridComponent); const grid = fix.componentInstance.instance; fix.detectChanges(); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); for (const grRow of groupRows) { const elem = grRow.groupContent.nativeElement; const grVal = grRow.groupRow.value === null ? '' : grRow.groupRow.value.toString(); const expectedText = 'Grouping by "Is it Released". ' + 'Total items with value:' + grVal + ' are ' + grRow.groupRow.records.length; expect(elem.innerText.trim(['\n', '\r', ' '])).toEqual(expectedText); const expander = grRow.nativeElement.querySelector('.igx-grid__grouping-indicator'); expect(expander.innerText).toBe('EXPANDED'); } groupRows[0].toggle(); const expndr = groupRows[0].nativeElement.querySelector('.igx-grid__grouping-indicator'); expect(expndr.innerText).toBe('COLLAPSED'); expect(grid.headerGroupContainer.nativeElement.innerText).toBe('EXPANDED'); grid.toggleAllGroupRows(); fix.detectChanges(); expect(grid.headerGroupContainer.nativeElement.innerText).toBe('COLLAPSED'); })); it('should allow setting custom template for group row via Input.', fakeAsync(() => { const fix = TestBed.createComponent(CustomTemplateGridComponent); const grid = fix.componentInstance.instance; fix.detectChanges(); grid.groupRowTemplate = fix.componentInstance.customGroupBy; fix.detectChanges(); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); const grRow = grid.groupsRowList.toArray()[0]; const elem = grRow.groupContent.nativeElement; expect(elem.innerText.trim()).toEqual('CUSTOM GROUP BY'); })); it('should have the correct ARIA attributes on the group rows.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; grid.primaryKey = 'ID'; fix.detectChanges(); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); for (const grRow of groupRows) { const elem = grRow.element.nativeElement; expect(elem.attributes['aria-describedby'].value).toEqual(grid.id + '_Released'); expect(elem.attributes['aria-expanded'].value).toEqual('true'); } })); it('should not apply grouping if the grouping expressions value is the same reference', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); fix.detectChanges(); // group by string column const grid = fix.componentInstance.instance; fix.detectChanges(); grid.groupBy({ fieldName: 'ReleaseDate', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); spyOn(grid.groupingExpressionsChange, 'emit'); fix.detectChanges(); const firstCellElem = grid.gridAPI.get_cell_by_index(2, 'Downloads'); UIInteractions.simulateClickAndSelectEvent(firstCellElem); fix.detectChanges(); expect(grid.groupingExpressionsChange.emit).toHaveBeenCalledTimes(0); })); it('should emit groupingExpressionsChange when a group is sorted through the chip', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); fix.detectChanges(); // group by string column const grid = fix.componentInstance.instance; fix.detectChanges(); grid.groupBy({ fieldName: 'ReleaseDate', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); spyOn(grid.groupingExpressionsChange, 'emit'); fix.detectChanges(); const chips = grid.groupArea.chips; grid.groupArea.handleClick(chips.first.id); fix.detectChanges(); expect(grid.groupingExpressionsChange.emit).toHaveBeenCalledTimes(1); })); it('should group unbound column with custom grouping strategy', fakeAsync(() => { const fix = TestBed.createComponent(GroupableGridComponent); fix.componentInstance.data.forEach((r, i) => { r['fieldValue1'] = Math.floor(i / 3); r['fieldValue2'] = Math.floor(i / 4); }); fix.detectChanges(); fix.componentInstance.instance.groupBy({ fieldName: 'UnboundField', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); const groupRows = fix.componentInstance.instance.groupsRowList.toArray(); expect(groupRows.length).toEqual(4); })); it('should update chip state after columns change.', () => { const fix = TestBed.createComponent(GroupByDataMoreColumnsComponent); fix.detectChanges(); const grid = fix.componentInstance.instance; grid.groupingExpressions = [ { dir: SortingDirection.Asc, fieldName: "NewColumn" } ]; fix.detectChanges(); // no such column initially, so chip is disabled. const chips = grid.groupArea.chips; expect(chips.first.disabled).toBeTrue(); const newCols = [...fix.componentInstance.columns]; newCols.push({ field: "NewColumn", width: 100 }); fix.componentInstance.columns = newCols; fix.detectChanges(); // column now exists and has groupable=true, so chip should be enabled. expect(chips.first.disabled).toBeFalse(); }); it('should update chip state on column groupable prop change', () => { const fix = TestBed.createComponent(DefaultGridComponent); fix.detectChanges(); const grid = fix.componentInstance.instance; const column = grid.getColumnByName('ProductName'); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); // initially should not be disabled. const chips = grid.groupArea.chips; expect(chips.first.disabled).toBeFalse(); // should get disbaled on groupable=false column.groupable = false; fix.detectChanges(); expect(chips.first.disabled).toBeTrue(); }); // GroupBy + Sorting integration it('should apply sorting on each group\'s records when non-grouped column is sorted.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.enableSorting = true; tick(); fix.detectChanges(); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); const dataRows = grid.dataRowList.toArray(); // verify groups and data rows count expect(groupRows.length).toEqual(5); expect(dataRows.length).toEqual(8); grid.sort({ fieldName: 'Released', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); // verify groups checkGroups(groupRows, ['NetAdvantage', 'Ignite UI for JavaScript', 'Ignite UI for Angular', '', null]); // verify data records order const expectedDataRecsOrder = [false, true, false, true, null, false, true, true]; dataRows.forEach((row, index) => { expect(row.data.Released).toEqual(expectedDataRecsOrder[index]); }); })); it('should apply the specified sort order on the group rows when already grouped columnn is sorted in asc/desc order.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.enableSorting = true; fix.detectChanges(); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); let groupRows = grid.groupsRowList.toArray(); let dataRows = grid.dataRowList.toArray(); // verify groups and data rows count expect(groupRows.length).toEqual(5); expect(dataRows.length).toEqual(8); // verify group order checkGroups(groupRows, ['NetAdvantage', 'Ignite UI for JavaScript', 'Ignite UI for Angular', '', null]); grid.sort({ fieldName: 'ProductName', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); // verify group order checkGroups(groupRows, [null, '', 'Ignite UI for Angular', 'Ignite UI for JavaScript', 'NetAdvantage']); })); it('should remove grouping when already grouped columnn is sorted with order "None" via the API.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.enableSorting = true; fix.detectChanges(); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); let groupRows = grid.groupsRowList.toArray(); let dataRows = grid.dataRowList.toArray(); // verify groups and data rows count expect(groupRows.length).toEqual(5); expect(dataRows.length).toEqual(8); // verify group order checkGroups(groupRows, ['NetAdvantage', 'Ignite UI for JavaScript', 'Ignite UI for Angular', '', null]); grid.sort({ fieldName: 'ProductName', dir: SortingDirection.None, ignoreCase: false }); fix.detectChanges(); groupRows = grid.groupsRowList.toArray(); dataRows = grid.dataRowList.toArray(); // verify groups and data rows count expect(groupRows.length).toEqual(0); expect(dataRows.length).toEqual(8); })); it('should not be able to sort the column when is already grouped by', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.enableSorting = true; fix.detectChanges(); grid.groupBy({ fieldName: 'Downloads', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); const headers = fix.debugElement.queryAll(By.css(COLUMN_HEADER_CLASS)); //header sort icon should not be displayed const sortIcon = headers[0].query(By.css('.sort-icon')); expect(sortIcon).toBeNull() })); it('should group by the specified field when grouping by an already sorted field.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.enableSorting = true; fix.detectChanges(); grid.sort({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); expect(grid.sortingExpressions.length).toBe(1); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Asc, ignoreCase: false }); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); // verify group order checkGroups(groupRows, [null, '', 'Ignite UI for Angular', 'Ignite UI for JavaScript', 'NetAdvantage']); expect(grid.sortingExpressions.length).toBe(0); expect(grid.groupingExpressions.length).toBe(1); })); it('should allow grouping of already sorted column', waitForAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.enableSorting = true; fix.detectChanges(); grid.sort({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); const groupRows = grid.groupsRowList.toArray(); const dataRows = grid.dataRowList.toArray(); // verify groups and data rows count expect(groupRows.length).toEqual(5); expect(dataRows.length).toEqual(8); expect(grid.groupingExpressions.length).toEqual(1); })); // GroupBy + Virtualization integration it('should virtualize data and group records.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.width = '600px'; fix.componentInstance.height = '300px'; grid.columnWidth = '200px'; fix.detectChanges(); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); expect(grid.groupsRowList.toArray().length).toEqual(3); expect(grid.dataRowList.toArray().length).toEqual(2); expect(grid.rowList.toArray().length).toEqual(5); })); it('should recalculate visible chunk data and scrollbar size when expanding/collapsing group rows.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.width = '600px'; tick(); fix.componentInstance.height = '300px'; tick(); grid.columnWidth = '200px'; tick(); fix.detectChanges(); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); const origScrollHeight = parseInt((grid.verticalScrollContainer.getScroll().children[0] as HTMLElement).style.height, 10); // collapse all group rows currently in the view const grRows = grid.groupsRowList.toArray(); grRows[0].toggle(); tick(); fix.detectChanges(); // verify rows are updated expect(grid.groupsRowList.toArray().length).toEqual(4); expect(grid.dataRowList.toArray().length).toEqual(1); expect(grid.rowList.toArray().length).toEqual(5); // verify scrollbar is updated - 4 rows x 51px are hidden. expect(parseInt((grid.verticalScrollContainer.getScroll().children[0] as HTMLElement).style.height, 10)) .toEqual(origScrollHeight - 204); grRows[0].toggle(); tick(); fix.detectChanges(); expect(grid.groupsRowList.toArray().length).toEqual(3); expect(grid.dataRowList.toArray().length).toEqual(2); expect(grid.rowList.toArray().length).toEqual(5); expect(parseInt((grid.verticalScrollContainer.getScroll().children[0] as HTMLElement).style.height, 10)) .toEqual(origScrollHeight); })); it('should persist group row expand/collapse state when scrolling.', async () => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.width = '500px'; fix.componentInstance.height = '300px'; grid.columnWidth = '200px'; await wait(); fix.detectChanges(); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); let groupRow = grid.groupsRowList.toArray()[0]; groupRow.toggle(); await wait(); expect(groupRow.expanded).toBe(false); fix.detectChanges(); // scroll to bottom grid.verticalScrollContainer.getScroll().scrollTop = 10000; await wait(100); fix.detectChanges(); // scroll back to the top grid.verticalScrollContainer.getScroll().scrollTop = 0; await wait(100); fix.detectChanges(); groupRow = grid.groupsRowList.toArray()[0]; expect(groupRow.expanded).toBe(false); }); it('should retain focused group after expanding/collapsing row via KB - Alt + ArrowUp/ArrowDown', async () => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.width = '500px'; fix.componentInstance.height = '300px'; grid.columnWidth = '200px'; await wait(); fix.detectChanges(); grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); fix.detectChanges(); // scroll to bottom grid.verticalScrollContainer.getScroll().