UNPKG

igniteui-angular-sovn

Version:

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

1,224 lines (1,039 loc) 51.3 kB
import { TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { IgxGridComponent } from './public_api'; import { BasicGridSearchComponent } from '../../test-utils/grid-base-components.spec'; import { SampleTestData } from '../../test-utils/sample-test-data.spec'; import { GridWithAvatarComponent, GroupableGridSearchComponent, ScrollableGridSearchComponent } from '../../test-utils/grid-samples.spec'; import { IForOfState } from '../../directives/for-of/for_of.directive'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; import { DefaultSortingStrategy, SortingDirection } from '../../data-operations/sorting-strategy'; import { configureTestSuite } from '../../test-utils/configure-suite'; import { wait, UIInteractions } from '../../test-utils/ui-interactions.spec'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { GridColumnDataType } from '../../data-operations/data-util'; import { clearGridSubs, setupGridScrollDetection } from '../../test-utils/helper-utils.spec'; import { IgxTextHighlightDirective } from '../../directives/text-highlight/text-highlight.directive'; import { GridFunctions } from '../../test-utils/grid-functions.spec'; describe('IgxGrid - search API #grid', () => { const CELL_CSS_CLASS = '.igx-grid__td'; const HIGHLIGHT_CSS_CLASS = '.igx-highlight'; const HIGHLIGHT_ACTIVE_CSS_CLASS = '.igx-highlight__active'; let fix; let component; let grid: IgxGridComponent; let fixNativeElement; configureTestSuite(); beforeAll(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ NoopAnimationsModule, BasicGridSearchComponent, GridWithAvatarComponent, GroupableGridSearchComponent, ScrollableGridSearchComponent ] }).compileComponents(); })) describe('BasicGrid - ', () => { beforeEach(() => { fix = TestBed.createComponent(BasicGridSearchComponent); fix.componentInstance.data = SampleTestData.personJobDataFull(); fix.detectChanges(); component = fix.componentInstance; grid = component.grid; fixNativeElement = fix.debugElement.nativeElement; }); it('Should clear all highlights', () => { const count = grid.findNext('software'); let spans = getSpans(); expect(spans.length).toBe(5); expect(count).toBe(5); grid.clearSearch(); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(0); }); it('findNext highlights the correct cells', () => { let count = grid.findNext('developer'); fix.detectChanges(); const spans = getSpans(); expect(spans.length).toBe(4); expect(count).toBe(4); verifyActiveSpan(0); count = grid.findNext('developer'); fix.detectChanges(); verifyActiveSpan(1); count = grid.findNext('developer'); fix.detectChanges(); verifyActiveSpan(2); count = grid.findNext('developer'); fix.detectChanges(); verifyActiveSpan(3); count = grid.findNext('developer'); fix.detectChanges(); verifyActiveSpan(0); }); it('findPrev highlights the correct cells', () => { let count = grid.findNext('developer'); const spans = getSpans(); expect(spans.length).toBe(4); expect(count).toBe(4); verifyActiveSpan(0); count = grid.findPrev('developer'); verifyActiveSpan(3); count = grid.findPrev('developer'); verifyActiveSpan(2); count = grid.findPrev('developer'); verifyActiveSpan(1); count = grid.findPrev('developer'); verifyActiveSpan(0); }); it('findPrev and findNext work properly for case sensitive searches', () => { grid.gridAPI.get_cell_by_index(4, 'JobTitle').update('Senior Software DEVELOPER'); fix.detectChanges(); let count = grid.findNext('Developer', true); fix.detectChanges(); let spans = getSpans(); expect(spans.length).toBe(3); expect(count).toBe(3); verifyActiveSpan(0); count = grid.findPrev('Developer', true); fix.detectChanges(); verifyActiveSpan(2); count = grid.findNext('Developer', true); fix.detectChanges(); verifyActiveSpan(0); count = grid.findNext('Developer', true); fix.detectChanges(); verifyActiveSpan(1); count = grid.findPrev('developer', true); fix.detectChanges(); spans = getSpans(); const activeSpan = getActiveSpan(); expect(activeSpan).toBe(null); expect(count).toBe(0); expect(spans.length).toBe(0); }); it('findNext and findPrev highlight nothing when there is no exact match, regardless of case sensitivity.', () => { let count = grid.findNext('Developer', false, true); let spans = getSpans(); expect(spans.length).toBe(0); expect(count).toBe(0); count = grid.findNext('Developer', true, true); spans = getSpans(); expect(spans.length).toBe(0); expect(count).toBe(0); count = grid.findPrev('Developer', false, true); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(0); expect(count).toBe(0); count = grid.findPrev('Developer', true, true); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(0); expect(count).toBe(0); }); it('findNext and findPrev highlight only exact matches when searching by exact match', () => { let count = grid.findNext('Software Developer', false, false); fix.detectChanges(); let spans = getSpans(); expect(spans.length).toBe(4); expect(count).toBe(4); count = grid.findNext('Software Developer', false, true); fix.detectChanges(); verifyActiveSpan(0); spans = getSpans(); expect(spans.length).toBe(1); expect(count).toBe(1); count = grid.findPrev('Software Developer', false, false); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(4); expect(count).toBe(4); count = grid.findPrev('Software Developer', false, true); fix.detectChanges(); verifyActiveSpan(0); spans = getSpans(); expect(spans.length).toBe(1); expect(count).toBe(1); }); it('findNext and findPrev highlight only exact matches by respecting case sensitivity', () => { grid.gridAPI.get_cell_by_index(5, 'JobTitle').update('director of Dev operations'); fix.detectChanges(); // Case INsensitive and exact match let count = grid.findNext('director', false, true); fix.detectChanges(); let spans = getSpans(); verifyActiveSpan(0); expect(spans.length).toBe(2); expect(count).toBe(2); count = grid.findPrev('director', false, true); verifyActiveSpan(1); expect(spans.length).toBe(2); expect(count).toBe(2); // Case sensitive and exact match count = grid.findNext('director', true, true); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(0); expect(count).toBe(0); count = grid.findPrev('director', true, true); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(0); expect(count).toBe(0); }); it('Should update exact match highlights when filtering.', () => { grid.findNext('Software Developer', false, true); let activeHighlight = getActiveHighlight(); let highlights = getHighlights(); expect(highlights.length).toBe(1); verifyActiveHighlight(0); grid.filter('JobTitle', 'Associate', IgxStringFilteringOperand.instance().condition('contains')); fix.detectChanges(); activeHighlight = getActiveHighlight(); highlights = getHighlights(); expect(highlights.length).toBe(0); expect(activeHighlight).toBeNull(); grid.clearFilter('JobTitle'); fix.detectChanges(); }); it('Should update exact match highlights when clearing filter.', fakeAsync(() => { grid.filter('JobTitle', 'Associate', IgxStringFilteringOperand.instance().condition('contains')); tick(16); fix.detectChanges(); grid.findNext('Software Developer', false, true); let activeHighlight = getActiveHighlight(); let highlights = getHighlights(); expect(highlights.length).toBe(0); expect(activeHighlight).toBeNull(); grid.clearFilter('JobTitle'); tick(16); fix.detectChanges(); activeHighlight = getActiveHighlight(); highlights = getHighlights(); expect(highlights.length).toBe(1); verifyActiveHighlight(0); })); it('Should update the active highlight when sorting', () => { const allCells = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS)); const rv = allCells[6].nativeElement; const cell = grid.gridAPI.get_cell_by_index(0, 'JobTitle'); const searchString = 'assoc'; let activeHighlight = rv.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(activeHighlight !== null).toBeFalsy(); cell.column.sortable = true; grid.findNext(searchString); grid.findNext(searchString); grid.sort({ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true }); fix.detectChanges(); activeHighlight = rv.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); let highlights = rv.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); grid.sort({ fieldName: 'JobTitle', dir: SortingDirection.Desc, ignoreCase: true }); fix.detectChanges(); const scrolledCell = grid.gridAPI.get_cell_by_index(grid.data.length - 1, 'JobTitle').nativeElement; activeHighlight = scrolledCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); highlights = scrolledCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); }); xit('Should scroll properly when using paging', () => { fix.componentInstance.paging = true; grid.height = '240px'; grid.paginator.perPage = 7; fix.detectChanges(); const searchString = 'assoc'; grid.findNext(searchString); fix.detectChanges(); expect(grid.paginator.page).toBe(0); let activeHighlight = getActiveHighlight(); let highlights = getHighlights(); expect(activeHighlight).not.toBeNull(); expect(highlights.length).toBe(1); grid.findNext(searchString); fix.detectChanges(); expect(grid.paginator.page).toBe(1); activeHighlight = getActiveHighlight(); highlights = getHighlights(); expect(activeHighlight).not.toBeNull(); expect(highlights.length).toBe(1); grid.findPrev(searchString); fix.detectChanges(); expect(grid.paginator.page).toBe(0); activeHighlight = getActiveHighlight(); highlights = getHighlights(); expect(activeHighlight).not.toBeNull(); expect(highlights.length).toBe(1); }); it('Hidden columns shouldn\'t be part of the search', () => { grid.columnList.get(1).hidden = true; fix.detectChanges(); grid.findNext('casey'); const activeHighlight = getActiveHighlight(); const highlights = getHighlights(); expect(highlights.length).toBe(0); expect(activeHighlight).toBe(null); }); it('Search should honor the visible columns order', () => { grid.columnList.get(3).pinned = true; const cell = grid.gridAPI.get_cell_by_index(0, 'HireDate').nativeElement; grid.findNext('1'); const highlights = cell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(5); verifyActiveHighlight(0); }); it('Active highlight should be updated when a column is pinned/unpinned', () => { let cellName = grid.gridAPI.get_cell_by_index(0, 'Name').nativeElement; let highlights: NodeListOf<Element>; grid.findNext('casey'); cellName = grid.gridAPI.get_cell_by_index(0, 'Name').nativeElement; highlights = cellName.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); verifyActiveHighlight(0); grid.columnList.get(1).pinned = true; fix.detectChanges(); cellName = grid.gridAPI.get_cell_by_index(0, 'Name').nativeElement; highlights = cellName.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); verifyActiveHighlight(0); grid.columnList.get(1).pinned = false; fix.detectChanges(); cellName = grid.gridAPI.get_cell_by_index(0, 'Name').nativeElement; highlights = cellName.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); verifyActiveHighlight(0); }); it('Active highlight should be updated when a column is hidden/shown', () => { let cellName = grid.gridAPI.get_cell_by_index(0, 'Name').nativeElement; let highlights: NodeListOf<Element>; grid.findNext('casey'); highlights = cellName.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); verifyActiveHighlight(0); grid.columnList.get(0).hidden = true; fix.detectChanges(); cellName = grid.gridAPI.get_cell_by_index(0, 'Name').nativeElement; highlights = cellName.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); verifyActiveHighlight(0); grid.columnList.get(0).hidden = false; fix.detectChanges(); cellName = grid.gridAPI.get_cell_by_index(0, 'Name').nativeElement; highlights = cellName.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); verifyActiveHighlight(0); }); it('Highlights should be updated after a column is hidden and another column is already hidden', () => { grid.columnList.get(0).hidden = true; fix.detectChanges(); grid.findNext('an'); fix.detectChanges(); let highlights = getHighlights(); expect(highlights.length).toBe(3); verifyActiveHighlight(0); expect(grid.lastSearchInfo.matchInfoCache.length).toBe(3); expect(grid.lastSearchInfo.activeMatchIndex).toBe(0); grid.columnList.get(1).hidden = true; fix.detectChanges(); highlights = getHighlights(); expect(highlights.length).toBe(1); verifyActiveHighlight(0); expect(grid.lastSearchInfo.matchInfoCache.length).toBe(1); expect(grid.lastSearchInfo.activeMatchIndex).toBe(0); }); it('Highlight should be updated when a column is hidden/shown and columns have different data types', () => { grid.columnList.get(0).dataType = GridColumnDataType.Number; fix.detectChanges(); let cell = grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement; grid.findNext('1'); let highlights = cell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); verifyActiveHighlight(0); grid.columnList.get(0).hidden = true; fix.detectChanges(); grid.columnList.get(0).hidden = false; fix.detectChanges(); cell = grid.gridAPI.get_cell_by_index(0, 'ID').nativeElement; highlights = cell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(cell.innerText).toBe('1'); }); it('Highlight should be updated when a column is hidden and there are other hidden columns', () => { grid.columnList.get(1).hidden = true; fix.detectChanges(); let finds = grid.findNext('Director'); expect(finds).toEqual(2); grid.columnList.get(2).hidden = true; fix.detectChanges(); finds = grid.findNext('Director'); expect(finds).toEqual(0); }); it('Clear filter properly updates the highlights', () => { let gilbertoDirectorCell = grid.gridAPI.get_cell_by_index(1, 'JobTitle').nativeElement; let tanyaDirectorCell = grid.gridAPI.get_cell_by_index(2, 'JobTitle').nativeElement; grid.findNext('director'); fix.detectChanges(); gilbertoDirectorCell = grid.gridAPI.get_cell_by_index(1, 'JobTitle').nativeElement; let activeHighlight = gilbertoDirectorCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); let highlights = gilbertoDirectorCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); verifyActiveHighlight(0); grid.filter('Name', 'Tanya', IgxStringFilteringOperand.instance().condition('contains')); fix.detectChanges(); tanyaDirectorCell = grid.gridAPI.get_cell_by_index(0, 'JobTitle').nativeElement; activeHighlight = tanyaDirectorCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); highlights = tanyaDirectorCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); grid.clearFilter(); fix.detectChanges(); tanyaDirectorCell = grid.gridAPI.get_cell_by_index(2, 'JobTitle').nativeElement; activeHighlight = tanyaDirectorCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); highlights = tanyaDirectorCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); grid.findNext('Director'); fix.detectChanges(); gilbertoDirectorCell = grid.gridAPI.get_cell_by_index(1, 'JobTitle').nativeElement; activeHighlight = gilbertoDirectorCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); highlights = gilbertoDirectorCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); }); it('Unsearchable column should not interfere with active highlight for other columns on its right', () => { grid.columnList.get(1).searchable = false; grid.columnList.get(3).searchable = false; fix.detectChanges(); const count = grid.findNext('Software'); const spans = getSpans(); expect(spans.length).toBe(5); expect(count).toBe(5); verifyActiveSpan(0); grid.findNext('Software'); verifyActiveSpan(1); }); it('Highlights should be properly updated when a row is deleted', () => { // Specify primaryKey so record deletion is allowed. grid.primaryKey = 'ID'; let jackSoftwareCell = grid.gridAPI.get_cell_by_index(3, 'JobTitle').nativeElement; let celiaSoftwareCell = grid.gridAPI.get_cell_by_index(4, 'JobTitle').nativeElement; let leslieSoftwareCell = grid.gridAPI.get_cell_by_index(8, 'JobTitle').nativeElement; grid.findNext('software'); jackSoftwareCell = grid.gridAPI.get_cell_by_index(3, 'JobTitle').nativeElement; let activeHighlight = jackSoftwareCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); let highlights = jackSoftwareCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); grid.deleteRow(4); fix.detectChanges(); celiaSoftwareCell = grid.gridAPI.get_cell_by_index(3, 'JobTitle').nativeElement; activeHighlight = celiaSoftwareCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); highlights = celiaSoftwareCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); grid.findPrev('software'); leslieSoftwareCell = grid.gridAPI.get_cell_by_index(7, 'JobTitle').nativeElement; activeHighlight = leslieSoftwareCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); highlights = leslieSoftwareCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); }); it('Highlights should be properly updated when a row is added', () => { const tanyaDirectorCell = grid.gridAPI.get_cell_by_index(2, 'JobTitle').nativeElement; grid.findNext('director'); grid.findNext('director'); let activeHighlight = tanyaDirectorCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); let highlights = tanyaDirectorCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); grid.addRow({ ID: 11, Name: 'John Doe', JobTitle: 'Director', HireDate: new Date() }); fix.detectChanges(); activeHighlight = tanyaDirectorCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); highlights = tanyaDirectorCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); grid.findNext('director'); const johnDirectorCell = grid.gridAPI.get_cell_by_index(grid.rowList.length - 1, 'JobTitle').nativeElement; activeHighlight = johnDirectorCell.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); highlights = johnDirectorCell.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); }); it('Active highlight should be updated when filtering is applied', () => { grid.findNext('developer'); grid.filter('JobTitle', 'Associate', IgxStringFilteringOperand.instance().condition('contains')); fix.detectChanges(); const highlights = getHighlights(); expect(highlights.length).toBe(2); verifyActiveHighlight(0); }); it('Active highlight should be preserved when all rows are filtered out', () => { grid.height = '500px'; fix.detectChanges(); grid.findNext('casey'); let highlights = getHighlights(); expect(highlights.length).toBe(1); grid.filter('Name', 'zxxz', IgxStringFilteringOperand.instance().condition('contains')); fix.detectChanges(); let activeHighlight = getActiveHighlight(); highlights = getHighlights(); expect(highlights.length).toBe(0); expect(activeHighlight).toBeNull(); grid.clearFilter('Name'); fix.detectChanges(); activeHighlight = getActiveHighlight(); highlights = getHighlights(); expect(highlights.length).toBe(1); verifyActiveHighlight(0); }); it('Active highlight should be preserved when a column is moved', () => { grid.findNext('casey'); const columns = grid.columnList.toArray(); grid.moveColumn(columns[0], columns[1]); fix.detectChanges(); const highlights = getHighlights(); expect(highlights.length).toBe(1); verifyActiveHighlight(0); }); it('Should exit edit mode and search a cell', () => { const cell = grid.getCellByColumn(0, 'Name'); cell.column.editable = true; fix.detectChanges(); cell.editMode = true; fix.detectChanges(); expect(cell.editMode).toBeTruthy(); grid.findNext('casey'); //grid.gridAPI.get_cell_by_index(0, 'Name').cdr.detectChanges(); grid.gridAPI.get_cell_by_index(0, 'Name'); grid.cdr.detectChanges(); const highlights = grid.gridAPI.get_cell_by_index(0, 'Name').nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(cell.editMode).toBeFalsy(); expect(highlights.length).toBe(1); verifyActiveHighlight(0); const nextCell = grid.gridAPI.get_cell_by_index(0, 'JobTitle').nativeElement; nextCell.dispatchEvent(new Event('click')); fix.detectChanges(); expect(grid.gridAPI.get_cell_by_index(0, 'Name').nativeElement.innerText.trim()).toBe('Casey Houston'); }); it('Search should not change the cell\'s value', () => { grid.findNext('12'); const rowIndexes = [1, 3, 4, 5]; rowIndexes.forEach((ind) => { const cell = grid.gridAPI.get_cell_by_index(ind, 'HireDate'); const highlights = cell.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); const activeHighlight = cell.nativeElement.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); const cellChildren = cell.nativeElement.children as HTMLCollection; // Check whether search does not change the cell's value expect(cellChildren.length).toBe(2); expect(cell.nativeElement.innerText.trim()).toBe(cell.value); expect((cellChildren[0] as HTMLElement).hidden).toBeTruthy(); expect((cellChildren[1] as HTMLElement).hidden).toBeFalsy(); expect(highlights.length).toBe(1); if (ind === 1) { verifyActiveHighlight(0); } else { expect(activeHighlight).toBeNull(); } expect((highlights[0] as HTMLElement).innerText).toEqual('12'); }); }); it('Search should close row edit mode', () => { grid.primaryKey = 'ID'; grid.rowEditable = true; grid.getColumnByName('Name').editable = true; grid.cdr.detectChanges(); fix.detectChanges(); const row = grid.getRowByIndex(0); const cell = grid.gridAPI.get_cell_by_index(0, 'Name'); grid.findNext('Casey'); grid.cdr.detectChanges(); fix.detectChanges(); let highlights = cell.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(row.inEditMode).toBe(false); cell.nativeElement.dispatchEvent(new Event('dblclick')); fix.detectChanges(); expect(row.inEditMode).toBe(true); let cellInput = null; cellInput = cell.nativeElement.querySelector('[igxinput]'); cellInput.value = 'newCellValue'; cellInput.dispatchEvent(new Event('input')); fix.detectChanges(); grid.findNext('Casey'); grid.cdr.detectChanges(); fix.detectChanges(); highlights = cell.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(row.inEditMode).toBe(false); }); it('Should keep edit mode when tabbing, after search is applied', () => { grid.primaryKey = 'ID'; grid.getColumnByName('Name').editable = true; grid.getColumnByName('JobTitle').editable = true; fix.detectChanges(); const cell = grid.gridAPI.get_cell_by_index(1, 'Name'); const caseyCell = grid.gridAPI.get_cell_by_index(0, 'Name'); const newVal = 'newCellValue'; grid.findNext('Casey'); fix.detectChanges(); let highlights = caseyCell.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); UIInteractions.simulateDoubleClickAndSelectEvent(cell.nativeElement); fix.detectChanges(); expect(cell.editMode).toBeTruthy(); highlights = caseyCell.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); let cellInput = null; cellInput = cell.nativeElement.querySelector('[igxinput]'); UIInteractions.setInputElementValue(cellInput, newVal); // press tab on edited cell GridFunctions.simulateGridContentKeydown(fix, 'tab'); fix.detectChanges(); expect(cell.value).toBe(newVal); expect(cell.editMode).toBeFalsy(); highlights = caseyCell.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); const nextCell = grid.gridAPI.get_cell_by_index(1, 'JobTitle'); expect(nextCell.editMode).toBeTruthy(); expect(highlights.length).toBe(1); }); }); describe('ScrollableGrid - ', () => { beforeEach(() => { fix = TestBed.createComponent(ScrollableGridSearchComponent); component = fix.componentInstance; grid = component.grid; setupGridScrollDetection(fix, grid); fix.detectChanges(); grid.data[29].HireDate = '1887-11-28T11:23:17.714Z'; grid.width = '500px'; grid.height = '600px'; fixNativeElement = fix.debugElement.nativeElement; fix.detectChanges(); }); afterEach(() => { clearGridSubs(); }); it('findNext scrolls to cells out of view', async () => { grid.findNext('30'); await wait(100); fix.detectChanges(); expect(isInView(29, grid.virtualizationState)).toBeTruthy(); grid.findNext('1887'); await wait(100); fix.detectChanges(); expect(isInView(3, grid.rowList.first.virtDirRow.state)).toBeTruthy(); }); it('findPrev scrolls to cells out of view', async () => { grid.findPrev('30'); await wait(100); fix.detectChanges(); expect(isInView(29, grid.virtualizationState)).toBeTruthy(); grid.findPrev('1887'); await wait(100); fix.detectChanges(); expect(isInView(3, grid.rowList.first.virtDirRow.state)).toBeTruthy(); }); it('should keep the active highlight when active cell enters and exits edit mode', () => { const rv = fix.debugElement.query(By.css(CELL_CSS_CLASS)).nativeElement; const cell = grid.getCellByColumn(0, 'ID'); const initialValue = rv.textContent; let activeHighlight = rv.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(activeHighlight).toBeNull(); cell.column.editable = true; grid.findNext('1'); fix.detectChanges(); activeHighlight = rv.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(activeHighlight).not.toBeNull(); cell.editMode = true; fix.detectChanges(); expect(cell.editMode).toBe(true); activeHighlight = rv.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(activeHighlight).toBeNull(); cell.editMode = false; fix.detectChanges(); expect(rv.innerText).toBe(initialValue); expect(rv.querySelectorAll(HIGHLIGHT_CSS_CLASS).length).toBe(1); activeHighlight = rv.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(activeHighlight).not.toBeNull(); }); it('should update highlights when a new value is entered', () => { const rv = fix.debugElement.query(By.css(CELL_CSS_CLASS)); const cell = grid.getCellByColumn(0, 'ID'); cell.column.editable = true; fix.detectChanges(); let activeHighlight = rv.nativeElement.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(activeHighlight).toBeNull(); grid.findNext('1'); fix.detectChanges(); activeHighlight = rv.nativeElement.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(activeHighlight).not.toBeNull(); cell.editMode = true; fix.detectChanges(); expect(cell.editMode).toBe(true); const inputElem: HTMLInputElement = rv.nativeElement.querySelector('input') as HTMLInputElement; inputElem.value = '11'; fix.detectChanges(); cell.update(inputElem.value); fix.detectChanges(); expect(rv.nativeElement.innerText).toBe('11'); activeHighlight = rv.nativeElement.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); const highlights = rv.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(2); verifyActiveHighlight(0); }); it('should update highlights when the cell value is cleared', () => { const rv = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS))[1].nativeElement; const rv2 = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS))[2].nativeElement; const cell = grid.getCellByColumn(0, 'Name'); let activeHighlight = rv.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(activeHighlight).toBeNull(); cell.column.editable = true; grid.findNext('c'); fix.detectChanges(); activeHighlight = rv.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(activeHighlight).not.toBeNull(); cell.editMode = true; fix.detectChanges(); expect(cell.editMode).toBe(true); const inputElem: HTMLInputElement = rv.querySelector('input') as HTMLInputElement; inputElem.value = ''; cell.update(inputElem.value); fix.detectChanges(); activeHighlight = rv.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); let highlights = rv.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(0); expect(activeHighlight).toBeNull(); activeHighlight = rv2.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); highlights = rv2.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(highlights.length).toBe(1); expect(activeHighlight).toBe(highlights[0]); }); it('Should update highlight when setting perPage option', () => { fix.componentInstance.paging = true; fix.detectChanges(); const searchString = 'casey'; grid.findNext(searchString); grid.findNext(searchString); fix.detectChanges(); let activeHighlight = getActiveHighlight(); expect(activeHighlight).not.toBeNull(); expect(grid.paginator.page).toBe(0); grid.paginator.perPage = 9; fix.detectChanges(); activeHighlight = getActiveHighlight(); expect(activeHighlight).toBeNull(); expect(grid.page).toBe(0); grid.paginator.page = 1; fix.detectChanges(); activeHighlight = getActiveHighlight(); expect(activeHighlight).not.toBeNull(); }); }); describe('Groupable Grid', () => { beforeEach(() => { fix = TestBed.createComponent(GroupableGridSearchComponent); fix.detectChanges(); component = fix.componentInstance; grid = component.grid; fixNativeElement = fix.debugElement.nativeElement; }); it('Should be able to navigate through highlights with grouping enabled', () => { grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); fix.detectChanges(); grid.findNext('Software'); fix.detectChanges(); let spans = getSpans(); expect(spans.length).toBe(5); verifyActiveHighlight(0); grid.findNext('Software'); grid.findNext('Software'); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(5); verifyActiveHighlight(2); grid.findPrev('Software'); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(5); verifyActiveHighlight(1); grid.findPrev('Software'); grid.findPrev('Software'); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(5); verifyActiveHighlight(4); }); it('Should be able to react to changes in grouping', () => { grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); fix.detectChanges(); let cell = grid.gridAPI.get_cell_by_index(1, 'JobTitle'); grid.findNext('software'); fix.detectChanges(); let highlight = cell.nativeElement.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(highlight !== null).toBeTruthy(); grid.clearGrouping(); fix.detectChanges(); cell = grid.gridAPI.get_cell_by_index(6, 'JobTitle'); highlight = cell.nativeElement.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(highlight !== null).toBeTruthy(); grid.groupBy([{ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }, { fieldName: 'Company', dir: SortingDirection.Desc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }]); fix.detectChanges(); cell = grid.gridAPI.get_cell_by_index(4, 'JobTitle'); highlight = cell.nativeElement.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(highlight !== null).toBeTruthy(); grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Desc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); fix.detectChanges(); grid.findNext('software'); fix.detectChanges(); cell = grid.gridAPI.get_cell_by_index(5, 'JobTitle'); highlight = cell.nativeElement.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS); expect(highlight !== null).toBeTruthy(); }); it('Should be able to navigate through highlights with grouping and paging enabled', () => { grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); fix.componentInstance.paging = true; fix.detectChanges(); grid.paginator.perPage = 6; fix.detectChanges(); grid.findNext('Software'); fix.detectChanges(); let spans = getSpans(); expect(spans.length).toBe(2); verifyActiveSpan(0); expect(grid.paginator.page).toBe(0); grid.findPrev('Software'); fix.detectChanges(); spans = getSpans(); verifyActiveSpan(1); expect(spans.length).toBe(2); expect(grid.paginator.page).toBe(2); grid.findPrev('Software'); grid.findPrev('Software'); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(1); verifyActiveSpan(0); expect(grid.paginator.page).toBe(1); }); it('Should be able to properly handle perPage changes with grouping and paging', () => { fix.componentInstance.paging = true; fix.detectChanges(); grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); grid.paginator.perPage = 16; grid.cdr.detectChanges(); fix.detectChanges(); grid.findNext('Software'); grid.findNext('Software'); grid.findNext('Software'); fix.detectChanges(); let spans = getSpans(); verifyActiveSpan(2); expect(spans.length).toBe(5); expect(grid.paginator.page).toBe(0); grid.paginator.perPage = 8; fix.detectChanges(); spans = getSpans(); const activeSpan = getActiveSpan(); expect(spans.length).toBe(2); expect(activeSpan).toBeNull(); expect(grid.page).toBe(0); grid.paginator.page = 1; fix.detectChanges(); spans = getSpans(); verifyActiveSpan(0); expect(spans.length).toBe(3); expect(grid.page).toBe(1); }); it('Should be able to properly handle navigating through collapsed rows', () => { grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); fix.detectChanges(); grid.findNext('software'); grid.findNext('software'); grid.findNext('software'); fix.detectChanges(); grid.toggleGroup(grid.groupsRecords[0]); fix.detectChanges(); let spans = getSpans(); expect(spans.length).toBe(3); verifyActiveSpan(0); grid.findNext('software'); grid.findNext('software'); grid.findNext('software'); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(5); verifyActiveSpan(0); expect(grid.isExpandedGroup(grid.groupsRecords[0])).toBeTruthy(); }); it('Should be able to navigate through highlights when scrolling with grouping enabled', async () => { grid.height = '500px'; fix.detectChanges(); grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); fix.detectChanges(); grid.findNext('a'); await wait(); fix.detectChanges(); (grid as any).scrollTo(9, 0); await wait(16); fix.detectChanges(); const row = grid.gridAPI.get_row_by_index(9); const spans = row.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(spans.length).toBe(5); }); it('Should be able to search when grouping is enabled', async () => { grid.height = '400px'; fix.detectChanges(); grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); fix.detectChanges(); grid.findNext('Casey'); await wait(100); fix.detectChanges(); let row = grid.gridAPI.get_row_by_index(17); let spans = row.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(spans.length).toBe(1); grid.toggleAllGroupRows(); fix.detectChanges(); (grid as any).scrollTo(0, 0); await wait(100); fix.detectChanges(); grid.toggleGroup(grid.groupsRecords[0]); fix.detectChanges(); grid.toggleGroup(grid.groupsRecords[1]); fix.detectChanges(); grid.findNext('Casey'); await wait(100); fix.detectChanges(); row = grid.gridAPI.get_row_by_index(11); spans = row.nativeElement.querySelectorAll(HIGHLIGHT_CSS_CLASS); expect(spans.length).toBe(1); }); it('Should be able to properly handle navigating through collapsed rows with paging', () => { grid.groupBy({ fieldName: 'JobTitle', dir: SortingDirection.Asc, ignoreCase: true, strategy: DefaultSortingStrategy.instance() }); fix.componentInstance.paging = true; fix.detectChanges(); grid.paginator.perPage = 8; fix.detectChanges(); grid.findNext('software'); grid.findNext('software'); fix.detectChanges(); grid.toggleGroup(grid.groupsRecords[0]); grid.findNext('software'); fix.detectChanges(); let spans = getSpans(); expect(spans.length).toBe(3); verifyActiveSpan(0); expect(grid.paginator.page).toBe(1); grid.findNext('software'); grid.findNext('software'); grid.findNext('software'); fix.detectChanges(); spans = getSpans(); expect(spans.length).toBe(2); verifyActiveSpan(0); expect(grid.isExpandedGroup(grid.groupsRecords[0])).toBeTruthy(); expect(grid.paginator.page).toBe(0); }); it('Should highlight search results in pinned and unpinned row areas separately', () => { grid.getRowByIndex(2).pin(); fix.detectChanges(); grid.findNext('Tanya Bennett'); fix.detectChanges(); const spans = getSpans(); expect(spans.length).toBe(2); verifyActiveSpan(0); grid.findNext('Tanya Bennett'); fix.detectChanges(); verifyActiveSpan(1); }); it('Should differentiate IgxHighlightDirective\'s metadata of pinned and unpinned rows', () => { grid.getRowByIndex(2).pin(); fix.detectChanges(); grid.findNext('Tanya Bennett'); fix.detectChanges(); const highlightDirectives = fix.debugElement.queryAll(By.css('div[ng-reflect-value="Tanya Bennett"]')); const firstHighlight = highlightDirectives[0].injector.get(IgxTextHighlightDirective); const secondHighlight = highlightDirectives[1].injector.get(IgxTextHighlightDirective); expect(firstHighlight.metadata.get('pinned')).toBe(true); expect(secondHighlight.metadata.get('pinned')).toBe(false); }); }); describe('Grid with Avatar - ', () => { beforeEach(() => { fix = TestBed.createComponent(GridWithAvatarComponent); grid = fix.componentInstance.grid; fix.detectChanges(); }); it('Cells with no text should be excluded from the search', () => { const matches = grid.findNext('https'); expect(matches).toBe(0); }); it('Cells with custom template should be excluded from search when pin/unpin', () => { grid.columnList.get(1).pinned = true; fix.detectChanges(); const matches = grid.findNext('https'); expect(matches).toBe(0); let cell = grid.gridAPI.get_cell_by_index(0, 'Avatar').nativeElement; expect(cell.children.length).toBe(1); let image = cell.querySelector('.cell__inner, .avatar-cell') as HTMLElement; expect(image.hidden).toBeFalsy(); g