igniteui-angular-sovn
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
910 lines (755 loc) • 134 kB
text/typescript
import { Component, DebugElement, ViewChild } from '@angular/core';
import { fakeAsync, TestBed, tick, ComponentFixture, flush } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { IgxGridComponent } from './grid.component';
import { wait, UIInteractions } from '../../test-utils/ui-interactions.spec';
import { GridFunctions, GridSummaryFunctions } from '../../test-utils/grid-functions.spec';
import { configureTestSuite } from '../../test-utils/configure-suite';
import {
ProductsComponent,
SummaryColumnComponent,
FilteringComponent,
SummariesGroupByComponent,
SummariesGroupByTransactionsComponent
} from '../../test-utils/grid-samples.spec';
import { clearGridSubs, setupGridScrollDetection } from '../../test-utils/helper-utils.spec';
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
import { GridSummaryCalculationMode } from '../common/enums';
import { IgxNumberFilteringOperand, IgxStringFilteringOperand } from '../../data-operations/filtering-condition';
import { DropPosition } from '../moving/moving.service';
import { DatePipe } from '@angular/common';
import { IgxGridGroupByRowComponent } from './groupby-row.component';
import { SortingDirection } from '../../data-operations/sorting-strategy';
import { IColumnPipeArgs, IgxColumnComponent, IgxDateSummaryOperand, IgxGridRow, IgxGroupByRow, IgxNumberSummaryOperand, IgxSummaryOperand, IgxSummaryResult, IgxSummaryRow } from '../public_api';
describe('IgxGrid - Summaries #grid', () => {
const SUMMARY_CLASS = '.igx-grid-summary';
const ITEM_CLASS = 'igx-grid-summary__item';
const SUMMARY_ROW = 'igx-grid-summary-row';
const SUMMARY_CELL = 'igx-grid-summary-cell';
const EMPTY_SUMMARY_CLASS = 'igx-grid-summary--empty';
const DEBOUNCETIME = 30;
configureTestSuite((() => {
return TestBed.configureTestingModule({
imports: [
NoopAnimationsModule,
CustomSummariesComponent,
ProductsComponent,
SummaryColumnComponent,
FilteringComponent,
SummariesGroupByComponent,
SummariesGroupByTransactionsComponent
]
});
}));
describe('Base tests: ', () => {
describe('in grid with no summaries defined: ', () => {
let fixture: ComponentFixture<ProductsComponent>;
let grid: IgxGridComponent;
beforeEach(() => {
fixture = TestBed.createComponent(ProductsComponent);
fixture.detectChanges();
grid = fixture.componentInstance.grid;
});
it('should not have summary if no summary is active ', () => {
expect(fixture.debugElement.query(By.css(SUMMARY_CLASS))).toBeNull();
});
it('should enableSummaries through grid API ', () => {
expect(grid.hasSummarizedColumns).toBe(false);
let tFoot = GridFunctions.getGridFooterWrapper(fixture).nativeElement.getBoundingClientRect().height;
expect(tFoot < grid.defaultSummaryHeight).toBe(true);
grid.enableSummaries([{ fieldName: 'ProductName' }, { fieldName: 'ProductID' }]);
fixture.detectChanges();
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fixture);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, [], []);
expect(grid.getColumnByName('ProductID').hasSummary).toBe(true);
expect(grid.getColumnByName('ProductName').hasSummary).toBe(true);
expect(grid.getColumnByName('OrderDate').hasSummary).toBe(false);
grid.summaryRowHeight = 0;
fixture.detectChanges();
tFoot = GridFunctions.getGridFooterWrapper(fixture).nativeElement.getBoundingClientRect().height;
expect(tFoot).toEqual(grid.defaultSummaryHeight);
});
it(`should recalculate grid sizes correctly when the column is outside of the viewport`, () => {
grid.width = '300px';
fixture.detectChanges();
grid.getColumnByName('UnitsInStock').hasSummary = true;
grid.summaryRowHeight = null;
fixture.detectChanges();
const tFoot = GridFunctions.getGridFooterWrapper(fixture).nativeElement.getBoundingClientRect().height;
expect(tFoot).toEqual(5 * grid.defaultSummaryHeight);
expect(GridSummaryFunctions.getRootSummaryRow(fixture)).toBeDefined();
});
it(`Should update summary section when the column is outside of the
viewport and have identical width with others`, (async () => {
grid.getColumnByName('UnitsInStock').hasSummary = true;
grid.width = '300px';
await wait(100);
fixture.detectChanges();
grid.addRow({
ProductID: 11, ProductName: 'Belgian Chocolate', InStock: true, UnitsInStock: 99000, OrderDate: new Date('2018-03-01')
});
await wait(30);
fixture.detectChanges();
grid.dataRowList.first.virtDirRow.scrollTo(3);
await wait(30);
fixture.detectChanges();
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fixture);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'],
['11', '0', '99,000', '138,004', '12,545.818']);
}));
it('When we have data which is undefined and enable summary per defined column, error should not be thrown', () => {
const idColumn = grid.getColumnByName('ProductID');
expect(grid.data.length > 0).toEqual(true);
fixture.componentInstance.data = undefined;
fixture.detectChanges();
expect(grid.data).toEqual([]);
expect(() => {
grid.enableSummaries(idColumn.field);
fixture.detectChanges();
}).not.toThrow();
});
});
describe('custom summaries: ', () => {
let fixture: ComponentFixture<CustomSummariesComponent>;
let grid: IgxGridComponent;
beforeEach(() => {
fixture = TestBed.createComponent(CustomSummariesComponent);
fixture.detectChanges();
grid = fixture.componentInstance.grid1;
});
it('should properly render custom summaries', () => {
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fixture);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Sum', 'Avg'], ['10', '39,004', '3,900.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Earliest', 'Items InStock'], ['May 17, 1990', '1337']);
grid.filter('UnitsInStock', '0', IgxNumberFilteringOperand.instance().condition('lessThan'), true);
fixture.detectChanges();
const filterResult = grid.rowList.length;
expect(filterResult).toEqual(0);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Sum', 'Avg'], ['0', '0', '0']);
});
it('should properly calculate all data custom summaries height', () => {
grid.getColumnByName('UnitsInStock').summaries = fixture.componentInstance.allDataAvgSummary;
grid.getColumnByName('OrderDate').summaries = fixture.componentInstance.allDataAvgSummary;
fixture.detectChanges();
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fixture);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Test 1', 'Test 2'], ['10', '50', '150']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Count', 'Test 3'], ['10', '850']);
grid.summaryRowHeight = undefined;
fixture.detectChanges();
const tFootHeight = GridFunctions.getGridFooterWrapper(fixture).nativeElement.getBoundingClientRect().height;
expect(tFootHeight).toBeGreaterThanOrEqual(3 * grid.defaultSummaryHeight);
});
it('should change custom summaries at runtime', () => {
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fixture);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Sum', 'Avg'], ['10', '39,004', '3,900.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Earliest', 'Items InStock'], ['May 17, 1990', '1337']);
GridSummaryFunctions.verifyVisibleSummariesHeight(fixture, 3, grid.defaultSummaryHeight);
grid.getColumnByName('UnitsInStock').summaries = fixture.componentInstance.dealsSummaryMinMax;
grid.summaryRowHeight = 0;
fixture.detectChanges();
const tFootHeight = GridFunctions.getGridFooterWrapper(fixture).nativeElement.getBoundingClientRect().height;
expect(tFootHeight).toBe(2 * grid.defaultSummaryHeight);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Min', 'Max'], ['0', '20,000']);
GridSummaryFunctions.verifyVisibleSummariesHeight(fixture, 2, grid.defaultSummaryHeight);
});
it('should be able to access alldata from each summary', () => {
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fixture);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Sum', 'Avg'], ['10', '39,004', '3,900.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Earliest', 'Items InStock'], ['May 17, 1990', '1337']);
GridSummaryFunctions.verifyVisibleSummariesHeight(fixture, 3, grid.defaultSummaryHeight);
grid.getColumnByName('UnitsInStock').summaries = fixture.componentInstance.inStockSummary;
fixture.detectChanges();
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg', 'Items InStock'],
['10', '0', '20,000', '39,004', '3,900.4', '6']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Earliest', 'Items InStock'], ['May 17, 1990', '1337']);
grid.getCellByColumn(4, 'InStock').update(true);
fixture.detectChanges();
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg', 'Items InStock'],
['10', '0', '20,000', '39,004', '3,900.4', '7']);
grid.filter('UnitsInStock', 0, IgxNumberFilteringOperand.instance().condition('equals'));
fixture.detectChanges();
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg', 'Items InStock'],
['3', '0', '0', '0', '0', '1']);
});
it('Last column summary cell should be aligned according to its data cells', () => {
grid.columnList.forEach(c => {
c.width = '150px';
});
grid.getColumnByName('UnitsInStock').hasSummary = true;
grid.width = '900px';
grid.height = '500px';
fixture.detectChanges();
// Get last cell of first data row
const lastColumnNormalCell = GridFunctions.getRowCells(fixture, 0)[4];
const lastColumnNormalCellRect = lastColumnNormalCell.nativeElement.getBoundingClientRect();
// Get last summary cell of the summary row
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fixture);
const lastColumnSummaryCell = GridSummaryFunctions.getSummaryCellByVisibleIndex(summaryRow, 4);
const lastColumnSummaryCellRect = lastColumnSummaryCell.nativeElement.getBoundingClientRect();
expect(lastColumnSummaryCellRect.left).toBe(lastColumnNormalCellRect.left,
'summary cell and data cell are not left aligned');
expect(lastColumnSummaryCellRect.right).toBe(lastColumnNormalCellRect.right,
'summary cell and data cell are not right aligned');
});
});
describe('specific data: ', () => {
let fixture: ComponentFixture<FilteringComponent>;
let grid: IgxGridComponent;
beforeEach(() => {
fixture = TestBed.createComponent(FilteringComponent);
fixture.detectChanges();
grid = fixture.componentInstance.grid;
});
it('should have correct summaries when there are null and undefined values', () => {
grid.getColumnByName('ProductName').hasSummary = true;
grid.getColumnByName('Downloads').hasSummary = true;
grid.getColumnByName('Released').hasSummary = true;
grid.getColumnByName('ReleaseDate').hasSummary = true;
fixture.detectChanges();
const summaryRow = fixture.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['8']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '1', '1,000', '2,204', '275.5']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count'], ['8']);
const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'short', day: 'numeric' };
const earliest = SampleTestData.timeGenerator.timedelta(SampleTestData.today, 'month', -1).toLocaleString('us', options);
const latest = SampleTestData.timeGenerator.timedelta(SampleTestData.today, 'month', 1).toLocaleString('us', options);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Count', 'Earliest', 'Latest'], ['8', earliest, latest]);
});
});
describe('', () => {
let fix;
let grid: IgxGridComponent;
beforeEach(() => {
fix = TestBed.createComponent(SummaryColumnComponent);
fix.detectChanges();
grid = fix.componentInstance.grid;
});
it('should disableSummaries through grid API ', () => {
const summariedColumns = [];
grid.columnList.forEach((col) => {
if (col.hasSummary) {
summariedColumns.push(col.field);
}
});
grid.disableSummaries(summariedColumns);
fix.detectChanges();
expect(GridSummaryFunctions.getRootSummaryRow(fix)).toBeNull();
expect(grid.hasSummarizedColumns).toBe(false);
});
it('should change summary operand through grid API', () => {
grid.enableSummaries([{ fieldName: 'UnitsInStock', customSummary: fix.componentInstance.dealsSummaryMinMax }]);
grid.summaryRowHeight = 0;
fix.detectChanges();
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
const tFootHeight = GridFunctions.getGridFooterWrapper(fix).nativeElement.getBoundingClientRect().height;
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Min', 'Max'], ['0', '20,000']);
GridSummaryFunctions.verifyVisibleSummariesHeight(fix, 3, grid.defaultSummaryHeight);
expect(tFootHeight).toBe(3 * grid.defaultSummaryHeight);
});
it('should have summary per each column that \'hasSummary\'= true', () => {
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Count', 'Earliest', 'Latest'], []);
});
it('should have count summary for string and boolean data types', () => {
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
grid.columnList.forEach((col) => {
if (col.hasSummary && (col.dataType === 'string' || col.dataType === 'boolean')) {
GridSummaryFunctions.verifyColumnSummaries(summaryRow, col.visibleIndex, ['Count'], []);
}
});
});
it('should have count, min, max, avg and sum summary for numeric data types', () => {
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
grid.columnList.forEach((col) => {
if (col.hasSummary && (col.dataType === 'number')) {
GridSummaryFunctions.verifyColumnSummaries(summaryRow, col.visibleIndex, ['Count', 'Min', 'Max', 'Sum', 'Avg'], []);
}
});
});
it('should have count, earliest and latest summary for \'date\' data types', () => {
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
grid.columnList.forEach((col) => {
if (col.hasSummary && (col.dataType === 'date')) {
GridSummaryFunctions.verifyColumnSummaries(summaryRow, col.visibleIndex, ['Count', 'Earliest', 'Latest'], []);
}
});
});
it('should summary function stay active when is clicked on it\'s label', () => {
const summary = fix.debugElement.queryAll(By.css(SUMMARY_CELL))[3];
const min: DebugElement = summary.query(By.css('[title=\'Min\']'));
expect(min.parent.nativeElement.classList.contains(ITEM_CLASS)).toBeTruthy();
min.triggerEventHandler('click', null);
fix.detectChanges();
expect(min.parent.nativeElement.classList.contains(ITEM_CLASS)).toBeTruthy();
expect(summary.query(By.css('[title=\'Count\']')).parent.nativeElement.classList.contains(ITEM_CLASS)).toBeTruthy();
expect(summary.query(By.css('[title=\'Max\']')).parent.nativeElement.classList.contains(ITEM_CLASS)).toBeTruthy();
expect(summary.query(By.css('[title=\'Sum\']')).parent.nativeElement.classList.contains(ITEM_CLASS)).toBeTruthy();
expect(summary.query(By.css('[title=\'Avg\']')).parent.nativeElement.classList.contains(ITEM_CLASS)).toBeTruthy();
});
it('should calculate summaries for \'number\' dataType or return if no data is provided', () => {
const summaryClass = fix.componentInstance.numberSummary;
const summaries = summaryClass.operate(fix.componentInstance.data.map((x) => x['UnitsInStock']));
expect(summaries[0].summaryResult).toBe(10);
expect(summaries[1].summaryResult).toBe(0);
expect(summaries[2].summaryResult).toBe(20000);
expect(summaries[3].summaryResult).toBe(39004);
expect(summaries[4].summaryResult).toBe(3900.4);
const emptySummaries = summaryClass.operate();
expect(emptySummaries[0].summaryResult).toBe(0);
expect(typeof emptySummaries[1].summaryResult).not.toEqual(undefined);
expect(typeof emptySummaries[2].summaryResult).not.toEqual(undefined);
expect(typeof emptySummaries[3].summaryResult).not.toEqual(undefined);
expect(typeof emptySummaries[4].summaryResult).not.toEqual(undefined);
expect(typeof emptySummaries[1].summaryResult).not.toEqual(null);
expect(typeof emptySummaries[2].summaryResult).not.toEqual(null);
expect(typeof emptySummaries[3].summaryResult).not.toEqual(null);
expect(typeof emptySummaries[4].summaryResult).not.toEqual(null);
expect(emptySummaries[1].summaryResult === 0).toBeTruthy();
expect(emptySummaries[2].summaryResult === 0).toBeTruthy();
expect(emptySummaries[3].summaryResult === 0).toBeTruthy();
expect(emptySummaries[4].summaryResult === 0).toBeTruthy();
});
it('should calculate summaries for \'date\' dataType or return if no data is provided', () => {
const summaryClass = fix.componentInstance.dateSummary;
const pipe = new DatePipe('en-US');
const summaries = summaryClass.operate(fix.componentInstance.data.map((x) => x['OrderDate']));
expect(summaries[0].summaryResult).toBe(10);
expect(pipe.transform(summaries[1].summaryResult, 'mediumDate')).toBe('May 17, 1990');
expect(pipe.transform(summaries[2].summaryResult, 'mediumDate')).toBe('Dec 25, 2025');
const emptySummaries = summaryClass.operate([]);
expect(emptySummaries[0].summaryResult).toBe(0);
expect(emptySummaries[1].summaryResult).toBe(undefined);
expect(emptySummaries[2].summaryResult).toBe(undefined);
});
it('should display summaries for \'date\' dataType based on column formatter', () => {
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
const pipe = new DatePipe('fr-FR');
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['10', 'May 17, 1990', 'Dec 25, 2025']);
grid.getColumnByName('OrderDate').summaryFormatter
= ((summaryResult: IgxSummaryResult, summaryOperand: IgxSummaryOperand) => {
const result = summaryResult.summaryResult;
if (summaryOperand instanceof IgxDateSummaryOperand
&& summaryResult.key !== 'count' && result !== null && result !== undefined) {
return pipe.transform(result, 'mediumDate');
}
return result;
});
fix.detectChanges();
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['10', '17 mai 1990', '25 déc. 2025']);
});
it('should calc tfoot height according number of summary functions', () => {
const summaries = fix.debugElement.queryAll(By.css(SUMMARY_CELL));
const footerRow = GridSummaryFunctions.getRootSummaryRow(fix).nativeElement.getBoundingClientRect().height;
const tfootSize = +footerRow;
grid.summaryRowHeight = null;
fix.detectChanges();
const expectedHeight = GridSummaryFunctions.calcMaxSummaryHeight(grid.columnList, summaries, grid.defaultSummaryHeight);
expect(tfootSize).toBe(expectedHeight);
});
it('should be able to change \'hasSummary\' property runtime and to recalculate grid sizes correctly', fakeAsync(() => {
grid.columnList.forEach((col) => {
if (col.field !== 'ProductID') {
expect(grid.getColumnByName(col.field).hasSummary).toBe(true);
}
});
grid.getColumnByName('UnitsInStock').hasSummary = false;
grid.summaryRowHeight = 0;
tick(100);
fix.detectChanges();
expect(grid.getColumnByName('UnitsInStock').hasSummary).toBe(false);
const summaries = fix.debugElement.queryAll(By.css(SUMMARY_CELL)).filter((el) =>
el.nativeElement.classList.contains(EMPTY_SUMMARY_CLASS) === false);
const tfootSize = GridSummaryFunctions.getRootSummaryRow(fix).nativeElement.getBoundingClientRect().height;
const expectedHeight = GridSummaryFunctions.calcMaxSummaryHeight(grid.columnList, summaries, grid.defaultSummaryHeight);
expect(tfootSize).toBe(expectedHeight);
grid.getColumnByName('ProductName').hasSummary = false;
grid.getColumnByName('InStock').hasSummary = false;
grid.getColumnByName('OrderDate').hasSummary = false;
fix.detectChanges();
tick(100);
expect(GridSummaryFunctions.getRootSummaryRow(fix)).toBeNull();
expect(grid.hasSummarizedColumns).toBe(false);
}));
it('should render correct data after hiding one bigger and then one smaller summary when scrolled to the bottom', (async () => {
grid.data = SampleTestData.foodProductData();
grid.width = '800px';
grid.height = '600px';
grid.allowFiltering = false;
fix.detectChanges();
await wait(100);
let rowsRendered;
let tbody;
let expectedRowLenght;
let firstCellsText;
GridFunctions.scrollTop(grid, 10000);
fix.detectChanges();
await wait(100);
fix.detectChanges();
rowsRendered = GridFunctions.getRows(fix);
tbody = GridFunctions.getGridDisplayContainer(fix).nativeElement.getBoundingClientRect().height;
expectedRowLenght = Math.round(parseFloat(tbody) / grid.defaultRowHeight);
expect(rowsRendered.length).toEqual(expectedRowLenght);
grid.disableSummaries(['ProductName', 'InStock', 'UnitsInStock']);
fix.detectChanges();
await wait(100);
fix.detectChanges();
rowsRendered = GridFunctions.getRows(fix);
tbody = GridFunctions.getGridDisplayContainer(fix).nativeElement.getBoundingClientRect().height;
expectedRowLenght = Math.ceil(parseFloat(tbody) / grid.defaultRowHeight) - 1;
firstCellsText = rowsRendered.map((item) => {
const cellElem = GridFunctions.getRowCells(fix, 0, item)[0];
if (cellElem) {
return GridFunctions.getValueFromCellElement(cellElem);
}
});
expect(rowsRendered.length).toEqual(expectedRowLenght);
let expectedFirstCellNum = grid.data.length - expectedRowLenght + 1;
for (let i = 0; i < rowsRendered.length - 1; i++) {
expect(firstCellsText[i]).toEqual((expectedFirstCellNum + i).toString());
}
grid.disableSummaries(['OrderDate']);
fix.detectChanges();
await wait(100);
fix.detectChanges();
rowsRendered = GridFunctions.getRows(fix);
tbody = GridFunctions.getGridDisplayContainer(fix).nativeElement.getBoundingClientRect().height;
expectedRowLenght = Math.ceil(parseFloat(tbody) / grid.defaultRowHeight) - 1;
firstCellsText = rowsRendered.map((item) => {
const cellElem = GridFunctions.getRowCells(fix, 0, item)[0];
if (cellElem) {
return GridFunctions.getValueFromCellElement(cellElem);
}
});
expect(rowsRendered.length).toEqual(expectedRowLenght);
expectedFirstCellNum = grid.data.length - expectedRowLenght + 1;
for (let i = 0; i < rowsRendered.length - 1; i++) {
expect(firstCellsText[i]).toEqual((expectedFirstCellNum + i).toString());
}
}));
it('should be able to set the height of the summary row through summaryRowHeight input unless the value is falsy', () => {
const summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
const summaryRowHeight = 300;
grid.summaryRowHeight = summaryRowHeight;
fix.detectChanges();
expect(summaryRow.nativeElement.offsetHeight).toBe(summaryRowHeight);
grid.summaryRowHeight = 0;
fix.detectChanges();
expect(summaryRow.nativeElement.offsetHeight).not.toBeFalsy();
grid.summaryRowHeight = null;
fix.detectChanges();
expect(summaryRow.nativeElement.offsetHeight).not.toBeFalsy();
});
it('should display the formatted summary value in the summary cells\' tooltip', () => {
const summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
const pipe = new DatePipe('fr-FR');
const summary = GridSummaryFunctions.getSummaryCellByVisibleIndex(summaryRow, 4);
const summaryItems = summary.queryAll(By.css('.igx-grid-summary__item'));
let summaryResultsValues = ['10', 'May 17, 1990', 'Dec 25, 2025'];
for (let i = 0; i < summaryItems.length; i++) {
const summaryItem = summaryItems[i];
const summaryResult = summaryItem.query(By.css('.igx-grid-summary__result'));
const summaryResultTooltip = summaryResult.nativeElement.getAttribute('title');
expect(summaryResultsValues[i]).toEqual(summaryResultTooltip);
}
grid.getColumnByName('OrderDate').summaryFormatter
= ((summaryResult: IgxSummaryResult, summaryOperand: IgxSummaryOperand) => {
const result = summaryResult.summaryResult;
if (summaryOperand instanceof IgxDateSummaryOperand
&& summaryResult.key !== 'count' && result !== null && result !== undefined) {
return pipe.transform(result, 'mediumDate');
}
return result;
});
fix.detectChanges();
summaryResultsValues = ['10', '17 mai 1990', '25 déc. 2025'];
for (let i = 0; i < summaryItems.length; i++) {
const summaryItem = summaryItems[i];
const summaryResult = summaryItem.query(By.css('.igx-grid-summary__result'));
const summaryResultTooltip = summaryResult.nativeElement.getAttribute('title');
expect(summaryResultsValues[i]).toEqual(summaryResultTooltip);
}
});
});
});
describe('Integration Scenarios: ', () => {
describe('', () => {
let fix;
let grid: IgxGridComponent;
beforeEach(() => {
fix = TestBed.createComponent(SummaryColumnComponent);
fix.detectChanges();
grid = fix.componentInstance.grid;
});
it('Filtering: should calculate summaries only over filteredData', fakeAsync(() => {
grid.filter('UnitsInStock', 0, IgxNumberFilteringOperand.instance().condition('equals'), true);
fix.detectChanges();
let filterResult = grid.rowList.length;
expect(filterResult).toEqual(3);
let summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['3']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['3']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['3', '0', '0', '0', '0']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['3', 'Jul 27, 2001', 'Oct 11, 2007']);
grid.filter('ProductID', 0, IgxNumberFilteringOperand.instance().condition('equals'), true);
fix.detectChanges();
filterResult = grid.rowList.length;
expect(filterResult).toEqual(0);
summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['0']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['0']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count', 'Min', 'Max', 'Sum', 'Avg'], ['0', '0', '0', '0', '0']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Count', 'Earliest', 'Latest'], ['0', '', '']);
grid.clearFilter();
fix.detectChanges();
filterResult = grid.rowList.length;
expect(filterResult).toEqual(10);
summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['10', '0', '20,000', '39,004', '3,900.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['10', 'May 17, 1990', 'Dec 25, 2025']);
}));
it('Moving: should move summaries when move column', fakeAsync(() => {
grid.moving = true;
const colUnitsInStock = grid.getColumnByName('UnitsInStock');
const colProductID = grid.getColumnByName('ProductID');
fix.detectChanges();
grid.moveColumn(colUnitsInStock, colProductID, DropPosition.BeforeDropTarget);
tick();
fix.detectChanges();
const summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['10', '0', '20,000', '39,004', '3,900.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['10', 'May 17, 1990', 'Dec 25, 2025']);
}));
it('Hiding: should hide summary row when a column which has summary is hidded', fakeAsync(() => {
grid.getColumnByName('ProductName').hasSummary = false;
grid.getColumnByName('InStock').hasSummary = false;
grid.getColumnByName('OrderDate').hasSummary = false;
// grid.recalculateSummaries();
fix.detectChanges();
tick(100);
let summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['10', '0', '20,000', '39,004', '3,900.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, [], []);
grid.getColumnByName('UnitsInStock').hidden = true;
tick();
fix.detectChanges();
summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
expect(summaryRow).toBeNull();
expect(grid.hasSummarizedColumns).toBe(false);
grid.getColumnByName('UnitsInStock').hidden = false;
tick();
fix.detectChanges();
summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
expect(summaryRow).toBeDefined();
expect(grid.hasSummarizedColumns).toBe(true);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['10', '0', '20,000', '39,004', '3,900.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, [], []);
}));
it('Hiding: should recalculate summary area after column with enabled summary is hidden', fakeAsync(() => {
grid.summaryRowHeight = undefined;
let tFoot = GridFunctions.getGridFooterWrapper(fix).nativeElement.getBoundingClientRect().height;
expect(tFoot).toEqual(5 * grid.defaultSummaryHeight);
grid.getColumnByName('UnitsInStock').hidden = true;
tick();
fix.detectChanges();
tFoot = GridFunctions.getGridFooterWrapper(fix).nativeElement.getBoundingClientRect().height;
expect(tFoot).toEqual(3 * grid.defaultSummaryHeight);
expect(grid.hasSummarizedColumns).toBe(true);
let summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Earliest', 'Latest'], ['10', 'May 17, 1990', 'Dec 25, 2025']);
grid.getColumnByName('UnitsInStock').hidden = false;
grid.summaryRowHeight = 0;
tick();
fix.detectChanges();
expect(grid.hasSummarizedColumns).toBe(true);
tFoot = GridFunctions.getGridFooterWrapper(fix).nativeElement.getBoundingClientRect().height;
expect(tFoot).toEqual(5 * grid.defaultSummaryHeight);
summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['10', '0', '20,000', '39,004', '3,900.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['10', 'May 17, 1990', 'Dec 25, 2025']);
}));
it('CRUD: should recalculate summary functions rowAdded', () => {
grid.addRow({
ProductID: 11, ProductName: 'Belgian Chocolate', InStock: true, UnitsInStock: 99000, OrderDate: new Date('2018-03-01')
});
fix.detectChanges();
const summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['11']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['11']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['11', '0', '99,000', '138,004', '12,545.818']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['11', 'May 17, 1990', 'Dec 25, 2025']);
});
it('CRUD: should recalculate summary functions rowDeleted', () => {
grid.deleteRow(9);
fix.detectChanges();
const summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['9']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['9']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['9', '0', '20,000', '32,006', '3,556.222']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['9', 'May 17, 1990', 'Mar 1, 2018']);
});
it('CRUD: should recalculate summary functions on updateRow', () => {
const productNameCell = grid.getCellByColumn(0, 'ProductName');
const unitsInStockCell = grid.getCellByColumn(0, 'UnitsInStock');
expect(productNameCell.value).toBe('Chai');
expect(unitsInStockCell.value).toBe(2760);
grid.updateRow({
ProductID: 1, ProductName: 'Spearmint', InStock: true, UnitsInStock: 510000, OrderDate: new Date('1984-03-21')
}, 1);
fix.detectChanges();
expect(productNameCell.value).toBe('Spearmint');
expect(unitsInStockCell.value).toBe(510000);
const summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['10', '0', '510,000', '546,244', '54,624.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['10', 'Mar 21, 1984', 'Dec 25, 2025']);
});
it('CRUD: should recalculate summary functions on cell update', () => {
const unitsInStockCell = grid.getCellByColumn(0, 'UnitsInStock');
unitsInStockCell.update(99000);
fix.detectChanges();
let summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['10', '0', '99,000', '135,244', '13,524.4']);
unitsInStockCell.update(-12);
fix.detectChanges();
summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['10', '-12', '20,000', '36,232', '3,623.2']);
});
it('Pinning: should display all active summaries after column pinning', () => {
grid.pinColumn('UnitsInStock');
grid.pinColumn('ProductID');
fix.detectChanges();
const summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['10', '0', '20,000', '39,004', '3,900.4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 2, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3, ['Count'], ['10']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Earliest', 'Latest'], ['10', 'May 17, 1990', 'Dec 25, 2025']);
});
it('CRUD: Apply filter and update cell', () => {
grid.filter('ProductName', 'ch', IgxStringFilteringOperand.instance().condition('contains'));
fix.detectChanges();
let summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['4']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['4', '52', '20,000', '29,810', '7,452.5']);
const cell = grid.getCellByColumn(2, 'ProductName');
cell.update('Teatime Cocoa Biscuits');
fix.detectChanges();
summaryRow = fix.debugElement.query(By.css(SUMMARY_ROW));
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1, ['Count'], ['3']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 3,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['3', '52', '20,000', '22,812', '7,604']);
});
});
});
describe('Keyboard Navigation', () => {
let fix;
let grid: IgxGridComponent;
beforeEach(() => {
fix = TestBed.createComponent(SummariesGroupByComponent);
grid = fix.componentInstance.grid;
setupGridScrollDetection(fix, grid);
grid.width = '800px';
grid.height = '800px';
fix.detectChanges();
});
afterEach(() => {
clearGridSubs();
});
it('should be able to select summaries with arrow keys', async () => {
const gridFooter = GridFunctions.getGridFooter(fix);
let summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
GridSummaryFunctions.focusSummaryCell(fix, summaryRow, 0);
for (let i = 0; i < 5; i++) {
GridSummaryFunctions.verifySummaryCellActive(fix, summaryRow, i);
UIInteractions.triggerEventHandlerKeyDown('ArrowRight', gridFooter);
await wait(DEBOUNCETIME);
fix.detectChanges();
}
summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '25', '50', '293', '36.625']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 5, ['Count'], ['8']);
for (let i = 5; i > 0; i--) {
GridSummaryFunctions.verifySummaryCellActive(fix, summaryRow, i);
UIInteractions.triggerEventHandlerKeyDown('ArrowLeft', gridFooter);
await wait(DEBOUNCETIME);
fix.detectChanges();
}
summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 0, [], []);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 1,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '17', '847', '2,188', '273.5']);
});
it('should be able to navigate with Arrow keys and Ctrl', async () => {
const gridFooter = GridFunctions.getGridFooter(fix);
let summaryRow = GridSummaryFunctions.getRootSummaryRow(fix);
GridSummaryFunctions.focusSummaryCell(fix, summaryRow, 1);
UIInteractions.triggerEventHandlerKeyDown('ArrowRight', gridFooter, false, false, true);
await wait(DEBOUNCETIME);
fix.detectChanges();
GridSummaryFunctions.verifySummaryCellActive(fix, summaryRow, 5);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4,
['Count', 'Min', 'Max', 'Sum', 'Avg'], ['8', '25', '50', '293', '36.625']);
GridSummaryFunctions.verifyColumnSummaries(summaryRow, 5, ['Count'], ['8']);
UIInteractions.triggerEventHandlerKeyDown('ArrowLeft', gridFooter, false, false, true);
await wait(DEBOUNCETIME);
fix.detectChanges();
GridSummaryFunctio