diff --git a/projects/igniteui-angular/src/lib/grids/grid/column-resizing.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/column-resizing.spec.ts index 8c401c152f8..7ce783afbc6 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/column-resizing.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/column-resizing.spec.ts @@ -13,6 +13,7 @@ import { SampleTestData } from '../../test-utils/sample-test-data.spec'; import { IColumnResized } from '../../test-utils/grid-interfaces.spec'; import { MultiColumnHeadersComponent } from '../../test-utils/grid-samples.spec'; import { configureTestSuite } from '../../test-utils/configure-suite'; +import { GridFunctions } from '../../test-utils/grid-functions.spec'; describe('IgxGrid - Deferred Column Resizing #grid', () => { configureTestSuite(); @@ -511,7 +512,7 @@ describe('IgxGrid - Deferred Column Resizing #grid', () => { fixture.detectChanges(); const grid = fixture.componentInstance.grid; const headers: DebugElement[] = fixture.debugElement.queryAll(By.css(COLUMN_HEADER_GROUP_CLASS)); - const displayContainer: HTMLElement = fixture.componentInstance.grid.tbody.nativeElement.querySelector('igx-display-container'); + const displayContainer: HTMLElement = GridFunctions.getGridDisplayContainer(fixture).nativeElement; let rowsRendered = displayContainer.querySelectorAll('igx-display-container'); let colsRendered = rowsRendered[0].children; diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts index 9b90069dc14..7d32dd44f8d 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts @@ -283,22 +283,22 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { fix.detectChanges(); GridFunctions.verifyFilteringDropDownIsOpened(fix); - prefix.triggerEventHandler('keydown', UIInteractions.spaceEvent); + UIInteractions.triggerEventHandlerKeyDown(' ', prefix); tick(30); fix.detectChanges(); GridFunctions.verifyFilteringDropDownIsOpened(fix, false); - input.triggerEventHandler('keydown', UIInteractions.enterEvent); + UIInteractions.triggerEventHandlerKeyDown('Enter', input); tick(30); fix.detectChanges(); GridFunctions.verifyFilteringDropDownIsOpened(fix); - prefix.triggerEventHandler('keydown', UIInteractions.tabEvent); + UIInteractions.triggerEventHandlerKeyDown('Tab', prefix); tick(30); fix.detectChanges(); GridFunctions.verifyFilteringDropDownIsOpened(fix, false); - input.triggerEventHandler('keydown', UIInteractions.spaceEvent); + UIInteractions.triggerEventHandlerKeyDown(' ', input); tick(30); fix.detectChanges(); GridFunctions.verifyFilteringDropDownIsOpened(fix); @@ -980,7 +980,7 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { expect(filterChip.componentInstance.selected).toBeTruthy(); expect(input.componentInstance.value).toEqual('a'); - input.triggerEventHandler('keydown', UIInteractions.enterEvent); + UIInteractions.triggerEventHandlerKeyDown('Enter', input); fix.detectChanges(); // Check focus is kept and chips is no longer selected. @@ -1298,8 +1298,7 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { const filterUIRow = fix.debugElement.query(By.css(FILTER_UI_ROW)); const input = filterUIRow.query(By.directive(IgxInputDirective)); - - input.triggerEventHandler('keydown', UIInteractions.altAndArrowDownEvent); + UIInteractions.triggerEventHandlerKeyDown('ArrowDown', input, true); tick(30); fix.detectChanges(); GridFunctions.verifyFilteringDropDownIsOpened(fix); @@ -1311,7 +1310,7 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { let filterUIRow = fix.debugElement.query(By.css(FILTER_UI_ROW)); const input = filterUIRow.query(By.directive(IgxInputDirective)); - input.triggerEventHandler('keydown', UIInteractions.escapeEvent); + UIInteractions.triggerEventHandlerKeyDown('Escape', input); tick(100); fix.detectChanges(); @@ -1348,7 +1347,7 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { verifyFilterRowUI(input, close, reset, false); // submit the input with empty value - input.triggerEventHandler('keydown', UIInteractions.enterEvent); + UIInteractions.triggerEventHandlerKeyDown('Enter', input); tick(50); fix.detectChanges(); @@ -1623,7 +1622,7 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { // Press 'Enter' on the commit icon. const inputCommitIcon = GridFunctions.getFilterRowInputCommitIcon(fix); - inputCommitIcon.triggerEventHandler('keydown', UIInteractions.enterEvent); + UIInteractions.triggerEventHandlerKeyDown('Enter', inputCommitIcon); tick(200); fix.detectChanges(); @@ -1645,7 +1644,7 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { // Press 'Enter' on the clear icon. const inputClearIcon = GridFunctions.getFilterRowInputClearIcon(fix); - inputClearIcon.triggerEventHandler('keydown', UIInteractions.enterEvent); + UIInteractions.triggerEventHandlerKeyDown('Enter', inputClearIcon); tick(200); fix.detectChanges(); @@ -1659,7 +1658,7 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { expect(fix.debugElement.query(By.css(FILTER_UI_ROW))).toBeNull(); const filterCellChip = GridFunctions.getFilterChipsForColumn('ReleaseDate', fix)[0]; - filterCellChip.triggerEventHandler('keydown', UIInteractions.enterEvent); + UIInteractions.triggerEventHandlerKeyDown('Enter', filterCellChip); tick(200); fix.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-keyBoardNav.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-keyBoardNav.spec.ts index 7795b2f8b6d..14bc61285ea 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-keyBoardNav.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-keyBoardNav.spec.ts @@ -1,465 +1,247 @@ -import { Component, ViewChild, TemplateRef } from '@angular/core'; import { async, TestBed, fakeAsync, tick } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { - IgxColumnComponent, IgxGridCellComponent, IgxGridModule, - IgxGridRowComponent, IgxGridGroupByRowComponent, } from './index'; import { IgxGridComponent } from './grid.component'; -import { DataParent } from '../../test-utils/sample-test-data.spec'; import { IGridCellEventArgs } from '../common/events'; import { SortingDirection } from '../../data-operations/sorting-expression.interface'; import { DefaultSortingStrategy } from '../../data-operations/sorting-strategy'; import { UIInteractions, wait } from '../../test-utils/ui-interactions.spec'; -import { HelperUtils, setupGridScrollDetection } from '../../test-utils/helper-utils.spec'; +import { setupGridScrollDetection, TestNgZone } from '../../test-utils/helper-utils.spec'; import { configureTestSuite } from '../../test-utils/configure-suite'; import { - PinOnInitAndSelectionComponent, PinningComponent, - VirtualGridComponent, ScrollsComponent, - GridWithPrimaryKeyComponent, SelectionComponent + VirtualGridComponent, + NoScrollsComponent, + IgxGridGroupByComponent } from '../../test-utils/grid-samples.spec'; import { GridSelectionMode } from '../common/enums'; -import { GridFunctions } from '../../test-utils/grid-functions.spec'; +import { GridFunctions, GridSelectionFunctions } from '../../test-utils/grid-functions.spec'; const DEBOUNCETIME = 30; -const CELL_CSS_CLASS = '.igx-grid__td'; describe('IgxGrid - Keyboard navigation #grid', () => { - configureTestSuite(); - - beforeAll(async(() => { - TestBed.configureTestingModule({ - declarations: [ - DefaultGridComponent, - CtrlKeyKeyboardNagivationComponent, - VirtualGridComponent, - GridWithPrimaryKeyComponent, - DefaultGroupBYGridComponent, - ScrollsComponent, - SelectionComponent, - PinOnInitAndSelectionComponent, - PinningComponent - ], - imports: [NoopAnimationsModule, IgxGridModule] - }).compileComponents(); - })); - - it('should move selected cell with arrow keys', (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - fix.detectChanges(); - - let topLeft; - let topRight; - let bottomLeft; - let bottomRight; - [topLeft, topRight, bottomLeft, bottomRight] = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS)); - - topLeft.nativeElement.dispatchEvent(new Event('focus')); - await wait(); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual(1); - expect(fix.componentInstance.selectedCell.column.field).toMatch('index'); - - UIInteractions.triggerKeyDownWithBlur('arrowdown', topLeft.nativeElement, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual(2); - expect(fix.componentInstance.selectedCell.column.field).toMatch('index'); - - UIInteractions.triggerKeyDownWithBlur('arrowright', bottomLeft.nativeElement, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual(2); - expect(fix.componentInstance.selectedCell.column.field).toMatch('value'); - - UIInteractions.triggerKeyDownWithBlur('arrowup', bottomRight.nativeElement, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual(1); - expect(fix.componentInstance.selectedCell.column.field).toMatch('value'); - - UIInteractions.triggerKeyDownWithBlur('arrowleft', topRight.nativeElement, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual(1); - expect(fix.componentInstance.selectedCell.column.field).toMatch('index'); - })); - - it('should jump to first/last cell with Ctrl', (async () => { - const fix = TestBed.createComponent(CtrlKeyKeyboardNagivationComponent); - fix.detectChanges(); - - const rv = fix.debugElement.query(By.css(CELL_CSS_CLASS)); - const rv2 = fix.debugElement.query(By.css(`${CELL_CSS_CLASS}:last-child`)); - - rv.nativeElement.dispatchEvent(new Event('focus')); - await wait(); - fix.detectChanges(); - - UIInteractions.triggerKeyDownWithBlur('arrowright', rv.nativeElement, true, false, false, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual(1); - expect(fix.componentInstance.selectedCell.column.field).toMatch('another'); - - UIInteractions.triggerKeyDownWithBlur('arrowleft', rv2.nativeElement, true, false, false, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual(1); - expect(fix.componentInstance.selectedCell.column.field).toMatch('index'); - })); - - it('Should properly blur the focused cell when scroll with mouse wheeel', (async () => { - pending('This scenario need to be tested manually'); - const fix = TestBed.createComponent(ScrollsComponent); - fix.detectChanges(); - const grid = fix.componentInstance.grid; - const firstCell = grid.rowList.first.cells.toArray()[0]; - - firstCell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(firstCell.selected).toBeTruthy(); - expect(firstCell.focused).toBeTruthy(); - - const displayContainer = grid.nativeElement.querySelector('.igx-grid__tbody >.igx-display-container'); - const event = new WheelEvent('wheel', { deltaX: 0, deltaY: 500 }); - displayContainer.dispatchEvent(event); - await wait(300); - - expect(firstCell.selected).toBeFalsy(); - expect(firstCell.focused).toBeFalsy(); - })); - - it('Should properly handle TAB / SHIFT + TAB on row selectors', (async () => { - const fix = TestBed.createComponent(ScrollsComponent); - fix.detectChanges(); - const grid = fix.componentInstance.grid; - setupGridScrollDetection(fix, grid); - - const firstRow = grid.getRowByIndex(0); - const firstRowCheckbox: HTMLElement = firstRow.nativeElement.querySelector('.igx-checkbox'); - const secondRow = grid.getRowByIndex(1); - const secondRowCheckbox: HTMLElement = secondRow.nativeElement.querySelector('.igx-checkbox'); - let cell = grid.getCellByColumn(1, 'ID'); - - cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(cell.selected).toBeTruthy(); - UIInteractions.triggerKeyDownEvtUponElem('space', cell.nativeElement, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(cell.selected).toBeTruthy(); - expect(secondRow.selected).toBeTruthy(); - expect(secondRowCheckbox.classList.contains('igx-checkbox--checked')).toBeTruthy(); - - UIInteractions.triggerKeyDownEvtUponElem('space', cell.nativeElement, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(cell.selected).toBeTruthy(); - expect(secondRow.selected).toBeFalsy(); - expect(secondRowCheckbox.classList.contains('igx-checkbox--checked')).toBeFalsy(); - - cell = grid.getCellByColumn(1, 'ID'); - UIInteractions.triggerKeyDownWithBlur('tab', cell.nativeElement, true, false, true); - await wait(100); - fix.detectChanges(); - expect(secondRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); - - cell = grid.getCellByColumn(0, 'Column 15'); - expect(cell.selected).toBeTruthy(); - expect(cell.focused).toBeTruthy(); - expect(secondRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); - - UIInteractions.triggerKeyDownEvtUponElem('space', cell.nativeElement, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(firstRow.selected).toBeTruthy(); - expect(firstRowCheckbox.classList.contains('igx-checkbox--checked')).toBeTruthy(); - - UIInteractions.triggerKeyDownEvtUponElem('space', cell.nativeElement, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(cell.selected).toBeTruthy(); - expect(firstRow.selected).toBeFalsy(); - expect(firstRowCheckbox.classList.contains('igx-checkbox--checked')).toBeFalsy(); - - UIInteractions.triggerKeyDownWithBlur('tab', cell.nativeElement, true); - await wait(100); - fix.detectChanges(); - expect(secondRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); - - cell = grid.getCellByColumn(1, 'ID'); - expect(cell.selected).toBeTruthy(); - expect(cell.focused).toBeTruthy(); - expect(secondRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); - })); - - it('Should properly handle TAB / SHIFT + TAB on edge cell, triggering virt scroll', (async () => { - const fix = TestBed.createComponent(ScrollsComponent); - fix.detectChanges(); - const grid = fix.componentInstance.grid; - const virtualizationSpy = spyOn(grid.parentVirtDir.onChunkLoad, 'emit').and.callThrough(); - // Focus left right cell - const gridFirstRow = grid.rowList.first; - const cellsLength = grid.rowList.first.cells.length; - const mockEvent = jasmine.createSpyObj('mockEvt', ['preventDefault', 'stopPropagation']); - - // Focus last right cell - const lastVisibleCell = gridFirstRow.cells.toArray()[cellsLength - 3]; - - lastVisibleCell.nativeElement.dispatchEvent(new Event('focus')); - await wait(30); - fix.detectChanges(); - - expect(lastVisibleCell.selected).toBeTruthy(); - UIInteractions.triggerKeyDownWithBlur('tab', lastVisibleCell.nativeElement, true); - await wait(30); - fix.detectChanges(); - expect(virtualizationSpy).toHaveBeenCalledTimes(1); - - const targetCell = gridFirstRow.cells.toArray()[cellsLength - 3]; - targetCell.nativeElement.dispatchEvent(new Event('focus')); - await wait(30); - fix.detectChanges(); - - expect(targetCell.selected).toBeTruthy(); - - // Focus second last right cell, TAB will NOT trigger virtualization; - UIInteractions.triggerKeyDownWithBlur('tab', targetCell.nativeElement, true); - await wait(30); - fix.detectChanges(); - - expect(virtualizationSpy).toHaveBeenCalledTimes(1); - expect(lastVisibleCell.selected).toBeTruthy(); - - // Focus leftmost cell, SHIFT + TAB will NOT trigger virtualization - gridFirstRow.cells.first.nativeElement.dispatchEvent(new Event('focus')); - await wait(30); - fix.detectChanges(); - - expect(gridFirstRow.cells.first.selected).toBeTruthy(); - UIInteractions.triggerKeyDownWithBlur('tab', gridFirstRow.cells.first.nativeElement, true, false, true); - await wait(30); - fix.detectChanges(); - - // There are not cells prior to the first cell - no scrolling will be done, spy will not be called; - expect(virtualizationSpy).toHaveBeenCalledTimes(1); - })); - - it('Should handle keydown events on cells properly even when primaryKey is specified', (async () => { - const fix = TestBed.createComponent(GridWithPrimaryKeyComponent); - fix.detectChanges(); - - const grid = fix.componentInstance.grid; - - expect(grid.primaryKey).toBeTruthy(); - expect(grid.rowList.length).toEqual(10, 'All 10 rows should initialized'); - - const targetCell = grid.getCellByKey(2, 'Name'); - const targetCellElement: HTMLElement = grid.getCellByKey(2, 'Name').nativeElement; - spyOn(grid.getCellByKey(2, 'Name'), 'onFocus').and.callThrough(); - expect(targetCell.focused).toEqual(false); - - targetCellElement.dispatchEvent(new FocusEvent('focus')); - await wait(DEBOUNCETIME); - - spyOn(grid.getCellByKey(3, 'Name'), 'onFocus').and.callThrough(); - fix.detectChanges(); - - expect(targetCell.onFocus).toHaveBeenCalledTimes(1); - expect(targetCell.focused).toEqual(true); - - UIInteractions.triggerKeyDownWithBlur('arrowdown', targetCellElement, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(grid.getCellByKey(3, 'Name').onFocus).toHaveBeenCalledTimes(1); - expect(grid.getCellByKey(3, 'Name').focused).toEqual(true); - expect(targetCell.focused).toEqual(false); - expect(grid.selectedCells.length).toEqual(1); - expect(grid.selectedCells[0].row.rowData[grid.primaryKey]).toEqual(3); - })); - - it('Should properly move focus when loading new row chunk', (async () => { - const fix = TestBed.createComponent(SelectionComponent); - fix.detectChanges(); - const grid = fix.componentInstance.grid; - const lastRowIndex = grid.rowList.length - 2; - let targetCell = grid.getCellByColumn(lastRowIndex, 'Column1'); - const initialValue = targetCell.value; - const targetCellElement: HTMLElement = targetCell.nativeElement; - spyOn(targetCell, 'onFocus').and.callThrough(); - expect(targetCell.focused).toEqual(false); - targetCellElement.focus(); - spyOn(targetCell.gridAPI, 'get_cell_by_visible_index').and.callThrough(); - fix.detectChanges(); - targetCell = grid.getCellByColumn(lastRowIndex, 'Column1'); - expect(targetCell.focused).toEqual(true); - UIInteractions.triggerKeyDownWithBlur('arrowdown', targetCellElement, true); - await wait(100); - fix.detectChanges(); - const newLastRowIndex = lastRowIndex + 1; - expect(grid.getCellByColumn(newLastRowIndex, 'Column1').value === initialValue).toBeFalsy(); - expect(grid.getCellByColumn(newLastRowIndex, 'Column1').focused).toEqual(true); - expect(grid.getCellByColumn(newLastRowIndex, 'Column1').selected).toEqual(true); - expect(grid.getCellByColumn(newLastRowIndex, 'Column1').nativeElement.classList).toContain('igx-grid__td--selected'); - expect(grid.getCellByColumn(lastRowIndex, 'Column1').focused).toEqual(false); - expect(grid.selectedCells.length).toEqual(1); - })); - - it('should allow keyboard navigation to first/last cell with Ctrl when there are the pinned columns.', async () => { - const fix = TestBed.createComponent(PinningComponent); - fix.detectChanges(); - - await wait(); - const grid = fix.componentInstance.grid; - grid.getColumnByName('CompanyName').pinned = true; - grid.getColumnByName('ContactName').pinned = true; - await wait(DEBOUNCETIME); - fix.detectChanges(); - const cells = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS)); - let cell = cells[0]; - - cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual('Maria Anders'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('ContactName'); - - UIInteractions.triggerKeyDownWithBlur('arrowright', cell.nativeElement, true, false, false, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual('030-0076545'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('Fax'); - - cell = cells[cells.length - 1]; - UIInteractions.triggerKeyDownWithBlur('arrowleft', cell.nativeElement, true, false, false, true); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - // It won't scroll left since the next selected cell will be in the pinned area - expect(fix.componentInstance.selectedCell.value).toEqual('Maria Anders'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('ContactName'); - }); - it('should allow horizontal keyboard navigation between start pinned area and unpinned area.', fakeAsync(() => { - const fix = TestBed.createComponent(PinningComponent); - fix.detectChanges(); - const grid = fix.componentInstance.grid; + describe('in not virtualized grid', () => { + let fix; + let grid: IgxGridComponent; + configureTestSuite(); + beforeAll(async(() => { + TestBed.configureTestingModule({ + declarations: [ + NoScrollsComponent + ], + imports: [NoopAnimationsModule, IgxGridModule], + }).compileComponents(); + })); + + beforeEach(fakeAsync(/** height/width setter rAF */() => { + fix = TestBed.createComponent(NoScrollsComponent); + fix.detectChanges(); + grid = fix.componentInstance.grid; + })); + + it('should move selected cell with arrow keys', () => { + let selectedCell: IgxGridCellComponent; + const firstCell = GridFunctions.getRowCells(fix, 0)[0]; + const secondCell = GridFunctions.getRowCells(fix, 1)[0]; + const thirdCell = GridFunctions.getRowCells(fix, 1)[1]; + const fourthCell = GridFunctions.getRowCells(fix, 0)[1]; + + grid.onSelection.subscribe((event: IGridCellEventArgs) => { + selectedCell = event.cell; + }); + firstCell.triggerEventHandler('focus', null); + fix.detectChanges(); + + expect(selectedCell.value).toEqual(1); + expect(selectedCell.column.field).toMatch('ID'); + + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowdown', firstCell); + fix.detectChanges(); + + expect(selectedCell.value).toEqual(2); + expect(selectedCell.column.field).toMatch('ID'); + + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowright', secondCell); + fix.detectChanges(); + + expect(selectedCell.value).toEqual('Gilberto Todd'); + expect(selectedCell.column.field).toMatch('Name'); + + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowup', thirdCell); + fix.detectChanges(); + + expect(selectedCell.value).toEqual('Casey Houston'); + expect(selectedCell.column.field).toMatch('Name'); + + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowleft', fourthCell); + fix.detectChanges(); + + expect(selectedCell.value).toEqual(1); + expect(selectedCell.column.field).toMatch('ID'); + }); + + it('should jump to first/last cell with Ctrl', () => { + let selectedCell: IgxGridCellComponent; + const firstCell = GridFunctions.getRowCells(fix, 1)[0]; + const lastCell = GridFunctions.getRowCells(fix, 1)[3]; + + grid.onSelection.subscribe((event: IGridCellEventArgs) => { + selectedCell = event.cell; + }); + + firstCell.triggerEventHandler('focus', null); + fix.detectChanges(); + + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowright', firstCell, false, false, true); + fix.detectChanges(); + + expect(selectedCell.value).toEqual('Company C'); + expect(selectedCell.column.field).toMatch('Company'); + + + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowleft', lastCell, false, false, true); + fix.detectChanges(); + + expect(selectedCell.value).toEqual(2); + expect(selectedCell.column.field).toMatch('ID'); + }); + + it('Should handle keydown events on cells properly even when primaryKey is specified', () => { + expect(grid.primaryKey).toBeTruthy(); + expect(grid.rowList.length).toEqual(10, 'All 10 rows should initialized'); + + const targetCell = grid.getCellByKey(2, 'Name'); + const targetCellElement = GridFunctions.getRowCells(fix, 1)[1]; + spyOn(grid.getCellByKey(2, 'Name'), 'onFocus').and.callThrough(); + expect(targetCell.focused).toEqual(false); + + targetCellElement.triggerEventHandler('focus', null); + fix.detectChanges(); + + spyOn(grid.getCellByKey(3, 'Name'), 'onFocus').and.callThrough(); + fix.detectChanges(); + + expect(targetCell.onFocus).toHaveBeenCalledTimes(1); + expect(targetCell.focused).toEqual(true); + + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowdown', targetCellElement); + fix.detectChanges(); + + expect(grid.getCellByKey(3, 'Name').onFocus).toHaveBeenCalledTimes(1); + expect(grid.getCellByKey(3, 'Name').focused).toEqual(true); + expect(targetCell.focused).toEqual(false); + expect(grid.selectedCells.length).toEqual(1); + expect(grid.selectedCells[0].row.rowData[grid.primaryKey]).toEqual(3); + }); + + it('Should properly handle TAB / SHIFT + TAB on row selectors', () => { + grid.rowSelection = GridSelectionMode.multiple; + fix.detectChanges(); + + const firstCell = GridFunctions.getRowCells(fix, 1)[0]; + const secondCell = GridFunctions.getRowCells(fix, 0)[3]; + const firstRow = grid.getRowByIndex(0); + const secondRow = grid.getRowByIndex(1); - fix.detectChanges(); - tick(); + firstCell.triggerEventHandler('focus', null); + fix.detectChanges(); - grid.getColumnByName('CompanyName').pinned = true; - grid.getColumnByName('ContactName').pinned = true; - fix.detectChanges(); + UIInteractions.triggerEventHandlerKeyDownWithBlur('Tab', firstCell, false, true); + fix.detectChanges(); - const cells = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS)); - let cell = cells[0]; + let cell = grid.getCellByColumn(0, 'Company'); + GridSelectionFunctions.verifyCellSelected(cell); + GridSelectionFunctions.verifyRowCheckboxIsNotFocused(secondRow.nativeElement); - cell.nativeElement.dispatchEvent(new Event('focus')); - tick(); - fix.detectChanges(); + UIInteractions.triggerEventHandlerKeyDownWithBlur('Tab', secondCell); + fix.detectChanges(); - expect(fix.componentInstance.selectedCell.value).toEqual('Maria Anders'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('ContactName'); + cell = grid.getCellByColumn(1, 'ID'); + GridSelectionFunctions.verifyCellSelected(cell); + GridSelectionFunctions.verifyRowCheckboxIsNotFocused(firstRow.nativeElement); + }); - UIInteractions.triggerKeyDownWithBlur('arrowright', cell.nativeElement, true); - tick(); - fix.detectChanges(); - expect(fix.componentInstance.selectedCell.value).toEqual('Alfreds Futterkiste'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('CompanyName'); - cell = cells[1]; + it('should allow vertical keyboard navigation in pinned area.', () => { + grid.getColumnByName('Name').pinned = true; + fix.detectChanges(); + let selectedCell; + const firstCell = GridFunctions.getRowCells(fix, 0)[0]; + const secondCell = GridFunctions.getRowCells(fix, 1)[0]; - UIInteractions.triggerKeyDownWithBlur('arrowright', cell.nativeElement, true); - tick(); + grid.onSelection.subscribe((event: IGridCellEventArgs) => { + selectedCell = event.cell; + }); + firstCell.triggerEventHandler('focus', null); + fix.detectChanges(); - fix.detectChanges(); - expect(fix.componentInstance.selectedCell.value).toEqual('ALFKI'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('ID'); - cell = cells[2]; + expect(selectedCell.value).toEqual('Casey Houston'); + expect(selectedCell.column.field).toMatch('Name'); - UIInteractions.triggerKeyDownWithBlur('arrowleft', cell.nativeElement, true); - tick(); - fix.detectChanges(); - expect(fix.componentInstance.selectedCell.value).toEqual('Alfreds Futterkiste'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('CompanyName'); - cell.triggerEventHandler('blur', {}); - tick(); - cell = cells[0]; + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowdown', firstCell); + fix.detectChanges(); - UIInteractions.triggerKeyDownWithBlur('arrowright', cell.nativeElement, true); - tick(); - fix.detectChanges(); - cell = cells[1]; + expect(selectedCell.value).toEqual('Gilberto Todd'); + expect(selectedCell.column.field).toMatch('Name'); - UIInteractions.triggerKeyDownWithBlur('arrowright', cell.nativeElement, true); - tick(); - fix.detectChanges(); - expect(fix.componentInstance.selectedCell.value).toEqual('ALFKI'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('ID'); - })); + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowup', secondCell); + fix.detectChanges(); - it('should allow vertical keyboard navigation in pinned area.', fakeAsync(() => { - const fix = TestBed.createComponent(PinOnInitAndSelectionComponent); - fix.detectChanges(); - const grid = fix.componentInstance.grid; - fix.detectChanges(); - const cells = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS)); - let cell = cells[0]; + expect(selectedCell.value).toEqual('Casey Houston'); + expect(selectedCell.column.field).toMatch('Name'); + }); - cell.nativeElement.dispatchEvent(new Event('focus')); - // cell.triggerEventHandler('focus', {}); + it('should allow horizontal keyboard navigation between start pinned area and unpinned area.', () => { + grid.getColumnByName('Name').pinned = true; + grid.getColumnByName('Company').pinned = true; + fix.detectChanges(); - tick(); - fix.detectChanges(); + let selectedCell; + const firstPinnedCell = GridFunctions.getRowCells(fix, 0)[0]; + const secondPinnedCell = GridFunctions.getRowCells(fix, 0)[1]; + const firstUnPinnedCell = GridFunctions.getRowCells(fix, 0)[2]; - expect(fix.componentInstance.selectedCell.value).toEqual('Alfreds Futterkiste'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('CompanyName'); + grid.onSelection.subscribe((event: IGridCellEventArgs) => { + selectedCell = event.cell; + }); + firstPinnedCell.triggerEventHandler('focus', null); + fix.detectChanges(); - UIInteractions.triggerKeyDownWithBlur('arrowdown', cell.nativeElement, true); + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowright', firstPinnedCell); + fix.detectChanges(); - tick(); - grid.cdr.detectChanges(); + expect(selectedCell.value).toEqual('Company A'); + expect(selectedCell.column.field).toMatch('Company'); - expect(fix.componentInstance.selectedCell.value).toEqual('Ana Trujillo Emparedados y helados'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('CompanyName'); - cell = cells[5]; + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowright', secondPinnedCell); + fix.detectChanges(); - UIInteractions.triggerKeyDownWithBlur('arrowup', cell.nativeElement, true); + expect(selectedCell.value).toEqual(1); + expect(selectedCell.column.field).toMatch('ID'); - tick(); - grid.cdr.detectChanges(); + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowleft', firstUnPinnedCell); + fix.detectChanges(); - expect(fix.componentInstance.selectedCell.value).toEqual('Alfreds Futterkiste'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('CompanyName'); - })); + expect(selectedCell.value).toEqual('Company A'); + expect(selectedCell.column.field).toMatch('Company'); + }); + }); describe('in virtualized grid', () => { - // configureTestSuite(); let fix; let grid: IgxGridComponent; + configureTestSuite(); + beforeAll(async(() => { + TestBed.configureTestingModule({ + declarations: [ + VirtualGridComponent + ], + imports: [NoopAnimationsModule, IgxGridModule], + }).compileComponents(); + })); beforeEach(fakeAsync(/** height/width setter rAF */() => { fix = TestBed.createComponent(VirtualGridComponent); @@ -469,34 +251,115 @@ describe('IgxGrid - Keyboard navigation #grid', () => { fix.detectChanges(); })); - it('should allow navigating down', async () => { - const cell = grid.getCellByColumn(4, 'index'); - cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(50); - fix.detectChanges(); - // navigate down to 50th row. - await GridFunctions.navigateVerticallyToIndex(grid, 4, 50); - await wait(100); + it('Should properly blur the focused cell when scroll with mouse wheeel', (async () => { + pending('This scenario need to be tested manually'); + const firstCell = grid.rowList.first.cells.toArray()[0]; + + firstCell.nativeElement.dispatchEvent(new Event('focus')); + await wait(); fix.detectChanges(); - expect(fix.componentInstance.selectedCell.rowIndex).toEqual(50); - }); - it('should allow navigating up', async () => { - grid.verticalScrollContainer.addScrollTop(5100); + expect(firstCell.selected).toBeTruthy(); + expect(firstCell.focused).toBeTruthy(); - await wait(200); + const displayContainer = GridFunctions.getGridDisplayContainer(fix).nativeElement; + const event = new WheelEvent('wheel', { deltaX: 0, deltaY: 500 }); + displayContainer.dispatchEvent(event); + await wait(300); + + expect(firstCell.selected).toBeFalsy(); + expect(firstCell.focused).toBeFalsy(); + })); + + it('Should properly handle TAB / SHIFT + TAB on edge cell, triggering virt scroll', (async () => { + const cols = []; + for (let i = 0; i < 10; i++) { + cols.push({ field: 'col' + i }); + } + fix.componentInstance.columns = cols; + fix.componentInstance.gridWidth = '830px'; + fix.componentInstance.data = fix.componentInstance.generateData(30); fix.detectChanges(); - const cell = grid.getCellByColumn(104, 'index'); + const virtualizationSpy = spyOn(grid.parentVirtDir.onChunkLoad, 'emit').and.callThrough(); + // Focus left right cell + const gridFirstRow = grid.rowList.first; + + const cell = grid.getCellByColumn(0, 'col3'); cell.nativeElement.dispatchEvent(new Event('focus')); + await wait(); + fix.detectChanges(); + + expect(cell.selected).toBeTruthy(); + UIInteractions.triggerKeyDownWithBlur('tab', cell.nativeElement, true); await wait(DEBOUNCETIME); fix.detectChanges(); + expect(virtualizationSpy).toHaveBeenCalledTimes(1); + + const targetCell = grid.getCellByColumn(0, 'col3'); + targetCell.nativeElement.dispatchEvent(new Event('focus')); + await wait(); + fix.detectChanges(); + + expect(targetCell.selected).toBeTruthy(); - await GridFunctions.navigateVerticallyToIndex(grid, 104, 0); + // Focus second last right cell, TAB will NOT trigger virtualization; + UIInteractions.triggerKeyDownWithBlur('tab', targetCell.nativeElement, true); await wait(DEBOUNCETIME); fix.detectChanges(); - expect(fix.componentInstance.selectedCell.rowIndex).toEqual(0); + expect(virtualizationSpy).toHaveBeenCalledTimes(1); + expect(cell.selected).toBeTruthy(); + + // Focus leftmost cell, SHIFT + TAB will NOT trigger virtualization + gridFirstRow.cells.first.nativeElement.dispatchEvent(new Event('focus')); + await wait(); + fix.detectChanges(); + + expect(gridFirstRow.cells.first.selected).toBeTruthy(); + UIInteractions.triggerKeyDownWithBlur('tab', gridFirstRow.cells.first.nativeElement, true, false, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + + // There are not cells prior to the first cell - no scrolling will be done, spy will not be called; + expect(virtualizationSpy).toHaveBeenCalledTimes(1); + })); + + it('should allow navigating down', async () => { + let cell = GridFunctions.getRowCells(fix, 4)[0]; + cell.triggerEventHandler('focus', null); + await wait(); + fix.detectChanges(); + + // Navigate to the 10th row + for (let index = 4; index < 10; index++) { + cell = GridFunctions.getRowCells(fix, 4)[0]; + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowdown', cell); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } + expect(fix.componentInstance.selectedCell.rowIndex).toEqual(10); + }); + + it('should allow navigating up', async () => { + grid.verticalScrollContainer.scrollTo(104); + await wait(); + fix.detectChanges(); + + let cell = GridFunctions.getRowCells(fix, 0)[0]; + cell.triggerEventHandler('focus', null); + await wait(); + fix.detectChanges(); + + expect(fix.componentInstance.selectedCell.rowIndex).toEqual(100); + // Navigate to the 94th row + for (let index = 0; index < 10; index++) { + cell = GridFunctions.getRowCells(fix, 0)[0]; + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowup', cell); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } + expect(fix.componentInstance.selectedCell.rowIndex).toEqual(90); }); it('should allow horizontal navigation', async () => { @@ -505,13 +368,13 @@ describe('IgxGrid - Keyboard navigation #grid', () => { cols.push({ field: 'col' + i }); } fix.componentInstance.columns = cols; - fix.detectChanges(); fix.componentInstance.data = fix.componentInstance.generateData(1000); + await wait(DEBOUNCETIME); fix.detectChanges(); const cell = grid.getCellByColumn(0, 'col3'); cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); + await wait(); fix.detectChanges(); await GridFunctions.navigateHorizontallyToIndex(grid, cell, 9); @@ -551,26 +414,25 @@ describe('IgxGrid - Keyboard navigation #grid', () => { fix.detectChanges(); expect(fix.componentInstance.selectedCell.visibleColumnIndex).toEqual(9); + // Verify columns + let cells = grid.getRowByIndex(0).cells.toArray(); + expect(cells.length).toEqual(5); + expect(cells[0].column.field).toEqual('col1'); + expect(cells[1].column.field).toEqual('col3'); + expect(cells[3].column.field).toEqual('col8'); + expect(cells[4].column.field).toEqual('col9'); + await GridFunctions.navigateHorizontallyToIndex(grid, fix.componentInstance.selectedCell, 1); await wait(DEBOUNCETIME); fix.detectChanges(); expect(fix.componentInstance.selectedCell.visibleColumnIndex).toEqual(1); - }); - it('should allow vertical navigation in virtualized grid with pinned cols.', async () => { - grid.pinColumn('index'); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - const cell = grid.getCellByColumn(4, 'index'); - cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(50); - fix.detectChanges(); - // navigate down to 20th row. - await GridFunctions.navigateVerticallyToIndex(grid, 4, 20); - await wait(50); - fix.detectChanges(); - expect(fix.componentInstance.selectedCell.rowIndex).toEqual(20); + cells = grid.getRowByIndex(0).cells.toArray(); + expect(cells.length).toEqual(5); + expect(cells[0].column.field).toEqual('col1'); + expect(cells[1].column.field).toEqual('col3'); + expect(cells[2].column.field).toEqual('col0'); + expect(cells[3].column.field).toEqual('col2'); }); it('should scroll into view the not fully visible cells when navigating down', async () => { @@ -578,23 +440,22 @@ describe('IgxGrid - Keyboard navigation #grid', () => { fix.componentInstance.data = fix.componentInstance.generateData(1000); fix.detectChanges(); - const rows = fix.nativeElement.querySelectorAll('igx-grid-row'); - const cell = rows[3].querySelectorAll('igx-grid-cell')[1]; - const bottomRowHeight = rows[4].offsetHeight; - const displayContainer = fix.nativeElement.querySelectorAll('igx-display-container')[1]; + const rows = GridFunctions.getRows(fix); + const cell = GridFunctions.getRowCells(fix, 3)[1]; + const bottomRowHeight = rows[4].nativeElement.offsetHeight; + const displayContainer = GridFunctions.getGridDisplayContainer(fix).nativeElement; const bottomCellVisibleHeight = displayContainer.parentElement.offsetHeight % bottomRowHeight; - cell.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); - + cell.triggerEventHandler('focus', null); + await wait(); fix.detectChanges(); + expect(fix.componentInstance.selectedCell.value).toEqual(30); expect(fix.componentInstance.selectedCell.column.field).toMatch('1'); - const curCell = grid.getCellByColumn(3, '1'); - UIInteractions.triggerKeyDownWithBlur('arrowdown', curCell.nativeElement, true); + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowdown', cell); await wait(DEBOUNCETIME); - fix.detectChanges(); + expect(parseInt(displayContainer.style.top, 10)).toBeLessThanOrEqual(-1 * (grid.rowHeight - bottomCellVisibleHeight)); expect(displayContainer.parentElement.scrollTop).toEqual(0); expect(fix.componentInstance.selectedCell.value).toEqual(40); @@ -604,25 +465,23 @@ describe('IgxGrid - Keyboard navigation #grid', () => { it('should scroll into view the not fully visible cells when navigating up', async () => { fix.componentInstance.columns = fix.componentInstance.generateCols(100); fix.componentInstance.data = fix.componentInstance.generateData(1000); - fix.detectChanges(); - const displayContainer = fix.nativeElement.querySelectorAll('igx-display-container')[1]; + + const displayContainer = GridFunctions.getGridDisplayContainer(fix).nativeElement; fix.componentInstance.scrollTop(25); await wait(DEBOUNCETIME); fix.detectChanges(); expect(displayContainer.style.top).toEqual('-25px'); - const rows = fix.nativeElement.querySelectorAll('igx-grid-row'); - const cell = rows[1].querySelectorAll('igx-grid-cell')[1]; - cell.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); + const cell = GridFunctions.getRowCells(fix, 1)[1]; + cell.triggerEventHandler('focus', null); + await wait(); fix.detectChanges(); expect(fix.componentInstance.selectedCell.value).toEqual(10); expect(fix.componentInstance.selectedCell.column.field).toMatch('1'); - const curCell = grid.getCellByColumn(1, '1'); - UIInteractions.triggerKeyDownWithBlur('arrowup', curCell.nativeElement, true); + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowup', cell); await wait(DEBOUNCETIME); fix.detectChanges(); @@ -633,51 +492,30 @@ describe('IgxGrid - Keyboard navigation #grid', () => { }); it('should allow navigating first/last cell in column with down/up and Ctrl key.', async () => { - grid.verticalScrollContainer.addScrollTop(5100); - - await wait(DEBOUNCETIME); - fix.detectChanges(); - - let cell = grid.getCellByColumn(104, 'value'); + let cell = grid.getCellByColumn(1, 'value'); cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); + await wait(); fix.detectChanges(); - expect(cell.selected).toBe(true); - expect(cell.focused).toBe(true); UIInteractions.triggerKeyDownWithBlur('arrowdown', cell.nativeElement, true, false, false, true); await wait(100); fix.detectChanges(); - let selectedCellFromGrid = grid.selectedCells[0]; - let selectedCell = fix.componentInstance.selectedCell; - expect(selectedCell.value).toEqual(9990); - expect(selectedCell.column.field).toMatch('value'); - expect(selectedCell.rowIndex).toEqual(999); - expect(selectedCellFromGrid.value).toEqual(9990); - expect(selectedCellFromGrid.column.field).toMatch('value'); - expect(selectedCellFromGrid.rowIndex).toEqual(999); + + cell = grid.getCellByColumn(999, 'value'); + GridSelectionFunctions.verifyGridCellSelected(fix, cell); cell = grid.getCellByColumn(998, 'other'); cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); + await wait(); fix.detectChanges(); - expect(cell.selected).toBe(true); - expect(cell.focused).toBe(true); UIInteractions.triggerKeyDownWithBlur('arrowup', cell.nativeElement, true, false, false, true); await wait(100); - fix.detectChanges(); + fix.detectChanges(); - selectedCellFromGrid = grid.selectedCells[0]; - selectedCell = fix.componentInstance.selectedCell; - expect(selectedCell.value).toEqual(0); - expect(selectedCell.column.field).toMatch('other'); - expect(selectedCell.rowIndex).toEqual(0); - expect(grid.verticalScrollContainer.getScroll().scrollTop).toEqual(0); - expect(selectedCellFromGrid.value).toEqual(0); - expect(selectedCellFromGrid.column.field).toMatch('other'); - expect(selectedCellFromGrid.rowIndex).toEqual(0); + cell = grid.getCellByColumn(0, 'other'); + GridSelectionFunctions.verifyGridCellSelected(fix, cell); }); it('should allow navigating first/last cell in column with home/end and Cntr key.', async () => { @@ -686,71 +524,54 @@ describe('IgxGrid - Keyboard navigation #grid', () => { fix.detectChanges(); grid.verticalScrollContainer.addScrollTop(5000); - - await wait(DEBOUNCETIME); + await wait(100); fix.detectChanges(); let cell = grid.getCellByColumn(101, '2'); cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); + await wait(); fix.detectChanges(); - expect(cell.selected).toBe(true); - expect(cell.focused).toBe(true); UIInteractions.triggerKeyDownWithBlur('home', cell.nativeElement, true, false, false, true); await wait(100); fix.detectChanges(); - let selectedCellFromGrid = grid.selectedCells[0]; - let selectedCell = fix.componentInstance.selectedCell; - expect(selectedCell.value).toEqual(0); - expect(selectedCell.column.field).toMatch('0'); - expect(selectedCell.rowIndex).toEqual(0); - expect(selectedCellFromGrid.value).toEqual(0); - expect(selectedCellFromGrid.column.field).toMatch('0'); - expect(selectedCellFromGrid.rowIndex).toEqual(0); + cell = grid.getCellByColumn(0, '0'); + GridSelectionFunctions.verifyGridCellSelected(fix, cell); expect(grid.verticalScrollContainer.getScroll().scrollTop).toEqual(0); cell = grid.getCellByColumn(4, '2'); cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); + await wait(); fix.detectChanges(); UIInteractions.triggerKeyDownWithBlur('end', cell.nativeElement, true, false, false, true); await wait(100); fix.detectChanges(); - selectedCell = fix.componentInstance.selectedCell; - expect(selectedCell.value).toEqual(244510); - expect(selectedCell.column.field).toMatch('49'); - expect(selectedCell.rowIndex).toEqual(499); - - selectedCellFromGrid = grid.selectedCells[0]; - expect(selectedCellFromGrid.value).toEqual(244510); - expect(selectedCellFromGrid.column.field).toMatch('49'); - expect(selectedCellFromGrid.rowIndex).toEqual(499); + cell = grid.getCellByColumn(499, '49'); + GridSelectionFunctions.verifyGridCellSelected(fix, cell); }); it('should scroll into view the not fully visible cells when navigating left', async () => { fix.componentInstance.columns = fix.componentInstance.generateCols(100); - fix.detectChanges(); fix.componentInstance.data = fix.componentInstance.generateData(1000); fix.detectChanges(); - const rows = fix.nativeElement.querySelectorAll('igx-grid-row'); - const rowDisplayContainer = rows[1].querySelector('igx-display-container'); + const rowDisplayContainer = GridFunctions.getRowDisplayContainer(fix, 1).nativeElement; fix.componentInstance.scrollLeft(50); await wait(DEBOUNCETIME); fix.detectChanges(); expect(rowDisplayContainer.style.left).toEqual('-50px'); - const cell = rows[1].querySelectorAll('igx-grid-cell')[1]; - cell.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); - + const cell = GridFunctions.getRowCells(fix, 1)[1]; + cell.triggerEventHandler('focus', null); + await wait(); fix.detectChanges(); + expect(fix.componentInstance.selectedCell.value).toEqual(10); expect(fix.componentInstance.selectedCell.column.field).toMatch('1'); + const curCell = grid.getCellByColumn(1, '1'); UIInteractions.triggerKeyDownWithBlur('arrowleft', curCell.nativeElement, true); await wait(DEBOUNCETIME); @@ -766,16 +587,16 @@ describe('IgxGrid - Keyboard navigation #grid', () => { fix.componentInstance.data = fix.componentInstance.generateData(1000); fix.detectChanges(); - const rows = fix.nativeElement.querySelectorAll('igx-grid-row'); - const rowDisplayContainer = rows[1].querySelector('igx-display-container'); + const rowDisplayContainer = GridFunctions.getRowDisplayContainer(fix, 1).nativeElement; expect(rowDisplayContainer.style.left).toEqual('0px'); - const cell = rows[1].querySelectorAll('igx-grid-cell')[2]; - cell.dispatchEvent(new Event('focus')); + const cell = GridFunctions.getRowCells(fix, 1)[2]; + cell.triggerEventHandler('focus', null); await wait(DEBOUNCETIME); fix.detectChanges(); expect(fix.componentInstance.selectedCell.value).toEqual(20); expect(fix.componentInstance.selectedCell.column.field).toMatch('2'); + const curCell = grid.getCellByColumn(1, '2'); UIInteractions.triggerKeyDownWithBlur('arrowright', curCell.nativeElement, true); await wait(DEBOUNCETIME); @@ -783,12 +604,13 @@ describe('IgxGrid - Keyboard navigation #grid', () => { expect(fix.componentInstance.selectedCell.value).toEqual(30); expect(fix.componentInstance.selectedCell.column.field).toMatch('3'); + expect(parseInt(rowDisplayContainer.style.left, 10)).toBeLessThanOrEqual(-40); }); it('should scroll first row into view when pressing arrow up', (async () => { grid.reflow(); fix.componentInstance.scrollTop(25); - await wait(100); + await wait(DEBOUNCETIME); fix.detectChanges(); let scrollContainer = grid.verticalScrollContainer.dc.instance._viewContainer; @@ -796,16 +618,14 @@ describe('IgxGrid - Keyboard navigation #grid', () => { expect(scrollContainerOffset).toEqual(-25); - const cell = fix.debugElement.queryAll(By.css(`${CELL_CSS_CLASS}:nth-child(2)`))[1]; - - cell.nativeElement.dispatchEvent(new Event('focus')); + const cell = GridFunctions.getRowCells(fix, 1)[1]; + cell.triggerEventHandler('focus', null); await wait(); fix.detectChanges(); expect(fix.componentInstance.selectedCell.value).toEqual(10); expect(fix.componentInstance.selectedCell.column.field).toMatch('value'); - - UIInteractions.triggerKeyDownWithBlur('arrowup', cell.nativeElement, true); + UIInteractions.triggerEventHandlerKeyDownWithBlur('arrowup', cell); await wait(DEBOUNCETIME); fix.detectChanges(); @@ -829,8 +649,8 @@ describe('IgxGrid - Keyboard navigation #grid', () => { // testing the pagedown key UIInteractions.triggerKeyDownEvtUponElem('PageDown', grid.nativeElement, true); grid.cdr.detectChanges(); - await wait(); + let currScrollTop = grid.verticalScrollContainer.getScroll().scrollTop; expect(currScrollTop).toEqual(grid.verticalScrollContainer.igxForContainerSize); @@ -876,7 +696,6 @@ describe('IgxGrid - Keyboard navigation #grid', () => { it('Custom KB navigation: onGridKeydown should be emitted', async () => { fix.componentInstance.columns = fix.componentInstance.generateCols(25); - fix.detectChanges(); fix.componentInstance.data = fix.componentInstance.generateData(25); fix.detectChanges(); const gridKeydown = spyOn(grid.onGridKeydown, 'emit').and.callThrough(); @@ -891,215 +710,177 @@ describe('IgxGrid - Keyboard navigation #grid', () => { targetType: 'dataCell', target: cell, cancel: false, event: new KeyboardEvent('keydown') }); }); - - it('should scroll into view not visible cell when in row edit and move from pinned to unpinned column', async () => { - fix.componentInstance.columns = fix.componentInstance.generateCols(100, 50); - fix.componentInstance.data = fix.componentInstance.generateData(100); - - fix.detectChanges(); - await wait(DEBOUNCETIME); - - grid.primaryKey = '0'; - grid.rowEditable = true; - grid.columns.every(c => c.editable = true); - - grid.getColumnByName('2').pinned = true; - grid.getColumnByName('3').pinned = true; - grid.getColumnByName('3').editable = false; - grid.getColumnByName('0').editable = false; - - await wait(DEBOUNCETIME); - fix.detectChanges(); - - grid.navigateTo(0, 99); - - await wait(DEBOUNCETIME); - fix.detectChanges(); - - const rows = fix.nativeElement.querySelectorAll('igx-grid-row'); - const cell = rows[0].querySelectorAll('igx-grid-cell')[0]; - cell.dispatchEvent(new Event('focus')); - UIInteractions.triggerKeyDownEvtUponElem('F2', cell, true); - - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(grid.crudService.cell.column.header).toBe('2'); - UIInteractions.triggerKeyDownEvtUponElem('tab', cell, true); - - await wait(DEBOUNCETIME); - fix.detectChanges(); - - expect(grid.crudService.cell.column.header).toBe('1'); - }); }); describe('Group By navigation ', () => { - // configureTestSuite(); + configureTestSuite(); + beforeAll(async(() => { + TestBed.configureTestingModule({ + declarations: [ + IgxGridGroupByComponent + ], + imports: [NoopAnimationsModule, IgxGridModule], + }).compileComponents(); + })); + let fix; let grid: IgxGridComponent; beforeEach(fakeAsync(/** height/width setter rAF */() => { - fix = TestBed.createComponent(DefaultGroupBYGridComponent); + fix = TestBed.createComponent(IgxGridGroupByComponent); fix.detectChanges(); grid = fix.componentInstance.grid; - fix.componentInstance.width = '600px'; - fix.componentInstance.height = '600px'; - grid.columnWidth = '100px'; setupGridScrollDetection(fix, grid); fix.detectChanges(); })); - it('should toggle expand/collapse state of group row with ArrowRight/ArrowLeft key.', async(() => { - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); + it('should toggle expand/collapse state of group row with ArrowRight/ArrowLeft key.', () => { const gRow = grid.groupsRowList.toArray()[0]; + const gRowElement = GridFunctions.getGroupedRows(fix)[0]; expect(gRow.expanded).toBe(true); - const evtArrowLeft = new KeyboardEvent('keydown', { key: 'ArrowLeft', altKey: true }); - const evtArrowRight = new KeyboardEvent('keydown', { key: 'ArrowRight', altKey: true }); - gRow.element.nativeElement.dispatchEvent(evtArrowLeft); + UIInteractions.triggerEventHandlerKeyDown('arrowleft', gRowElement, true); fix.detectChanges(); expect(gRow.expanded).toBe(false); - gRow.element.nativeElement.dispatchEvent(evtArrowRight); + UIInteractions.triggerEventHandlerKeyDown('arrowright', gRowElement, true); fix.detectChanges(); expect(gRow.expanded).toBe(true); - })); + }); - it('should toggle expand/collapse state of group row with ArrowUp/ArrowDown key.', async(() => { - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); + it('should toggle expand/collapse state of group row with ArrowUp/ArrowDown key.', () => { const gRow = grid.groupsRowList.toArray()[0]; + const gRowElement = GridFunctions.getGroupedRows(fix)[0]; expect(gRow.expanded).toBe(true); - const evtArrowUp = new KeyboardEvent('keydown', { key: 'ArrowUp', altKey: true }); - - const evtArrowDown = new KeyboardEvent('keydown', { key: 'ArrowDown', altKey: true }); - gRow.element.nativeElement.dispatchEvent(evtArrowUp); + UIInteractions.triggerEventHandlerKeyDown('ArrowUp', gRowElement, true); fix.detectChanges(); expect(gRow.expanded).toBe(false); - gRow.element.nativeElement.dispatchEvent(evtArrowDown); + UIInteractions.triggerEventHandlerKeyDown('ArrowDown', gRowElement, true); fix.detectChanges(); expect(gRow.expanded).toBe(true); - })); + }); it(`focus should stay over the group row when expanding/collapsing with keyboard and the grid is scrolled to the bottom`, (async () => { - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); - grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); - await wait(100); - fix.detectChanges(); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); + await wait(DEBOUNCETIME); + fix.detectChanges(); - const groupRows = grid.nativeElement.querySelectorAll('igx-grid-groupby-row'); - let lastGroupRow = groupRows[groupRows.length - 1]; - const lastGroupRowIndex = parseInt(lastGroupRow.dataset.rowindex, 10); - lastGroupRow.dispatchEvent(new FocusEvent('focus')); - fix.detectChanges(); + let groupedRowsCount = grid.groupsRowList.length; + let groupRow = grid.groupsRowList.toArray()[groupedRowsCount - 1]; + const groupRowElement = GridFunctions.getGroupedRows(fix)[groupedRowsCount - 1]; + groupRowElement.triggerEventHandler('focus', null); + fix.detectChanges(); - expect(lastGroupRow.classList.contains('igx-grid__group-row--active')).toBeTruthy(); - lastGroupRow.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', altKey: true })); + GridFunctions.verifyGroupRowIsFocused(groupRow); - fix.detectChanges(); - lastGroupRow = grid.nativeElement.querySelector(`igx-grid-groupby-row[data-rowindex="${lastGroupRowIndex}"]`); - expect(lastGroupRow).toBeDefined(); - expect(lastGroupRow.classList.contains('igx-grid__group-row--active')).toBeTruthy(); - expect(lastGroupRow.getAttribute('aria-expanded')).toBe('false'); - })); + UIInteractions.triggerEventHandlerKeyDown('ArrowLeft', groupRowElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + + groupedRowsCount = grid.groupsRowList.length; + groupRow = grid.groupsRowList.toArray()[groupedRowsCount - 1]; + expect(groupRow.index).toEqual(11); + expect(groupRow.expanded).toBeFalsy(); + GridFunctions.verifyGroupRowIsFocused(groupRow); + })); it(`should be able to navigate down to the next row when expand the last group row and grid is scrolled to bottom`, (async () => { - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); - - grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); - await wait(100); - fix.detectChanges(); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); + await wait(100); + fix.detectChanges(); - grid.groupsRowList.last.toggle(); - await wait(DEBOUNCETIME); - fix.detectChanges(); - expect(grid.groupsRowList.last.expanded).toBeFalsy(); + grid.groupsRowList.last.toggle(); + await wait(DEBOUNCETIME); + fix.detectChanges(); + expect(grid.groupsRowList.last.expanded).toBeFalsy(); - grid.groupsRowList.last.toggle(); - await wait(DEBOUNCETIME); - fix.detectChanges(); - expect(grid.groupsRowList.last.expanded).toBeTruthy(); + grid.groupsRowList.last.toggle(); + await wait(DEBOUNCETIME); + fix.detectChanges(); + expect(grid.groupsRowList.last.expanded).toBeTruthy(); - const groupRowIndex = grid.groupsRowList.last.index; - UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', grid.groupsRowList.last.nativeElement, true); - await wait(100); - fix.detectChanges(); + const groupRowIndex = grid.groupsRowList.last.index; + grid.groupsRowList.last.nativeElement.dispatchEvent(new Event('focus')); + await wait(); + fix.detectChanges(); - const selectedCell = grid.nativeElement.querySelector('.igx-grid__td--selected'); - expect(selectedCell).toBeDefined(); - expect(parseInt(selectedCell.dataset.rowindex, 10)).toBe(groupRowIndex + 1); - expect(parseInt(selectedCell.dataset.visibleindex, 10)).toBe(0); + UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', grid.groupsRowList.last.nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); - })); + const cell = grid.getCellByColumn(groupRowIndex + 1, 'Downloads'); + GridSelectionFunctions.verifyCellSelected(cell); + })); it('should allow keyboard navigation through group rows.', (async () => { fix.componentInstance.width = '400px'; fix.componentInstance.height = '300px'; - grid.columnWidth = '200px'; await wait(); fix.detectChanges(); - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false, strategy: DefaultSortingStrategy.instance() }); + await wait(); fix.detectChanges(); - let row = grid.getRowByIndex(0); - row.nativeElement.dispatchEvent(new Event('focus')); - await GridFunctions.navigateVerticallyToIndex(grid, 0, 9); - await wait(DEBOUNCETIME); + let row = grid.getRowByIndex(1); + row.nativeElement.dispatchEvent(new Event('focus')); + await wait(); fix.detectChanges(); + for (let index = 1; index < 9; index++) { + row = grid.getRowByIndex(index); + if (row instanceof IgxGridGroupByRowComponent) { + UIInteractions.triggerKeyDownWithBlur('arrowDown', row.nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } else { + const cell = grid.selectedCells[0]; + expect(cell.rowIndex).toEqual(index); + UIInteractions.triggerKeyDownWithBlur('arrowDown', grid.selectedCells[0].nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } + } row = grid.getRowByIndex(9); - expect(row instanceof IgxGridRowComponent).toBe(true); - expect(row.focused).toBe(true); expect(row.cells.toArray()[0].selected).toBe(true); - await GridFunctions.navigateVerticallyToIndex(grid, 9, 0); - await wait(DEBOUNCETIME); - fix.detectChanges(); - row = grid.getRowByIndex(0); + for (let index = 9; index > 1; index--) { + row = grid.getRowByIndex(index); + if (row instanceof IgxGridGroupByRowComponent) { + UIInteractions.triggerKeyDownWithBlur('arrowUp', row.nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } else { + const cell = grid.selectedCells[0]; + expect(cell.rowIndex).toEqual(index); + UIInteractions.triggerKeyDownWithBlur('arrowUp', grid.selectedCells[0].nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } + } + + row = grid.getRowByIndex(1); expect(row instanceof IgxGridGroupByRowComponent).toBe(true); expect(row.focused).toBe(true); + + row = grid.getRowByIndex(2); + expect(row.cells.toArray()[0].selected).toBe(true); })); - it('should persist last selected cell column index when navigation down through group rows.', async () => { + it('should persist last selected cell column index when navigate through group rows.', async () => { fix.componentInstance.width = '400px'; fix.componentInstance.height = '300px'; grid.columnWidth = '200px'; await wait(DEBOUNCETIME); fix.detectChanges(); - - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false, strategy: DefaultSortingStrategy.instance() @@ -1108,26 +889,55 @@ describe('IgxGrid - Keyboard navigation #grid', () => { grid.headerContainer.getScroll().scrollLeft = 1000; await wait(DEBOUNCETIME); + let cell = grid.getCellByColumn(2, 'Released'); cell.nativeElement.dispatchEvent(new Event('focus')); - - await GridFunctions.navigateVerticallyToIndex(grid, 0, 9, 4); - - await wait(DEBOUNCETIME); + await wait(); fix.detectChanges(); - const row = grid.getRowByIndex(9); + let row; + for (let index = 2; index < 9; index++) { + row = grid.getRowByIndex(index); + if (row instanceof IgxGridGroupByRowComponent) { + UIInteractions.triggerKeyDownWithBlur('arrowDown', row.nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } else { + const selectedCell = grid.selectedCells[0]; + expect(selectedCell.rowIndex).toEqual(index); + expect(selectedCell.column.field).toEqual('Released'); + UIInteractions.triggerKeyDownWithBlur('arrowDown', grid.selectedCells[0].nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } + } cell = grid.getCellByColumn(9, 'Released'); - expect(row instanceof IgxGridRowComponent).toBe(true); + expect(cell.selected).toBe(true); + + for (let index = 9; index > 1; index--) { + row = grid.getRowByIndex(index); + if (row instanceof IgxGridGroupByRowComponent) { + UIInteractions.triggerKeyDownWithBlur('arrowUp', row.nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } else { + const selectedCell = grid.selectedCells[0]; + expect(selectedCell.rowIndex).toEqual(index); + expect(selectedCell.column.field).toEqual('Released'); + UIInteractions.triggerKeyDownWithBlur('arrowUp', grid.selectedCells[0].nativeElement, true); + await wait(DEBOUNCETIME); + fix.detectChanges(); + } + } + + row = grid.getRowByIndex(1); + expect(row instanceof IgxGridGroupByRowComponent).toBe(true); expect(row.focused).toBe(true); + + cell = grid.getCellByColumn(2, 'Released'); expect(cell.selected).toBe(true); }); it('should focus grouped row when press Tab key and Shift + Tab on a cell', (async () => { - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); let cell = grid.getCellByColumn(2, 'Released'); cell.nativeElement.dispatchEvent(new Event('focus')); await wait(DEBOUNCETIME); @@ -1139,50 +949,40 @@ describe('IgxGrid - Keyboard navigation #grid', () => { let groupRow = grid.groupsRowList.toArray()[1]; cell = grid.getCellByColumn(2, 'Released'); - await GridFunctions.expandCollapceGroupRow(fix, groupRow, cell); + GridFunctions.verifyGroupRowIsFocused(groupRow); + GridSelectionFunctions.verifyCellSelected(cell); UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', groupRow.nativeElement, true); await wait(DEBOUNCETIME); fix.detectChanges(); - cell = grid.getCellByColumn(2, 'Released'); - expect(groupRow.focused).toBe(false); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(false); - expect(cell.selected).toBe(true); + GridFunctions.verifyGroupRowIsFocused(groupRow, false); + GridSelectionFunctions.verifyCellSelected(cell); expect(cell.focused).toBe(true); cell = grid.getCellByColumn(7, 'Downloads'); cell.nativeElement.dispatchEvent(new Event('focus')); fix.detectChanges(); - expect(groupRow.focused).toBe(false); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(false); - cell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', shiftKey: true })); + GridFunctions.verifyGroupRowIsFocused(groupRow, false); + UIInteractions.triggerKeyDownEvtUponElem('tab', cell.nativeElement, true, false, true); await wait(DEBOUNCETIME); fix.detectChanges(); groupRow = grid.groupsRowList.toArray()[2]; - cell = grid.getCellByColumn(7, 'Downloads'); - await GridFunctions.expandCollapceGroupRow(fix, groupRow, cell); + GridFunctions.verifyGroupRowIsFocused(groupRow); + GridSelectionFunctions.verifyCellSelected(cell); })); it('should correct work when press tab and sft+tab on a grouped row', (async () => { - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); - let groupRow = grid.groupsRowList.toArray()[0]; groupRow.nativeElement.dispatchEvent(new Event('focus')); await wait(DEBOUNCETIME); fix.detectChanges(); - groupRow = grid.groupsRowList.toArray()[0]; - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); + GridFunctions.verifyGroupRowIsFocused(groupRow); UIInteractions.triggerKeyDownEvtUponElem('tab', groupRow.nativeElement, true); - await wait(100); + await wait(DEBOUNCETIME); fix.detectChanges(); let cell = grid.getCellByColumn(1, 'Downloads'); @@ -1191,14 +991,13 @@ describe('IgxGrid - Keyboard navigation #grid', () => { groupRow = grid.groupsRowList.toArray()[1]; groupRow.nativeElement.dispatchEvent(new Event('focus')); - await wait(100); + await wait(DEBOUNCETIME); fix.detectChanges(); groupRow = grid.groupsRowList.toArray()[1]; - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); - groupRow.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', shiftKey: true })); - await wait(100); + GridFunctions.verifyGroupRowIsFocused(groupRow); + UIInteractions.triggerKeyDownEvtUponElem('tab', groupRow.nativeElement, true, false, true); + await wait(DEBOUNCETIME); fix.detectChanges(); cell = grid.getCellByColumn(2, 'Released'); @@ -1211,24 +1010,14 @@ describe('IgxGrid - Keyboard navigation #grid', () => { await wait(DEBOUNCETIME); fix.detectChanges(); - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - await wait(DEBOUNCETIME); - fix.detectChanges(); - const groupRow = grid.groupsRowList.toArray()[0]; const firstRow = grid.getRowByIndex(1); - const firstRowCheckbox: HTMLElement = firstRow.nativeElement.querySelector('.igx-checkbox'); const cell = grid.getCellByColumn(1, 'Downloads'); groupRow.nativeElement.dispatchEvent(new Event('focus')); await wait(DEBOUNCETIME); fix.detectChanges(); - - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); + GridFunctions.verifyGroupRowIsFocused(groupRow); UIInteractions.triggerKeyDownEvtUponElem('tab', groupRow.nativeElement, true); await wait(DEBOUNCETIME); @@ -1236,70 +1025,47 @@ describe('IgxGrid - Keyboard navigation #grid', () => { expect(cell.selected).toBeTruthy(); expect(cell.focused).toBeTruthy(); - expect(firstRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); + GridSelectionFunctions.verifyRowCheckboxIsNotFocused(firstRow.nativeElement); - cell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', shiftKey: true })); + UIInteractions.triggerKeyDownEvtUponElem('tab', groupRow.nativeElement, true, false, true); await wait(DEBOUNCETIME); fix.detectChanges(); expect(cell.selected).toBeTruthy(); - expect(cell.focused).toBeFalsy(); - expect(firstRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); - - await GridFunctions.expandCollapceGroupRow(fix, groupRow, cell); - })); - - it('expand/colapse row with arrow keys', (async () => { - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); - - const groupRow = grid.groupsRowList.toArray()[0]; - groupRow.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); - fix.detectChanges(); - - await GridFunctions.expandCollapceGroupRow(fix, groupRow, null); + GridSelectionFunctions.verifyRowCheckboxIsNotFocused(firstRow.nativeElement); + GridFunctions.verifyGroupRowIsFocused(groupRow); })); it('should focus grouped row when press arrow keys up or down', (async () => { - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); let cell = grid.getCellByColumn(1, 'ID'); cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); + await wait(); fix.detectChanges(); expect(cell.selected).toBe(true); expect(cell.focused).toBe(true); UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', cell.nativeElement, true); - await wait(100); + await wait(); fix.detectChanges(); let groupRow = grid.groupsRowList.toArray()[0]; cell = grid.getCellByColumn(1, 'ID'); - await GridFunctions.expandCollapceGroupRow(fix, groupRow, cell); + GridFunctions.verifyGroupRowIsFocused(groupRow); cell = grid.getCellByColumn(2, 'ProductName'); cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(100); + await wait(); fix.detectChanges(); expect(cell.focused).toBe(true); expect(cell.selected).toBe(true); UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', cell.nativeElement, true); - await wait(100); + await wait(); fix.detectChanges(); - cell = grid.getCellByColumn(2, 'ProductName'); groupRow = grid.groupsRowList.toArray()[1]; - - await GridFunctions.expandCollapceGroupRow(fix, groupRow, cell); + GridFunctions.verifyGroupRowIsFocused(groupRow); + expect(cell.selected).toBe(true); })); it('should correct work when press tab and sft+tab when there is a horizontal scroll', (async () => { @@ -1307,13 +1073,6 @@ describe('IgxGrid - Keyboard navigation #grid', () => { await wait(DEBOUNCETIME); fix.detectChanges(); - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - await wait(DEBOUNCETIME); - fix.detectChanges(); - const groupRow = grid.groupsRowList.toArray()[1]; let cell; @@ -1321,9 +1080,8 @@ describe('IgxGrid - Keyboard navigation #grid', () => { await wait(DEBOUNCETIME); fix.detectChanges(); - expect(groupRow.focused).toBe(true); - groupRow.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', shiftKey: true })); - await wait(100); + UIInteractions.triggerKeyDownEvtUponElem('tab', groupRow.nativeElement, true, false, true); + await wait(DEBOUNCETIME); fix.detectChanges(); cell = grid.getCellByColumn(2, 'Released'); @@ -1331,92 +1089,55 @@ describe('IgxGrid - Keyboard navigation #grid', () => { expect(cell.selected).toBe(true); UIInteractions.triggerKeyDownEvtUponElem('Tab', cell.nativeElement, true); - await wait(100); + await wait(DEBOUNCETIME); fix.detectChanges(); expect(cell.selected).toBe(true); - - await GridFunctions.expandCollapceGroupRow(fix, groupRow, cell); + GridFunctions.verifyGroupRowIsFocused(groupRow); UIInteractions.triggerKeyDownEvtUponElem('Tab', groupRow.nativeElement, true); - await wait(100); + await wait(DEBOUNCETIME); fix.detectChanges(); cell = grid.getCellByColumn(4, 'Downloads'); expect(cell.focused).toBe(true); expect(cell.selected).toBe(true); - cell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', shiftKey: true })); + UIInteractions.triggerKeyDownEvtUponElem('tab', cell.nativeElement, true, false, true); await wait(DEBOUNCETIME); fix.detectChanges(); expect(cell.selected).toBe(true); - expect(groupRow.focused).toBe(true); + GridFunctions.verifyGroupRowIsFocused(groupRow); })); - - it('should persist last selected cell column index when navigation up through group rows.', async () => { - fix.componentInstance.width = '400px'; - fix.componentInstance.height = '300px'; - grid.columnWidth = '200px'; - await wait(DEBOUNCETIME); - fix.detectChanges(); - - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - grid.groupBy({ - fieldName: 'Released', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); - grid.headerContainer.getScroll().scrollLeft = 1000; - await wait(100); - fix.detectChanges(); - grid.verticalScrollContainer.addScrollTop(1000); - await wait(200); - fix.detectChanges(); - const cell = grid.getCellByColumn(20, 'Released'); + it('should keep selected cell when expand/collapse grouped row ', (async () => { + const cell = grid.getCellByColumn(2, 'Released'); cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(DEBOUNCETIME); - fix.detectChanges(); - await GridFunctions.navigateVerticallyToIndex(grid, 20, 0, 4); - await wait(DEBOUNCETIME); + await wait(); fix.detectChanges(); - const row = grid.getRowByIndex(0); - expect(row instanceof IgxGridGroupByRowComponent).toBe(true); - expect(row.focused).toBe(true); - }); - it('should NOT clear selection from data cells when a group row is focused via KB navigation.', async () => { - fix.componentInstance.width = '800px'; - fix.componentInstance.height = '300px'; - grid.columnWidth = '200px'; - await wait(100); + UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', cell.nativeElement, true); + await wait(); fix.detectChanges(); - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - grid.groupBy({ - fieldName: 'Released', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); + const groupRow = grid.groupsRowList.toArray()[1]; + GridFunctions.verifyGroupRowIsFocused(groupRow); + expect(cell.selected).toBe(true); + + UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', groupRow.nativeElement, true, true); + await wait(); fix.detectChanges(); - const cell = grid.getCellByColumn(2, 'Downloads'); - cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(100); + expect(cell.selected).toBe(true); - await GridFunctions.navigateVerticallyToIndex(grid, 2, 0); + expect(groupRow.expanded).toBe(false); - await wait(DEBOUNCETIME); + UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', groupRow.nativeElement, true, true); + await wait(); fix.detectChanges(); - const row = grid.getRowByIndex(0); - expect(row instanceof IgxGridGroupByRowComponent).toBe(true); - expect(row.focused).toBe(true); + expect(cell.selected).toBe(true); - }); + expect(groupRow.expanded).toBe(true); + })); it('Custom KB navigation: should be able to scroll to a random row and pass a cb', async () => { fix.componentInstance.width = '600px'; @@ -1425,12 +1146,6 @@ describe('IgxGrid - Keyboard navigation #grid', () => { await wait(DEBOUNCETIME); fix.detectChanges(); - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); - grid.navigateTo(9, -1, (args) => { args.target.nativeElement.focus(); }); await wait(100); fix.detectChanges(); @@ -1447,15 +1162,10 @@ describe('IgxGrid - Keyboard navigation #grid', () => { await wait(DEBOUNCETIME); fix.detectChanges(); - grid.groupBy({ - fieldName: 'ProductName', dir: SortingDirection.Desc, - ignoreCase: false, strategy: DefaultSortingStrategy.instance() - }); - fix.detectChanges(); const gridKeydown = spyOn(grid.onGridKeydown, 'emit').and.callThrough(); const rowEl = grid.rowList.find(r => r.index === 0); - rowEl.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', ctrlKey: false })); + UIInteractions.triggerKeyDownEvtUponElem('Enter', rowEl.nativeElement, true); await wait(DEBOUNCETIME); fix.detectChanges(); @@ -1464,7 +1174,7 @@ describe('IgxGrid - Keyboard navigation #grid', () => { targetType: 'groupRow', target: rowEl, cancel: false, event: new KeyboardEvent('keydown') }); - rowEl.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', ctrlKey: false })); + UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', rowEl.nativeElement, true); await wait(DEBOUNCETIME); fix.detectChanges(); @@ -1473,113 +1183,5 @@ describe('IgxGrid - Keyboard navigation #grid', () => { targetType: 'groupRow', target: rowEl, cancel: false, event: new KeyboardEvent('keydown') }); }); - }); - }); - -@Component({ - template: ` - - - ` -}) -export class DefaultGridComponent { - - public data = [ - { index: 1, value: 1 }, - { index: 2, value: 2 } - ]; - - public selectedCell: IgxGridCellComponent; - public clickedCell: IgxGridCellComponent; - - @ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true }) - public instance: IgxGridComponent; - - public cellSelected(event: IGridCellEventArgs) { - this.selectedCell = event.cell; - } - - public cellClick(evt) { - this.clickedCell = evt.cell; - } - - public cellRightClick(evt) { - this.clickedCell = evt.cell; - } - - public doubleClick(evt) { - this.clickedCell = evt.cell; - } -} - -@Component({ - template: ` - - ` -}) -export class CtrlKeyKeyboardNagivationComponent { - - public data = [ - { index: 1, value: 1, other: 1, another: 1 }, - { index: 2, value: 2, other: 2, another: 2 } - ]; - - public selectedCell: IgxGridCellComponent; - - @ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true }) - public instance: IgxGridComponent; - - public cellSelected(event: IGridCellEventArgs) { - this.selectedCell = event.cell; - } -} - -@Component({ - template: ` - - - - Custom template - - ` -}) -export class DefaultGroupBYGridComponent extends DataParent { - public width = '800px'; - public height = null; - - @ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true }) - public grid: IgxGridComponent; - - @ViewChild('dropArea', { read: TemplateRef, static: true }) - public dropAreaTemplate: TemplateRef; - - public enableSorting = false; - public enableFiltering = false; - public enableResizing = false; - public enableEditing = false; - public enableGrouping = true; - public currentSortExpressions; - - public columnsCreated(column: IgxColumnComponent) { - column.sortable = this.enableSorting; - column.filterable = this.enableFiltering; - column.resizable = this.enableResizing; - column.editable = this.enableEditing; - column.groupable = this.enableGrouping; - } - public onGroupingDoneHandler(sortExpr) { - this.currentSortExpressions = sortExpr; - } -} diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-editing.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-editing.spec.ts index 446459761b7..107dd003daa 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-editing.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-editing.spec.ts @@ -24,7 +24,8 @@ import { IgxGridRowEditingWithoutEditableColumnsComponent, IgxGridCustomOverlayComponent, IgxGridRowEditingWithFeaturesComponent, - IgxGridEmptyRowEditTemplateComponent + IgxGridEmptyRowEditTemplateComponent, + VirtualGridComponent } from '../../test-utils/grid-samples.spec'; import { IgxGridTestComponent } from './grid.component.spec'; @@ -47,7 +48,8 @@ describe('IgxGrid - Row Editing #grid', () => { IgxGridTestComponent, IgxGridCustomOverlayComponent, IgxGridRowEditingWithFeaturesComponent, - IgxGridEmptyRowEditTemplateComponent + IgxGridEmptyRowEditTemplateComponent, + VirtualGridComponent ], imports: [ NoopAnimationsModule, IgxGridModule] @@ -281,12 +283,11 @@ describe('IgxGrid - Row Editing #grid', () => { it('Should properly exit pending state when committing row edit w/o changes', fakeAsync(() => { const initialDataLength = grid.data.length; const productNameCell = fix.debugElement.queryAll(By.css(CELL_CLASS))[2]; - const enterEvent = { key: 'enter', stopPropagation: () => { }, preventDefault: () => { } }; - productNameCell.triggerEventHandler('keydown', enterEvent); + UIInteractions.triggerEventHandlerKeyDown('enter', productNameCell); tick(16); fix.detectChanges(); expect(grid.getCellByKey(1, 'ProductName').editMode).toBeTruthy(); - productNameCell.triggerEventHandler('keydown', enterEvent); + UIInteractions.triggerEventHandlerKeyDown('enter', productNameCell); tick(16); fix.detectChanges(); expect(grid.getCellByKey(1, 'ProductName').editMode).toBeFalsy(); @@ -1897,6 +1898,53 @@ describe('IgxGrid - Row Editing #grid', () => { expect(columns[1].editable).toBeTruthy(); // column.editable not set expect(columns[2].editable).toBeFalsy(); // column.editable not set. Primary column })); + + it('should scroll into view not visible cell when in row edit and move from pinned to unpinned column', async () => { + const fix = TestBed.createComponent(VirtualGridComponent); + fix.detectChanges(); + const grid = fix.componentInstance.grid; + setupGridScrollDetection(fix, grid); + fix.detectChanges(); + + fix.componentInstance.columns = fix.componentInstance.generateCols(100, 50); + fix.componentInstance.data = fix.componentInstance.generateData(100); + + fix.detectChanges(); + await wait(DEBOUNCETIME); + + grid.primaryKey = '0'; + grid.rowEditable = true; + grid.columns.every(c => c.editable = true); + + grid.getColumnByName('2').pinned = true; + grid.getColumnByName('3').pinned = true; + grid.getColumnByName('3').editable = false; + grid.getColumnByName('0').editable = false; + + await wait(DEBOUNCETIME); + fix.detectChanges(); + + grid.navigateTo(0, 99); + + await wait(DEBOUNCETIME); + fix.detectChanges(); + + const rows = fix.nativeElement.querySelectorAll('igx-grid-row'); + const cell = rows[0].querySelectorAll('igx-grid-cell')[0]; + cell.dispatchEvent(new Event('focus')); + UIInteractions.triggerKeyDownEvtUponElem('F2', cell, true); + + await wait(DEBOUNCETIME); + fix.detectChanges(); + + expect(grid.crudService.cell.column.header).toBe('2'); + UIInteractions.triggerKeyDownEvtUponElem('tab', cell, true); + + await wait(DEBOUNCETIME); + fix.detectChanges(); + + expect(grid.crudService.cell.column.header).toBe('1'); + }); }); describe('Custom overlay', () => { @@ -2396,7 +2444,7 @@ describe('IgxGrid - Row Editing #grid', () => { it('Hide row editing dialog with group collapsing/expanding', fakeAsync(() => { const fix = TestBed.createComponent(IgxGridRowEditingWithFeaturesComponent); fix.detectChanges(); - const grid = fix.componentInstance.instance; + const grid = fix.componentInstance.grid; grid.primaryKey = 'ID'; fix.detectChanges(); @@ -2485,7 +2533,7 @@ describe('IgxGrid - Row Editing #grid', () => { fakeAsync(() => { const fix = TestBed.createComponent(IgxGridRowEditingWithFeaturesComponent); fix.detectChanges(); - const grid = fix.componentInstance.instance; + const grid = fix.componentInstance.grid; grid.primaryKey = 'ID'; fix.detectChanges(); grid.groupBy({ diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts index c6322a62f4c..c1e0f16d925 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts @@ -12,6 +12,7 @@ import { setupHierarchicalGridScrollDetection } from '../../test-utils/helper-ut import { FilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree'; import { FilteringLogic } from '../../data-operations/filtering-expression.interface'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; +import { GridFunctions } from '../../test-utils/grid-functions.spec'; describe('IgxHierarchicalGrid Virtualization #hGrid', () => { configureTestSuite(); @@ -161,7 +162,7 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { await wait(100); fixture.detectChanges(); const startIndex = hierarchicalGrid.verticalScrollContainer.state.startIndex; - const topOffset = fixture.debugElement.queryAll(By.css('.igx-display-container'))[1].nativeElement.style.top; + const topOffset = GridFunctions.getGridDisplayContainer(fixture).nativeElement.style.top; const secondRow = hierarchicalGrid.dataRowList.toArray()[1]; // expand second row (secondRow.nativeElement.children[0] as HTMLElement).click(); @@ -170,7 +171,7 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { expect(hierarchicalGrid.verticalScrollContainer.state.startIndex).toEqual(startIndex); expect( - parseInt(fixture.debugElement.queryAll(By.css('.igx-display-container'))[1].nativeElement.style.top, 10) - + parseInt(GridFunctions.getGridDisplayContainer(fixture).nativeElement.style.top, 10) - parseInt(topOffset, 10) ).toBeLessThanOrEqual(1); @@ -180,7 +181,7 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { // collapse second row expect(hierarchicalGrid.verticalScrollContainer.state.startIndex).toEqual(startIndex); expect( - parseInt(fixture.debugElement.queryAll(By.css('.igx-display-container'))[1].nativeElement.style.top, 10) - + parseInt(GridFunctions.getGridDisplayContainer(fixture).nativeElement.style.top, 10) - parseInt(topOffset, 10) ).toBeLessThanOrEqual(1); }); @@ -219,7 +220,7 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { await wait(100); fixture.detectChanges(); const startIndex = hierarchicalGrid.verticalScrollContainer.state.startIndex; - const topOffset = fixture.debugElement.queryAll(By.css('.igx-display-container'))[1].nativeElement.style.top; + const topOffset = GridFunctions.getGridDisplayContainer(fixture).nativeElement.style.top; const secondRow = hierarchicalGrid.rowList.toArray()[2]; // expand second row (secondRow.nativeElement.children[0] as HTMLElement).click(); @@ -228,7 +229,7 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { expect(hierarchicalGrid.verticalScrollContainer.state.startIndex).toEqual(startIndex); expect( - parseInt(fixture.debugElement.queryAll(By.css('.igx-display-container'))[1].nativeElement.style.top, 10) - + parseInt(GridFunctions.getGridDisplayContainer(fixture).nativeElement.style.top, 10) - parseInt(topOffset, 10) ).toBeLessThanOrEqual(1); @@ -238,7 +239,7 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { // collapse second row expect(hierarchicalGrid.verticalScrollContainer.state.startIndex).toEqual(startIndex); expect( - parseInt(fixture.debugElement.queryAll(By.css('.igx-display-container'))[1].nativeElement.style.top, 10) - + parseInt(GridFunctions.getGridDisplayContainer(fixture).nativeElement.style.top, 10) - parseInt(topOffset, 10) ).toBeLessThanOrEqual(1); }); diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts index 04f928cc000..8f9843defbb 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-functions.spec.ts @@ -29,6 +29,7 @@ const BANNER_ROW_CLASS = '.igx-banner__row'; const EDIT_OVERLAY_CONTENT = '.igx-overlay__content'; const PAGER_BUTTONS = '.igx-paginator__pager > button'; const ACTIVE_GROUP_ROW_CLASS = 'igx-grid__group-row--active'; +const GROUP_ROW_CLASS = 'igx-grid-groupby-row'; const CELL_SELECTED_CSS_CLASS = 'igx-grid__td--selected'; const ROW_DIV_SELECTION_CHECKBOX_CSS_CLASS = '.igx-grid__cbx-selection'; const ROW_SELECTION_CSS_CLASS = 'igx-grid__tr--selected'; @@ -41,9 +42,35 @@ const CHECKBOX_LBL_CSS_CLASS = '.igx-checkbox__composite'; const DEBOUNCETIME = 50; const GROUP_EXPANDER_CLASS = '.igx-grid__th-expander'; const GROUP_HEADER_CLASS = '.igx-grid__th-group-title'; +const CELL_CSS_CLASS = '.igx-grid__td'; +const ROW_CSS_CLASS = '.igx-grid__tr'; +const FOCUSED_CHECKBOX_CLASS = 'igx-checkbox--focused'; +const GRID_BODY_CLASS = '.igx-grid__tbody'; +const DISPLAY_CONTAINER = 'igx-display-container'; export class GridFunctions { + public static getRows(fix): DebugElement[] { + const rows: DebugElement[] = fix.debugElement.queryAll(By.css(ROW_CSS_CLASS)); + rows.shift(); + return rows; + } + + public static getRowCells(fix, rowIndex: number): DebugElement[] { + const allRows = GridFunctions.getRows(fix); + return allRows[rowIndex].queryAll(By.css(CELL_CSS_CLASS)); + } + + public static getGridDisplayContainer(fix): DebugElement { + const gridBody = fix.debugElement.query(By.css(GRID_BODY_CLASS)); + return gridBody.query(By.css(DISPLAY_CONTAINER)); + } + + public static getRowDisplayContainer(fix, index: number): DebugElement { + const row = GridFunctions.getRows(fix)[index]; + return row.query(By.css(DISPLAY_CONTAINER)); + } + public static getColGroup(grid: IgxGridComponent, headerName: string): IgxColumnGroupComponent { const colGroups = grid.columnList.filter(c => c.columnGroup && c.header === headerName); if (colGroups.length === 0) { @@ -84,40 +111,6 @@ export class GridFunctions { vScrollbar.scrollTop = newTop; } - public static navigateVerticallyToIndex = ( - grid: IgxGridComponent, - rowStartIndex: number, - rowEndIndex: number, - colIndex?: number, - shift = false) => new Promise(async (resolve, reject) => { - const dir = rowStartIndex > rowEndIndex ? 'ArrowUp' : 'ArrowDown'; - const row = grid.getRowByIndex(rowStartIndex); - const cIndx = colIndex || 0; - const colKey = grid.columnList.toArray()[cIndx].field; - const nextIndex = dir === 'ArrowUp' ? rowStartIndex - 1 : rowStartIndex + 1; - let elem; - if (row) { - elem = row instanceof IgxGridGroupByRowComponent ? - row : grid.getCellByColumn(row.index, colKey); - } else { - const summariRow = grid.summariesRowList.find(s => s.index === rowStartIndex); - if (summariRow) { - elem = summariRow.summaryCells.find(cell => cell.visibleColumnIndex === cIndx); - } - } - - if (rowStartIndex === rowEndIndex) { - resolve(); - return; - } - - UIInteractions.triggerKeyDownWithBlur(dir, elem.nativeElement, true, false, shift); - await wait(40); - - GridFunctions.navigateVerticallyToIndex(grid, nextIndex, rowEndIndex, colIndex, shift) - .then(() => { resolve(); }); - }) - public static navigateHorizontallyToIndex = ( grid: IgxGridComponent, cell: IgxGridCellComponent, @@ -191,36 +184,14 @@ export class GridFunctions { resolve(); }) - public static expandCollapceGroupRow = - (fix, groupRow: IgxGridGroupByRowComponent, - cell: IgxGridCellComponent) => new Promise(async (resolve, reject) => { - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains(ACTIVE_GROUP_ROW_CLASS)).toBe(true); - if (cell != null) { - expect(cell.selected).toBe(true); - } - UIInteractions.triggerKeyDownEvtUponElem('arrowleft', groupRow.nativeElement, true, true); - await wait(300); - fix.detectChanges(); - - expect(groupRow.expanded).toBe(false); - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains(ACTIVE_GROUP_ROW_CLASS)).toBe(true); - if (cell != null) { - expect(cell.selected).toBe(true); - } - UIInteractions.triggerKeyDownEvtUponElem('arrowright', groupRow.nativeElement, true, true); - await wait(100); - fix.detectChanges(); - - expect(groupRow.expanded).toBe(true); - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains(ACTIVE_GROUP_ROW_CLASS)).toBe(true); - if (cell != null) { - expect(cell.selected).toBe(true); - } - resolve(); - }) + public static getGroupedRows(fix): DebugElement[] { + return fix.debugElement.queryAll(By.css(GROUP_ROW_CLASS)); + } + + public static verifyGroupRowIsFocused(groupRow: IgxGridGroupByRowComponent, focused = true) { + expect(groupRow.focused).toBe(focused); + expect(groupRow.nativeElement.classList.contains(ACTIVE_GROUP_ROW_CLASS)).toBe(focused); + } public static getCurrentCellFromGrid(grid, row, cell) { const gridRow = grid.rowList.toArray()[row]; @@ -624,7 +595,7 @@ export class GridFunctions { fix.detectChanges(); // Enter key to submit - input.triggerEventHandler('keydown', UIInteractions.enterEvent); + UIInteractions.triggerEventHandlerKeyDown('Enter', input); fix.detectChanges(); } @@ -657,7 +628,8 @@ export class GridFunctions { public static submitFilterRowInput(fix) { const filterUIRow = fix.debugElement.query(By.css(FILTER_UI_ROW)); const input = filterUIRow.query(By.directive(IgxInputDirective)); - input.triggerEventHandler('keydown', UIInteractions.enterEvent); + + UIInteractions.triggerEventHandlerKeyDown('Enter', input); fix.detectChanges(); } @@ -1792,6 +1764,20 @@ export class GridSelectionFunctions { expect(cell.nativeElement.classList.contains(CELL_SELECTED_CSS_CLASS)).toBe(selected); } + // Check the grid selected cell and cell in in the onSelection function + public static verifyGridCellSelected(fix, cell: IgxGridCellComponent) { + const selectedCellFromGrid = cell.grid.selectedCells[0]; + const selectedCell = fix.componentInstance.selectedCell; + expect(cell.selected).toBe(true); + expect(selectedCell.value).toEqual(cell.value); + expect(selectedCell.column.field).toMatch(cell.column.field); + expect(selectedCell.rowIndex).toEqual(cell.rowIndex); + expect(selectedCellFromGrid.value).toEqual(cell.value); + expect(selectedCellFromGrid.column.field).toMatch(cell.column.field); + expect(selectedCellFromGrid.rowIndex).toEqual(cell.rowIndex); + } + + public static verifyRowSelected(row, selected = true, hasCheckbox = true) { expect(row.selected).toBe(selected); expect(row.nativeElement.classList.contains(ROW_SELECTION_CSS_CLASS)).toBe(selected); @@ -1848,6 +1834,11 @@ export class GridSelectionFunctions { } } + public static verifyRowCheckboxIsNotFocused(rowDOM: HTMLElement, focused = false) { + const rowCheckbox: HTMLElement = GridSelectionFunctions.getRowCheckbox(rowDOM); + expect(rowCheckbox.classList.contains(FOCUSED_CHECKBOX_CLASS)).toEqual(focused); + } + public static verifyHeaderRowHasCheckbox(parent, hasCheckbox = true, hasCheckboxDiv = true) { GridSelectionFunctions.verifyRowHasCheckbox(GridSelectionFunctions.getHeaderRow(parent), hasCheckbox, hasCheckboxDiv, true); } diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts index 8c97c308222..d2323dd0b0c 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts @@ -18,6 +18,7 @@ import { IgxGridComponent } from '../grids/grid'; import { IgxRowEditTabStopDirective } from '../grids/grid.rowEdit.directive'; import { IgxGridExcelStyleFilteringComponent } from '../grids/filtering/excel-style/grid.excel-style-filtering.component'; import { FilteringLogic } from '../data-operations/filtering-expression.interface'; +import { SortingDirection } from '../data-operations/sorting-expression.interface'; @Component({ template: `
@@ -215,6 +216,18 @@ export class ScrollsComponent extends BasicGridComponent { } } +@Component({ + template: GridTemplateStrings.declareGrid( + ` [primaryKey]="'ID'" + [width]="'900px'" + [height]="'900px'" + [columnWidth]="'200px'"`, + '', ColumnDefinitions.idNameJobTitleCompany) +}) +export class NoScrollsComponent extends BasicGridSearchComponent { + data = SampleTestData.personIDNameJobCompany(); +} + @Component({ template: GridTemplateStrings.declareGrid( ` rowSelection = "multiple"`, @@ -1534,7 +1547,7 @@ export class IgxGridRowEditingWithFeaturesComponent extends DataParent { public height = null; @ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true }) - public instance: IgxGridComponent; + public grid: IgxGridComponent; @ViewChild('dropArea', { read: TemplateRef, static: true }) public dropAreaTemplate: TemplateRef; @@ -1559,6 +1572,57 @@ export class IgxGridRowEditingWithFeaturesComponent extends DataParent { } } +@Component({ + template: ` + + + + Custom template + + ` +}) +export class IgxGridGroupByComponent extends DataParent implements OnInit { + public width = '600px'; + public height = '600px'; + + @ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true }) + public grid: IgxGridComponent; + + @ViewChild('dropArea', { read: TemplateRef, static: true }) + public dropAreaTemplate: TemplateRef; + + public enableSorting = false; + public enableFiltering = false; + public enableResizing = false; + public enableEditing = true; + public enableGrouping = true; + public enableRowEditing = false; + public currentSortExpressions; + + public columnsCreated(column: IgxColumnComponent) { + column.sortable = this.enableSorting; + column.filterable = this.enableFiltering; + column.resizable = this.enableResizing; + column.editable = this.enableEditing; + column.groupable = this.enableGrouping; + } + public onGroupingDoneHandler(sortExpr) { + this.currentSortExpressions = sortExpr; + } + + public ngOnInit() { + this.grid.groupingExpressions = [ + { fieldName: 'ProductName', dir: SortingDirection.Desc } + ]; + } +} + @Component({ template: ` diff --git a/projects/igniteui-angular/src/lib/test-utils/ui-interactions.spec.ts b/projects/igniteui-angular/src/lib/test-utils/ui-interactions.spec.ts index 37260e011af..34bb4202b01 100644 --- a/projects/igniteui-angular/src/lib/test-utils/ui-interactions.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/ui-interactions.spec.ts @@ -1,4 +1,5 @@ import { HorizontalAlignment, VerticalAlignment, Point } from '../services'; +import { DebugElement } from '@angular/core'; export function wait(ms = 0) { return new Promise((resolve, reject) => setTimeout(resolve, ms)); @@ -8,12 +9,26 @@ declare var Touch: { new(prop): Touch; }; export class UIInteractions { - public static enterEvent = { key: 'Enter', stopPropagation: () => { }, preventDefault: () => { } }; - public static spaceEvent = { key: ' ', stopPropagation: () => { }, preventDefault: () => { }, stopImmediatePropagation: () => { } }; - public static tabEvent = { key: 'Tab', stopPropagation: () => { }, preventDefault: () => { } }; public static escapeEvent = { key: 'Escape', stopPropagation: () => { }, preventDefault: () => { } }; - public static arrowDownEvent = { key: 'ArrowDown', stopPropagation: () => { }, preventDefault: () => { } }; - public static altAndArrowDownEvent = { key: 'ArrowDown', altKey: true, stopPropagation: () => { }, preventDefault: () => { } }; + + public static triggerEventHandlerKeyDown(keyPressed: string, elem: DebugElement, altKey = false, shift = false, ctrl = false) { + const event = { + key: keyPressed, + altKey: altKey, + shiftKey: shift, + ctrlKey: ctrl, + stopPropagation: () => { }, + stopImmediatePropagation: () => { }, + preventDefault: () => { } + }; + elem.triggerEventHandler('keydown', event); + } + + public static triggerEventHandlerKeyDownWithBlur(keyPressed: string, elem: DebugElement, altKey = false, shift = false, ctrl = false) { + UIInteractions.triggerEventHandlerKeyDown(keyPressed, elem, altKey, shift, ctrl); + elem.triggerEventHandler('blur', null); + } + public static sendInput(element, text, fix?) { element.nativeElement.value = text; @@ -70,7 +85,7 @@ export class UIInteractions { UIInteractions.simulatePointerEvent('pointerdown', nativeElement, elementRect.left, elementRect.top); nativeElement.dispatchEvent(new Event('focus')); UIInteractions.simulatePointerEvent('pointerup', nativeElement, elementRect.left, elementRect.top); - nativeElement.dispatchEvent(new Event('click', { bubbles: true})); + nativeElement.dispatchEvent(new Event('click', { bubbles: true })); } public static simulateMouseEvent(eventName: string, element, x, y) { @@ -177,8 +192,8 @@ export class UIInteractions { public static simulateWheelEvent(element, deltaX, deltaY) { const event = new WheelEvent('wheel', { deltaX: deltaX, deltaY: deltaY }); - Object.defineProperty(event, 'wheelDeltaX', {value: deltaX}); - Object.defineProperty(event, 'wheelDeltaY', {value: deltaY}); + Object.defineProperty(event, 'wheelDeltaX', { value: deltaX }); + Object.defineProperty(event, 'wheelDeltaY', { value: deltaY }); return new Promise((resolve, reject) => { element.dispatchEvent(event); @@ -194,7 +209,7 @@ export class UIInteractions { pageY: pageY }; const t = new Touch(touchInit); - const touchEventObject = new TouchEvent('touchstart', {touches: [t]}); + const touchEventObject = new TouchEvent('touchstart', { touches: [t] }); return new Promise((resolve, reject) => { element.dispatchEvent(touchEventObject); resolve(); @@ -208,7 +223,7 @@ export class UIInteractions { pageY: movedY }; const t = new Touch(touchInit); - const touchEventObject = new TouchEvent('touchmove', {touches: [t]}); + const touchEventObject = new TouchEvent('touchmove', { touches: [t] }); return new Promise((resolve, reject) => { element.dispatchEvent(touchEventObject); resolve(); @@ -223,7 +238,7 @@ export class UIInteractions { pageY: movedY }; const t = new Touch(touchInit); - const touchEventObject = new TouchEvent('touchend', {touches: [t]}); + const touchEventObject = new TouchEvent('touchend', { touches: [t] }); return new Promise((resolve, reject) => { element.dispatchEvent(touchEventObject); resolve(); @@ -240,11 +255,11 @@ export class UIInteractions { element: Element, hAlign: HorizontalAlignment = HorizontalAlignment.Center, vAlign: VerticalAlignment = VerticalAlignment.Middle): Point { - const elementRect = element.getBoundingClientRect(); - return { - x: elementRect.right + hAlign * elementRect.width, - y: elementRect.bottom + vAlign * elementRect.height - }; + const elementRect = element.getBoundingClientRect(); + return { + x: elementRect.right + hAlign * elementRect.width, + y: elementRect.bottom + vAlign * elementRect.height + }; } public static hoverElement(element: HTMLElement, bubbles: boolean = false) { @@ -256,7 +271,7 @@ export class UIInteractions { } public static clickDragDirective(fix, dragDir) { - dragDir.onPointerDown(new PointerEvent('pointerdown', { pointerId: 1})); + dragDir.onPointerDown(new PointerEvent('pointerdown', { pointerId: 1 })); dragDir.onPointerUp(new PointerEvent('pointerup')); fix.detectChanges(); }