igniteui-angular-sovn
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
458 lines (378 loc) • 19.5 kB
text/typescript
import { Component, ViewChild, OnInit, NgZone, DebugElement } from '@angular/core';
import { TestBed, fakeAsync } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { IgxGridComponent } from './public_api';
import { UIInteractions, wait } from '../../test-utils/ui-interactions.spec';
import { configureTestSuite } from '../../test-utils/configure-suite';
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
import { HammerGesturesManager } from '../../core/touch';
import { PlatformUtil } from '../../core/utils';
import { VirtualGridComponent, NoScrollsComponent,
NoColumnWidthGridComponent, IgxGridDateTimeColumnComponent } from '../../test-utils/grid-samples.spec';
import { GridFunctions } from '../../test-utils/grid-functions.spec';
import { TestNgZone } from '../../test-utils/helper-utils.spec';
import { CellType } from '../common/grid.interface';
import { NgFor } from '@angular/common';
import { IGridCellEventArgs, IgxColumnComponent } from '../public_api';
describe('IgxGrid - Cell component #grid', () => {
describe('Test events', () => {
let fix;
let grid: IgxGridComponent;
let cellElem: DebugElement;
let firstCell: CellType;
let firstCellElem: CellType;
configureTestSuite((() => {
return TestBed.configureTestingModule({
imports: [NoopAnimationsModule, NoScrollsComponent]
});
}));
beforeEach(() => {
fix = TestBed.createComponent(NoScrollsComponent);
fix.detectChanges();
grid = fix.componentInstance.grid;
cellElem = GridFunctions.getRowCells(fix, 0)[0];
firstCell = grid.getCellByColumn(0, 'ID');
firstCellElem = grid.gridAPI.get_cell_by_index(0, 'ID');
});
it('@Input properties and getters', () => {
expect(firstCell.column.index).toEqual(grid.columnList.first.index);
expect(firstCell.row.index).toEqual(grid.rowList.first.index);
expect(firstCell.grid).toBe(grid);
expect(firstCell.active).toBeFalse();
expect(firstCell.selected).toBeFalse();
expect(firstCell.editMode).toBeFalse();
expect(firstCell.editValue).toBeUndefined();
expect(firstCellElem.nativeElement).toBeDefined();
expect(firstCellElem.nativeElement.textContent).toMatch('1');
expect(firstCellElem.readonly).toBe(true);
});
it('selection and selection events', () => {
expect(cellElem.nativeElement.getAttribute('aria-selected')).toMatch('false');
spyOn(grid.selected, 'emit').and.callThrough();
UIInteractions.simulateClickAndSelectEvent(cellElem);
const args: IGridCellEventArgs = {
cell: grid.getCellByColumn(0, 'ID'),
event: jasmine.anything() as any
};
fix.detectChanges();
expect(grid.selected.emit).toHaveBeenCalledWith(args);
expect(firstCell.selected).toBe(true);
expect(cellElem.nativeElement.getAttribute('aria-selected')).toMatch('true');
firstCell.selected = !firstCell.selected;
expect(firstCell.selected).toBe(false);
firstCell.selected = !firstCell.selected;
expect(firstCell.selected).toBe(true);
});
it('Should not emit selection event for already selected cell', () => {
grid.getColumnByName('ID').editable = true;
fix.detectChanges();
spyOn(grid.selected, 'emit').and.callThrough();
UIInteractions.simulateClickAndSelectEvent(cellElem);
fix.detectChanges();
expect(grid.selected.emit).toHaveBeenCalledTimes(1);
const gridContent = GridFunctions.getGridContent(fix);
UIInteractions.triggerEventHandlerKeyDown('Enter', gridContent);
fix.detectChanges();
UIInteractions.triggerEventHandlerKeyDown('Escape', gridContent);
fix.detectChanges();
expect(grid.selected.emit).toHaveBeenCalledTimes(1);
});
it('Should trigger onCellClick event when click into cell', () => {
spyOn(grid.cellClick, 'emit').and.callThrough();
const event = new Event('click');
firstCellElem.nativeElement.dispatchEvent(event);
const args: IGridCellEventArgs = {
cell: grid.getCellByColumn(0, 'ID'),
event
};
fix.detectChanges();
expect(grid.cellClick.emit).toHaveBeenCalledTimes(1);
expect(grid.cellClick.emit).toHaveBeenCalledWith(args);
});
it('Should trigger doubleClick event', () => {
grid.columnList.get(0).editable = true;
fix.detectChanges();
spyOn(grid.doubleClick, 'emit').and.callThrough();
cellElem.triggerEventHandler('dblclick', new Event('dblclick'));
fix.detectChanges();
expect(grid.doubleClick.emit).toHaveBeenCalledTimes(1);
cellElem.triggerEventHandler('dblclick', new Event('dblclick'));
fix.detectChanges();
expect(grid.doubleClick.emit).toHaveBeenCalledTimes(2);
});
it('Should trigger contextMenu event when right click into cell', () => {
spyOn(grid.contextMenu, 'emit').and.callThrough();
const event = new Event('contextmenu');
cellElem.nativeElement.dispatchEvent(event);
const args: IGridCellEventArgs = {
cell: grid.getCellByColumn(0, 'ID'),
event
};
fix.detectChanges();
expect(grid.contextMenu.emit).toHaveBeenCalledTimes(1);
expect(grid.contextMenu.emit).toHaveBeenCalledWith(args);
});
it('Should trigger doubleClick event when double click into cell', () => {
spyOn(grid.doubleClick, 'emit').and.callThrough();
const event = new Event('dblclick');
spyOn(event, 'preventDefault');
cellElem.nativeElement.dispatchEvent(event);
const args: IGridCellEventArgs = {
cell: grid.getCellByColumn(0, 'ID'),
event
};
fix.detectChanges();
expect(event.preventDefault).not.toHaveBeenCalled();
expect(grid.doubleClick.emit).toHaveBeenCalledWith(args);
});
});
describe('Cells in virtualized grid ', () => {
let fix;
let grid: IgxGridComponent;
configureTestSuite((() => {
return TestBed.configureTestingModule({
imports: [NoopAnimationsModule, VirtualGridComponent],
providers: [{ provide: NgZone, useFactory: () => new TestNgZone() }]
});
}));
beforeEach(fakeAsync(() => {
fix = TestBed.createComponent(VirtualGridComponent);
fix.detectChanges();
grid = fix.componentInstance.grid;
}));
it('should fit last cell in the available display container when there is vertical scroll.', () => {
const rows = grid.rowList;
rows.forEach((item) => {
expect(item.cells.last.width).toEqual('200px');
});
});
it('should use default column width for cells with width in %.', () => {
fix.componentInstance.defaultWidth = '25%';
fix.detectChanges();
const rows = grid.rowList;
rows.forEach((item) => {
expect(item.cells.last.width).toEqual('25%');
});
});
it('should fit last cell in the available display container when there is vertical and horizontal scroll.', (async () => {
fix.componentInstance.columns = fix.componentInstance.generateCols(100);
fix.componentInstance.data = fix.componentInstance.generateData(1000);
await wait();
fix.detectChanges();
const firsCell = GridFunctions.getRowCells(fix, 1)[0];
expect(GridFunctions.getValueFromCellElement(firsCell)).toEqual('0');
fix.componentInstance.scrollLeft(999999);
await wait();
// This won't work always in debugging mode due to the angular native events behavior, so errors are expected
fix.detectChanges();
const cells = GridFunctions.getRowCells(fix, 1);
const lastCell = cells[cells.length - 1];
expect(GridFunctions.getValueFromCellElement(lastCell)).toEqual('990');
// Calculate where the end of the cell is. Relative left position should equal the grid calculated width
expect(lastCell.nativeElement.getBoundingClientRect().left +
lastCell.nativeElement.offsetWidth +
grid.scrollSize).toEqual(parseInt(grid.width, 10));
}));
it('should not reduce the width of last pinned cell when there is vertical scroll.', () => {
const columns = grid.columnList;
const lastCol: IgxColumnComponent = columns.last;
lastCol.pinned = true;
fix.detectChanges();
lastCol.cells.forEach((cell) => {
expect(cell.width).toEqual('200px');
});
const rows = fix.componentInstance.grid.rowList;
rows.forEach((item) => {
expect(item.cells.last.width).toEqual('200px');
});
});
it('should not make last column smaller when vertical scrollbar is on the right of last cell', () => {
fix.componentInstance.columns = fix.componentInstance.generateCols(4, '30px');
fix.componentInstance.data = fix.componentInstance.generateData(10);
fix.detectChanges();
const lastColumnCells = grid.columnList.get(grid.columnList.length - 1).cells;
lastColumnCells.forEach((item) => {
expect(item.width).toEqual('30px');
});
});
it('should not make last column smaller when vertical scrollbar is on the left of last cell', async () => {
fix.componentInstance.columns = fix.componentInstance.generateCols(4, '500px');
fix.componentInstance.data = fix.componentInstance.generateData(10);
fix.detectChanges();
const scrollbar = grid.headerContainer.getScroll();
scrollbar.scrollLeft = 10000;
fix.detectChanges();
await wait();
const lastColumnCells = grid.columnList.get(grid.columnList.length - 1).cells;
fix.detectChanges();
lastColumnCells.forEach((item) => {
expect(item.width).toEqual('500px');
});
});
it('Should not clear selected cell when scrolling with mouse wheel', (async () => {
const cell = grid.gridAPI.get_cell_by_index(3, 'value');
UIInteractions.simulateClickAndSelectEvent(cell);
fix.detectChanges();
const displayContainer = grid.verticalScrollContainer.dc.instance._viewContainer.element.nativeElement;
await UIInteractions.simulateWheelEvent(displayContainer, 0, 200);
fix.detectChanges();
await wait(16);
const gridContent = GridFunctions.getGridContent(fix);
UIInteractions.triggerEventHandlerKeyDown('arrowup', gridContent);
fix.detectChanges();
await wait(30);
expect(grid.getCellByColumn(2, 'value').selected).toBeTruthy();
}));
});
describe('iOS tests', () => {
configureTestSuite((() => {
return TestBed.configureTestingModule({
imports: [NoopAnimationsModule, NoScrollsComponent]
});
}));
it('Should not attach doubletap handler for non-iOS', () => {
const addListenerSpy = spyOn(HammerGesturesManager.prototype, 'addEventListener');
const platformUtil: PlatformUtil = TestBed.inject(PlatformUtil);
const oldIsIOS = platformUtil.isIOS;
platformUtil.isIOS = false;
const fix = TestBed.createComponent(NoScrollsComponent);
fix.detectChanges();
// spyOnProperty(PlatformUtil.prototype, 'isIOS').and.returnValue(false);
expect(addListenerSpy).not.toHaveBeenCalled();
platformUtil.isIOS = oldIsIOS;
});
it('Should handle doubletap on iOS, trigger doubleClick event', () => {
const addListenerSpy = spyOn(HammerGesturesManager.prototype, 'addEventListener');
const platformUtil: PlatformUtil = TestBed.inject(PlatformUtil);
const oldIsIOS = platformUtil.isIOS;
platformUtil.isIOS = true;
const fix = TestBed.createComponent(NoScrollsComponent);
fix.detectChanges();
const grid = fix.componentInstance.grid;
const firstCellElem = grid.gridAPI.get_cell_by_index(0, 'ID');
// should attach 'doubletap'
expect(addListenerSpy.calls.count()).toBeGreaterThan(1);
expect(addListenerSpy).toHaveBeenCalledWith(firstCellElem.nativeElement, 'doubletap', firstCellElem.onDoubleClick,
{ cssProps: {} as any });
spyOn(grid.doubleClick, 'emit').and.callThrough();
const event = {
type: 'doubletap',
preventDefault: jasmine.createSpy('preventDefault')
};
firstCellElem.onDoubleClick(event as any);
const args: IGridCellEventArgs = {
cell: grid.getCellByColumn(0, 'ID'),
event
} as any;
fix.detectChanges();
expect(event.preventDefault).toHaveBeenCalled();
expect(grid.doubleClick.emit).toHaveBeenCalledWith(args);
platformUtil.isIOS = oldIsIOS;
});
});
describe('No column widths', () => {
configureTestSuite((() => {
return TestBed.configureTestingModule({
imports: [NoopAnimationsModule, NoColumnWidthGridComponent]
});
}));
it('should not make last column width 0 when no column width is set', () => {
const fix = TestBed.createComponent(NoColumnWidthGridComponent);
fix.detectChanges();
const columns = fix.componentInstance.grid.columns;
const lastCol: IgxColumnComponent = columns[columns.length - 1];
lastCol._cells.forEach((cell) => {
expect(cell.nativeElement.clientWidth).toBeGreaterThan(100);
});
});
});
describe('Cells styles', () => {
configureTestSuite((() => {
return TestBed.configureTestingModule({
imports: [NoopAnimationsModule, ConditionalCellStyleTestComponent]
});
}));
it('should be able to conditionally style cells', fakeAsync(() => {
const fixture = TestBed.createComponent(ConditionalCellStyleTestComponent);
fixture.detectChanges();
const grid = fixture.componentInstance.grid;
grid.getColumnByName('UnitsInStock')._cells.forEach((cell) => {
expect(cell.nativeElement.classList).toContain('test1');
});
const indexColCells = grid.getColumnByName('ProductID')._cells;
expect(indexColCells[3].nativeElement.classList).not.toContain('test');
expect(indexColCells[4].nativeElement.classList).toContain('test2');
expect(indexColCells[5].nativeElement.classList).toContain('test');
expect(indexColCells[6].nativeElement.classList).toContain('test');
expect(grid.getColumnByName('ProductName')._cells[4].nativeElement.classList).toContain('test2');
expect(grid.getColumnByName('InStock')._cells[4].nativeElement.classList).toContain('test2');
expect(grid.getColumnByName('OrderDate')._cells[4].nativeElement.classList).toContain('test2');
}));
});
describe('Cell properties', () => {
configureTestSuite((() => {
return TestBed.configureTestingModule({
imports: [NoopAnimationsModule, IgxGridDateTimeColumnComponent]
});
}));
it('verify that value of the cell title is correctly', fakeAsync(() => {
const fixture = TestBed.createComponent(IgxGridDateTimeColumnComponent);
fixture.detectChanges();
const grid = fixture.componentInstance.grid;
const receiveTime = grid.getColumnByName('ReceiveTime');
expect(receiveTime._cells[0].title).toEqual('8:37:11 AM');
expect(receiveTime._cells[5].title).toEqual('12:47:42 PM');
const product = grid.getColumnByName('ProductName');
expect(product._cells[2].title).toEqual('Antons Cajun Seasoning');
expect(product._cells[6].title).toEqual('Queso Cabrales');
product.formatter = fixture.componentInstance.testFormatter;
fixture.detectChanges();
expect(product._cells[2].title).toEqual('testAntons Cajun Seasoning');
expect(product._cells[6].title).toEqual('testQueso Cabrales');
}));
});
});
({
template: `
<igx-grid #grid [data]="data" [primaryKey]="'ProductID'" [width]="'900px'" [height]="'500px'" rowSelection = "multiple" [moving]="true">
<igx-column *ngFor="let c of columns" [field]="c.field"
[header]="c.field"
[width]="c.width"
[groupable]="true"
[resizable]="true"
[sortable]="true"
[filterable]="true"
[editable]="true"
[cellClasses]="c.cellClasses">
</igx-column>
</igx-grid>`,
styleUrls: ['../../test-utils/grid-cell-style-testing.scss'],
standalone: true,
imports: [IgxGridComponent, IgxColumnComponent, NgFor]
})
export class ConditionalCellStyleTestComponent implements OnInit {
('grid', { static: true }) public grid: IgxGridComponent;
public data: Array<any>;
public columns: Array<any>;
public cellClasses;
public cellClasses1;
public callback = (rowData: any, columnKey: any) => rowData[columnKey] >= 5;
public callback1 = (rowData: any) => rowData[this.grid.primaryKey] === 5;
public ngOnInit(): void {
this.cellClasses = {
test: this.callback,
test2: this.callback1
};
this.cellClasses1 = {
test2: this.callback1
};
this.columns = [
{ field: 'ProductID', width: 100, cellClasses: this.cellClasses },
{ field: 'ProductName', width: 200, cellClasses: this.cellClasses1 },
{ field: 'InStock', width: 150, cellClasses: this.cellClasses1 },
{ field: 'UnitsInStock', width: 150, cellClasses: { test1: true } },
{ field: 'OrderDate', width: 150, cellClasses: this.cellClasses1 }
];
this.data = SampleTestData.foodProductDataExtended();
}
}