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 feb2298dc29..5ff51e54ca1 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,10 +1,11 @@ -import { Component, ViewChild, OnInit } from '@angular/core'; -import { async, TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { Component, ViewChild, OnInit, TemplateRef } from '@angular/core'; +import { async, TestBed, fakeAsync, tick, ComponentFixture } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { take } from 'rxjs/operators'; -import { IgxColumnComponent, IgxGridCellComponent, IgxGridModule, } from './index'; +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 '../grid-base.component'; import { IgxStringFilteringOperand } from '../../../public_api'; import { SortingDirection } from '../../data-operations/sorting-expression.interface'; @@ -18,6 +19,41 @@ const CELL_CSS_CLASS = '.igx-grid__td'; describe('IgxGrid - Keyboard navigation', () => { configureTestSuite(); + const expandCollapceGroupRow = + (fix: ComponentFixture, + groupRow: IgxGridGroupByRowComponent, + cell: IgxGridCellComponent) => new Promise(async (resolve, reject) => { + expect(groupRow.focused).toBe(true); + expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); + if (cell != null) { + expect(cell.selected).toBe(true); + } + + groupRow.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'arrowleft', code: 'arrowleft', altKey: true })); + await wait(300); + fix.detectChanges(); + + expect(groupRow.expanded).toBe(false); + expect(groupRow.focused).toBe(true); + expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); + if (cell != null) { + expect(cell.selected).toBe(true); + } + + groupRow.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'arrowright', code: 'arrowright', altKey: true })); + await wait(100); + fix.detectChanges(); + + expect(groupRow.expanded).toBe(true); + expect(groupRow.focused).toBe(true); + expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); + if (cell != null) { + expect(cell.selected).toBe(true); + } + resolve(); + }); + + const navigateHorizontallyToIndex = ( grid: IgxGridComponent, cell: IgxGridCellComponent, @@ -80,7 +116,8 @@ describe('IgxGrid - Keyboard navigation', () => { CellEditingScrollTestComponent, ConditionalCellStyleTestComponent, ColumnEditablePropertyTestComponent, - GridWithScrollsComponent + GridWithScrollsComponent, + GridWithSelectionComponent ], imports: [NoopAnimationsModule, IgxGridModule.forRoot()] }).compileComponents(); @@ -669,6 +706,976 @@ describe('IgxGrid - Keyboard navigation', () => { 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.gridSelection1; + 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(30); + spyOn(grid.getCellByKey(3, 'Name'), 'onFocus').and.callThrough(); + fix.detectChanges(); + expect(targetCell.onFocus).toHaveBeenCalledTimes(1); + expect(targetCell.focused).toEqual(true); + + UIInteractions.triggerKeyDownEvtUponElem('arrowdown', targetCellElement, true); + await wait(30); + 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(GridWithSelectionComponent); + fix.detectChanges(); + const grid = fix.componentInstance.gridSelection3; + 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.triggerKeyDownEvtUponElem('arrowdown', targetCellElement, true); + await wait(200); + 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 toggle expand/collapse state of group row with ArrowRight/ArrowLeft key.', async(() => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + fix.componentInstance.width = '400px'; + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + const gRow = grid.groupsRowList.toArray()[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); + fix.detectChanges(); + + expect(gRow.expanded).toBe(false); + + gRow.element.nativeElement.dispatchEvent(evtArrowRight); + fix.detectChanges(); + expect(gRow.expanded).toBe(true); + })); + + it(`focus should stays over the group row when expand/collapse + with ArrowRight/ArrowLeft keys and grid is scrolled to bottom`, (async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + fix.componentInstance.width = '600px'; + fix.componentInstance.height = '500px'; + await wait(30); + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + + grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + await wait(100); + 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')); + await wait(30); + fix.detectChanges(); + + expect(lastGroupRow.classList.contains('igx-grid__group-row--active')).toBeTruthy(); + lastGroupRow.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', altKey: true })); + + await wait(100); + 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'); + })); + + it(`should be able to navigate down to the next row when expand the last group row + and grid is scrolled to bottom`, (async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + fix.componentInstance.width = '600px'; + fix.componentInstance.height = '500px'; + await wait(30); + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + + grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + await wait(100); + fix.detectChanges(); + + grid.groupsRowList.last.toggle(); + await wait(30); + fix.detectChanges(); + expect(grid.groupsRowList.last.expanded).toBeFalsy(); + + grid.groupsRowList.last.toggle(); + await wait(30); + 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 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); + + })); + + xit('should allow keyboard navigation through group rows.', (async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + + fix.componentInstance.width = '400px'; + fix.componentInstance.height = '300px'; + grid.columnWidth = '200px'; + await wait(); + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + await HelperUtils.navigateVerticallyToIndex(grid, 0, 9); + + let row = grid.getRowByIndex(9); + expect(row instanceof IgxGridRowComponent).toBe(true); + expect(row.focused).toBe(true); + expect(row.cells.toArray()[0].selected).toBe(true); + + await HelperUtils.navigateVerticallyToIndex(grid, 9, 0); + + row = grid.getRowByIndex(0); + expect(row instanceof IgxGridGroupByRowComponent).toBe(true); + expect(row.focused).toBe(true); + })); + + + describe('IgxGrid - keyboard navigation tests', () => { + configureTestSuite(); + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + IgxGridDefaultRenderingComponent + ], + imports: [ + NoopAnimationsModule, IgxGridModule.forRoot()] + }).compileComponents(); + })); + + it('should allow pageup/pagedown navigation when the grid is focused', async () => { + const fix = TestBed.createComponent(IgxGridDefaultRenderingComponent); + fix.detectChanges(); + const grid = fix.componentInstance.grid; + const pageDownKeyEvent = new KeyboardEvent('keydown', { + code: 'PageDown', + key: 'PageDown' + }); + const pageUpKeyEvent = new KeyboardEvent('keydown', { + code: 'PageUp', + key: 'PageUp' + }); + let currScrollTop; + grid.width = '800px'; + grid.height = '500px'; + fix.componentInstance.initColumnsRows(25, 25); + await wait(); + fix.detectChanges(); + grid.nativeElement.dispatchEvent(new Event('focus')); + + // testing the pagedown key + grid.nativeElement.dispatchEvent(pageDownKeyEvent); + grid.cdr.detectChanges(); + + await wait(); + currScrollTop = grid.verticalScrollContainer.getVerticalScroll().scrollTop; + expect(currScrollTop).toEqual(grid.verticalScrollContainer.igxForContainerSize); + + // testing the pageup key + grid.nativeElement.dispatchEvent(pageUpKeyEvent); + grid.cdr.detectChanges(); + await wait(); + currScrollTop = grid.parentVirtDir.getHorizontalScroll().scrollTop; + expect(currScrollTop).toEqual(0); + }); + }); + + describe('Row Editing - Navigation - Keyboard', () => { + it(`Should jump from first editable columns to overlay buttons`, fakeAsync(() => { + const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); + fixture.detectChanges(); + const grid = fixture.componentInstance.grid; + const targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); + const firstCellElement = targetCell.nativeElement; + fixture.detectChanges(); + targetCell.onKeydownEnterEditMode({}); + fixture.detectChanges(); + // TO button + fixture.componentInstance.moveNext(true); + fixture.detectChanges(); + expect(document.activeElement.outerHTML).toContain('igxrowedittabstop='); + expect(document.activeElement.textContent).toContain('Done'); + // FROM button to first + document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { + key: 'tab', + code: 'tab', + shiftKey: false + })); + tick(); + fixture.detectChanges(); + expect(fixture.componentInstance.getCurrentEditCell().column.field).toEqual('Downloads'); + expect(document.activeElement).toEqual(firstCellElement); + })); + + it(`Should jump from last editable columns to overlay buttons`, (async () => { + const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); + fixture.detectChanges(); + const grid = fixture.componentInstance.grid; + grid.parentVirtDir.getHorizontalScroll().scrollLeft = grid.parentVirtDir.getHorizontalScroll().clientWidth; + await wait(DEBOUNCETIME); + const targetCell = fixture.componentInstance.getCell(0, 'Test'); + const lastCellElement = targetCell.nativeElement; + targetCell.nativeElement.focus(); + fixture.detectChanges(); + targetCell.onKeydownEnterEditMode({}); + fixture.detectChanges(); + // TO button + fixture.componentInstance.moveNext(false); + fixture.detectChanges(); + expect(document.activeElement.outerHTML).toContain('igxrowedittabstop='); + expect(document.activeElement.textContent).toContain('Cancel'); + // FROM button to first + document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { + key: 'tab', + code: 'tab', + shiftKey: true + })); + fixture.detectChanges(); + expect(fixture.componentInstance.getCurrentEditCell().column.field).toEqual('Test'); + expect(document.activeElement).toEqual(lastCellElement); + })); + + it(`Should scroll editable column into view when navigating from buttons`, (async () => { + const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); + fixture.detectChanges(); + let currentEditCell: IgxGridCellComponent; + const grid = fixture.componentInstance.grid; + const targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); + fixture.detectChanges(); + grid.parentVirtDir.getHorizontalScroll().scrollLeft = 0; + await wait(500); + targetCell.onKeydownEnterEditMode({}); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + fixture.detectChanges(); + // go to 'Cancel' + (document.activeElement.previousElementSibling).focus(); + fixture.detectChanges(); + // go to LAST editable cell + document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', code: 'tab', shiftKey: true })); + fixture.detectChanges(); + await wait(500); + currentEditCell = fixture.componentInstance.getCurrentEditCell(); + expect(grid.parentVirtDir.getHorizontalScroll().scrollLeft).toBeGreaterThan(0); + expect(currentEditCell.column.field).toEqual('Test'); + // move to Cancel + fixture.componentInstance.moveNext(false); + fixture.detectChanges(); + // move to DONE + (document.activeElement.nextElementSibling).focus(); + fixture.detectChanges(); + // move to FIRST editable cell + document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', code: 'tab', shiftKey: false })); + fixture.detectChanges(); + await wait(500); + currentEditCell = fixture.componentInstance.getCurrentEditCell(); + expect(grid.parentVirtDir.getHorizontalScroll().scrollLeft).toEqual(0); + expect(currentEditCell.column.field).toEqual('Downloads'); + })); + + it(`Should skip non-editable columns`, fakeAsync(() => { + const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); + fixture.detectChanges(); + const grid = fixture.componentInstance.grid; + const targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); + fixture.detectChanges(); + targetCell.onKeydownEnterEditMode({}); + tick(); + fixture.detectChanges(); + const navSpyR = spyOn((grid).navigation, 'moveNextEditable').and.callThrough(); + const navSpyL = spyOn((grid).navigation, 'movePreviousEditable').and.callThrough(); + // Move forwards + fixture.componentInstance.moveNext(false); + tick(); + fixture.detectChanges(); + expect(navSpyR).toHaveBeenCalledTimes(1); + const newCell = (grid).gridAPI.get_cell_inEditMode(grid.id); + expect(newCell.cellID.columnID).toEqual(targetCell.columnIndex + 3); + expect(newCell.cell.column.editable).toEqual(true); + // Move backwards + fixture.componentInstance.moveNext(true); + tick(); + fixture.detectChanges(); + expect(navSpyL).toHaveBeenCalledTimes(1); + expect((grid).gridAPI.get_cell_inEditMode(grid.id).cellID.columnID).toEqual(targetCell.columnIndex); + expect((grid).gridAPI.get_cell_inEditMode(grid.id).cell.column.editable).toEqual(true); + + })); + + it(`Should skip non-editable columns when column pinning is enabled`, fakeAsync(() => { + const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); + fixture.detectChanges(); + const grid = fixture.componentInstance.grid; + let targetCell: IgxGridCellComponent; + let editedCell: IgxGridCellComponent; + fixture.componentInstance.pinnedFlag = true; + fixture.detectChanges(); + // from pinned to pinned + targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); + targetCell.onKeydownEnterEditMode({}); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + tick(); + fixture.detectChanges(); + // EXPECT focused cell to be 'Released' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + // from pinned to unpinned + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + tick(); + fixture.detectChanges(); + // EXPECT focused cell to be 'ReleaseDate' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('ReleaseDate'); + expect(editedCell.inEditMode).toEqual(true); + // from unpinned to pinned + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + tick(); + fixture.detectChanges(); + // EXPECT edited cell to be 'Released' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + })); + + it(`Should skip non-editable columns when column hiding is enabled`, fakeAsync(() => { + const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); + fixture.detectChanges(); + const grid = fixture.componentInstance.grid; + let targetCell: IgxGridCellComponent; + let editedCell: IgxGridCellComponent; + fixture.componentInstance.hiddenFlag = true; + fixture.detectChanges(); + // jump over 3 hidden, both editable and not + targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); + targetCell.onKeydownEnterEditMode({}); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + tick(); + fixture.detectChanges(); + // EXPECT focused cell to be 'Released' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + // jump over 1 hidden, editable + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + tick(); + fixture.detectChanges(); + // EXPECT focused cell to be 'Items' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Items'); + expect(editedCell.inEditMode).toEqual(true); + // jump over 1 hidden, editable + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + tick(); + fixture.detectChanges(); + // EXPECT edited cell to be 'Released' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + // jump over 3 hidden, both editable and not + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + tick(); + fixture.detectChanges(); + // EXPECT edited cell to be 'Downloads' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Downloads'); + expect(editedCell.inEditMode).toEqual(true); + })); + + it(`Should skip non-editable columns when column pinning & hiding is enabled`, fakeAsync(() => { + const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); + fixture.detectChanges(); + const grid = fixture.componentInstance.grid; + let targetCell: IgxGridCellComponent; + let editedCell: IgxGridCellComponent; + fixture.componentInstance.hiddenFlag = true; + fixture.componentInstance.pinnedFlag = true; + fixture.detectChanges(); + // jump over 1 hidden, pinned + targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); + targetCell.onKeydownEnterEditMode({}); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + tick(); + fixture.detectChanges(); + // EXPECT focused cell to be 'Released' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + // jump from pinned to unpinned + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + tick(); + fixture.detectChanges(); + // EXPECT focused cell to be 'Items' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Items'); + expect(editedCell.inEditMode).toEqual(true); + // jump back to pinned + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + tick(); + fixture.detectChanges(); + // EXPECT edited cell to be 'Released' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + // jump over 1 hidden, pinned + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + tick(); + fixture.detectChanges(); + // EXPECT edited cell to be 'Downloads' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Downloads'); + expect(editedCell.inEditMode).toEqual(true); + })); + + it(`Should skip non-editable columns when column grouping is enabled`, (async () => { + const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); + fixture.detectChanges(); + const grid = fixture.componentInstance.grid; + let targetCell: IgxGridCellComponent; + let editedCell: IgxGridCellComponent; + fixture.componentInstance.columnGroupingFlag = true; + fixture.detectChanges(); + targetCell = fixture.componentInstance.focusGridCell(0, 'ReleaseDate'); + targetCell.onKeydownEnterEditMode({}); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + fixture.detectChanges(); + // Should disregards the Igx-Column-Group component + // EXPECT focused cell to be 'Released' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + // Go forwards, jump over Category and group end + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + await wait(DEBOUNCETIME); + fixture.detectChanges(); + // EXPECT focused cell to be 'Items' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Items'); + expect(editedCell.inEditMode).toEqual(true); + // Go backwards, jump over group end and return to 'Released' + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + fixture.detectChanges(); + // EXPECT focused cell to be 'Released' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + await wait(DEBOUNCETIME); + // Go to release date + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + fixture.detectChanges(); + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('ReleaseDate'); + expect(editedCell.inEditMode).toEqual(true); + })); + + it(`Should skip non-editable columns when column when all column features are enabled`, fakeAsync(() => { + const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); + fixture.detectChanges(); + const grid = fixture.componentInstance.grid; + let targetCell: IgxGridCellComponent; + let editedCell: IgxGridCellComponent; + fixture.componentInstance.hiddenFlag = true; + fixture.componentInstance.pinnedFlag = true; + fixture.componentInstance.columnGroupingFlag = true; + fixture.detectChanges(); + targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); + targetCell.onKeydownEnterEditMode({}); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + tick(); + fixture.detectChanges(); + // Move from Downloads over hidden to Released in Column Group + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(false); + tick(); + fixture.detectChanges(); + // Move from pinned 'Released' (in Column Group) to unpinned 'Items' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Items'); + expect(editedCell.inEditMode).toEqual(true); + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + tick(); + fixture.detectChanges(); + // Move back to pinned 'Released' (in Column Group) + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Released'); + expect(editedCell.inEditMode).toEqual(true); + editedCell.nativeElement.focus(); + fixture.detectChanges(); + fixture.componentInstance.moveNext(true); + tick(); + fixture.detectChanges(); + // Move back to pinned 'Downloads' + editedCell = fixture.componentInstance.getCurrentEditCell(); + expect(editedCell.column.field).toEqual('Downloads'); + expect(editedCell.inEditMode).toEqual(true); + })); + }); + + + xit('should persist last selected cell column index when navigation down through group rows.', async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + fix.componentInstance.width = '400px'; + fix.componentInstance.height = '300px'; + grid.columnWidth = '200px'; + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + + grid.parentVirtDir.getHorizontalScroll().scrollLeft = 1000; + await wait(); + let cell = grid.getCellByColumn(2, 'Released'); + cell.onFocus(new Event('focus')); + + await HelperUtils.navigateVerticallyToIndex(grid, 0, 9, 4); + + grid.markForCheck(); + fix.detectChanges(); + const row = grid.getRowByIndex(9); + cell = grid.getCellByColumn(9, 'Released'); + expect(row instanceof IgxGridRowComponent).toBe(true); + expect(row.focused).toBe(true); + expect(cell.selected).toBe(true); + }); + + it('keyboard navigation - should focus grouped row when press Tab key and Shift + Tab on a cell', (async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + + fix.componentInstance.width = '600px'; + fix.componentInstance.height = '600px'; + grid.columnWidth = '100px'; + await wait(100); + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + let cell = grid.getCellByColumn(2, 'Released'); + cell.nativeElement.dispatchEvent(new Event('focus')); + await wait(100); + fix.detectChanges(); + + UIInteractions.triggerKeyDownEvtUponElem('tab', cell.nativeElement, true); + await wait(100); + fix.detectChanges(); + + let groupRow = grid.groupsRowList.toArray()[1]; + cell = grid.getCellByColumn(2, 'Released'); + await expandCollapceGroupRow(fix, groupRow, cell); + + UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', groupRow.nativeElement, true); + await wait(300); + 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); + 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 })); + await wait(500); + fix.detectChanges(); + + groupRow = grid.groupsRowList.toArray()[2]; + cell = grid.getCellByColumn(7, 'Downloads'); + await expandCollapceGroupRow(fix, groupRow, cell); + })); + + it('keyboard navigation - should correct work when press tab and sft+tab on a grouped row', (async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + + fix.componentInstance.width = '600px'; + fix.componentInstance.height = '600px'; + grid.columnWidth = '100px'; + await wait(50); + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + + let groupRow = grid.groupsRowList.toArray()[0]; + groupRow.nativeElement.dispatchEvent(new Event('focus')); + await wait(50); + fix.detectChanges(); + + groupRow = grid.groupsRowList.toArray()[0]; + expect(groupRow.focused).toBe(true); + expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); + UIInteractions.triggerKeyDownEvtUponElem('tab', groupRow.nativeElement, true); + await wait(100); + fix.detectChanges(); + + let cell = grid.getCellByColumn(1, 'Downloads'); + expect(cell.selected).toBe(true); + expect(cell.focused).toBe(true); + + groupRow = grid.groupsRowList.toArray()[1]; + groupRow.nativeElement.dispatchEvent(new Event('focus')); + await wait(100); + 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); + fix.detectChanges(); + + cell = grid.getCellByColumn(2, 'Released'); + expect(cell.selected).toBe(true); + expect(cell.focused).toBe(true); + })); + + it('keyboard navigation - should correct work when press tab and sft+tab on a grouped row when have row selectors', (async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + + fix.componentInstance.width = '600px'; + fix.componentInstance.height = '600px'; + grid.columnWidth = '100px'; + grid.rowSelectable = true; + await wait(30); + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + await wait(30); + 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(30); + fix.detectChanges(); + + expect(groupRow.focused).toBe(true); + expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); + + UIInteractions.triggerKeyDownEvtUponElem('tab', groupRow.nativeElement, true); + await wait(100); + fix.detectChanges(); + + expect(cell.selected).toBeTruthy(); + expect(cell.focused).toBeTruthy(); + expect(firstRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); + + cell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', shiftKey: true })); + await wait(30); + fix.detectChanges(); + + expect(cell.selected).toBeTruthy(); + expect(cell.focused).toBeFalsy(); + expect(firstRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); + + await expandCollapceGroupRow(fix, groupRow, cell); + })); + + it('keyboard navigation - expand/colapse row with arrow keys', (async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + + fix.componentInstance.width = '600px'; + fix.componentInstance.height = '600px'; + grid.columnWidth = '100px'; + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + + const groupRow = grid.groupsRowList.toArray()[0]; + groupRow.nativeElement.dispatchEvent(new Event('focus')); + await wait(50); + fix.detectChanges(); + + await expandCollapceGroupRow(fix, groupRow, null); + })); + + it('keyboard navigation - should focus grouped row when press arrow keys up or down', (async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + + fix.componentInstance.width = '600px'; + fix.componentInstance.height = '600px'; + grid.columnWidth = '100px'; + await wait(50); + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + let cell = grid.getCellByColumn(1, 'ID'); + cell.nativeElement.dispatchEvent(new Event('focus')); + await wait(50); + fix.detectChanges(); + + expect(cell.selected).toBe(true); + expect(cell.focused).toBe(true); + UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', cell.nativeElement, true); + await wait(100); + fix.detectChanges(); + + let groupRow = grid.groupsRowList.toArray()[0]; + cell = grid.getCellByColumn(1, 'ID'); + await expandCollapceGroupRow(fix, groupRow, cell); + + cell = grid.getCellByColumn(2, 'ProductName'); + cell.nativeElement.dispatchEvent(new Event('focus')); + await wait(100); + fix.detectChanges(); + + expect(cell.focused).toBe(true); + expect(cell.selected).toBe(true); + UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', cell.nativeElement, true); + await wait(100); + fix.detectChanges(); + + cell = grid.getCellByColumn(2, 'ProductName'); + groupRow = grid.groupsRowList.toArray()[1]; + + await expandCollapceGroupRow(fix, groupRow, cell); + })); + + it('keyboard navigation - should correct work when press tab and sft+tab when there is a horizontal scroll', (async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + + fix.componentInstance.width = '600px'; + fix.componentInstance.height = '600px'; + grid.columnWidth = '200px'; + await wait(30); + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + await wait(30); + fix.detectChanges(); + + const groupRow = grid.groupsRowList.toArray()[1]; + const secondRow = grid.getRowByIndex(2); + let cell; + + groupRow.nativeElement.dispatchEvent(new Event('focus')); + await wait(30); + fix.detectChanges(); + + expect(groupRow.focused).toBe(true); + groupRow.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', shiftKey: true })); + await wait(100); + fix.detectChanges(); + + cell = grid.getCellByColumn(2, 'Released'); + expect(cell.focused).toBe(true); + expect(cell.selected).toBe(true); + + UIInteractions.triggerKeyDownEvtUponElem('Tab', cell.nativeElement, true); + await wait(100); + fix.detectChanges(); + expect(cell.selected).toBe(true); + + await expandCollapceGroupRow(fix, groupRow, cell); + + UIInteractions.triggerKeyDownEvtUponElem('Tab', groupRow.nativeElement, true); + await wait(100); + 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 })); + await wait(30); + fix.detectChanges(); + + expect(cell.selected).toBe(true); + expect(groupRow.focused).toBe(true); + })); + + + xit('should persist last selected cell column index when navigation up through group rows.', async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + + fix.componentInstance.width = '400px'; + fix.componentInstance.height = '300px'; + grid.columnWidth = '200px'; + await wait(); + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + grid.parentVirtDir.getHorizontalScroll().scrollLeft = 1000; + await wait(100); + fix.detectChanges(); + grid.verticalScrollContainer.addScrollTop(1000); + await wait(200); + fix.detectChanges(); + const cell = grid.getCellByColumn(20, 'Released'); + cell.onFocus(new Event('focus')); + await wait(50); + fix.detectChanges(); + // await HelperUtils.navigateVerticallyToIndex(grid, 20, 0, 4); + const row = grid.getRowByIndex(0); + expect(row instanceof IgxGridGroupByRowComponent).toBe(true); + expect(row.focused).toBe(true); + }); + + xit('should NOT clear selection from data cells when a group row is focused via KB navigation.', async () => { + const fix = TestBed.createComponent(DefaultGroupBYGridComponent); + const grid = fix.componentInstance.instance; + + fix.componentInstance.width = '800px'; + fix.componentInstance.height = '300px'; + grid.columnWidth = '200px'; + fix.detectChanges(); + + grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); + grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); + fix.detectChanges(); + const cell = grid.getCellByColumn(2, 'Downloads'); + cell.onClick(null); + await wait(); + expect(cell.selected).toBe(true); + await HelperUtils.navigateVerticallyToIndex(grid, 2, 0); + + fix.detectChanges(); + const row = grid.getRowByIndex(0); + expect(row instanceof IgxGridGroupByRowComponent).toBe(true); + expect(row.focused).toBe(true); + expect(cell.selected).toBe(true); + }); + + it('should allow keyboard navigation to first/last cell with Ctrl when there are the pinned columns.', async () => { + const fix = TestBed.createComponent(GridPinningComponent); + fix.detectChanges(); + + await wait(); + const grid = fix.componentInstance.instance; + grid.getColumnByName('CompanyName').pinned = true; + grid.getColumnByName('ContactName').pinned = true; + fix.detectChanges(); + const cells = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS)); + let cell = cells[0]; + + cell.triggerEventHandler('focus', {}); + await wait(); + fix.detectChanges(); + + expect(fix.componentInstance.selectedCell.value).toEqual('Maria Anders'); + expect(fix.componentInstance.selectedCell.column.field).toMatch('ContactName'); + + cell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'arrowright', ctrlKey: true })); + await wait(30); + fix.detectChanges(); + + expect(fix.componentInstance.selectedCell.value).toEqual('030-0076545'); + expect(fix.componentInstance.selectedCell.column.field).toMatch('Fax'); + + cell = cells[cells.length - 1]; + cell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'arrowleft', ctrlKey: true })); + await wait(30); + 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'); + }); }); @@ -1019,3 +2026,291 @@ export class GridWithScrollsComponent implements OnInit { } } +@Component({ + template: ` + + + ` +}) +export class GridWithSelectionComponent implements OnInit { + public data = []; + + @ViewChild('gridSelection3', {read: IgxGridComponent}) + public gridSelection3: IgxGridComponent; + + ngOnInit() { + const bigData = []; + for (let i = 0; i < 100; i++) { + for (let j = 0; j < 5; j++) { + bigData.push({ + ID: i.toString() + '_' + j.toString(), + Column1: i * j, + Column2: i * j * Math.pow(10, i), + Column3: i * j * Math.pow(100, i) + }); + } + } + this.data = bigData; + } +} + +@Component({ + template: ` + + + + + + + ` +}) +export class GridWithPrimaryKeyComponent { + public data = data; + + @ViewChild('gridSelection1', {read: IgxGridComponent}) + public gridSelection1: IgxGridComponent; +} + +let data = [ + {ID: 1, Name: 'Casey Houston', JobTitle: 'Vice President', HireDate: '2017-06-19T11:43:07.714Z'}, + {ID: 2, Name: 'Gilberto Todd', JobTitle: 'Director', HireDate: '2015-12-18T11:23:17.714Z'}, + {ID: 3, Name: 'Tanya Bennett', JobTitle: 'Director', HireDate: '2005-11-18T11:23:17.714Z'}, + {ID: 4, Name: 'Jack Simon', JobTitle: 'Software Developer', HireDate: '2008-12-18T11:23:17.714Z'}, + {ID: 5, Name: 'Celia Martinez', JobTitle: 'Senior Software Developer', HireDate: '2007-12-19T11:23:17.714Z'}, + {ID: 6, Name: 'Erma Walsh', JobTitle: 'CEO', HireDate: '2016-12-18T11:23:17.714Z'}, + {ID: 7, Name: 'Debra Morton', JobTitle: 'Associate Software Developer', HireDate: '2005-11-19T11:23:17.714Z'}, + {ID: 8, Name: 'Erika Wells', JobTitle: 'Software Development Team Lead', HireDate: '2005-10-14T11:23:17.714Z'}, + {ID: 9, Name: 'Leslie Hansen', JobTitle: 'Associate Software Developer', HireDate: '2013-10-10T11:23:17.714Z'}, + {ID: 10, Name: 'Eduardo Ramirez', JobTitle: 'Manager', HireDate: '2011-11-28T11:23:17.714Z'} +]; + + +@Component({ + template: ` + + + ` +}) +export class IgxGridDefaultRenderingComponent { + public columns = []; + public data = []; + + public changeInitColumns = false; + + @ViewChild('grid', { read: IgxGridComponent }) + public grid: IgxGridComponent; + + public initColumnsRows(rowsNumber: number, columnsNumber: number): void { + this.columns = []; + this.data = []; + let i, j: number; + for (i = 0; i < columnsNumber; i++) { + this.columns.push({ + key: 'col' + i, + dataType: 'number' + }); + } + for (i = 0; i < rowsNumber; i++) { + const record = {}; + for (j = 0; j < columnsNumber; j++) { + record[this.columns[j].key] = j * i; + } + this.data.push(record); + } + } + + public isHorizonatScrollbarVisible() { + const scrollbar = this.grid.parentVirtDir.getHorizontalScroll(); + return scrollbar.offsetWidth < scrollbar.children[0].offsetWidth; + } + + public initColumns(column) { + if (this.changeInitColumns) { + switch (this.grid.columnList.length) { + case 5: + if (column.index === 0 || column.index === 4) { + column.width = '100px'; + } + break; + case 30: + if (column.index === 0 || column.index === 5 || column.index === 3 || column.index === 10 || column.index === 25) { + column.width = '200px'; + } + break; + case 150: + if (column.index === 0 || column.index === 5 || column.index === 3 || column.index === 10 || column.index === 50) { + column.width = '500px'; + } + break; + } + } + } +} + + +@Component({ + template: ` + + + + + + + + + + + + + + + + + + + + + + + + + + ` +}) +export class IgxGridWithEditingAndFeaturesComponent { + /* Data fields: Downloads:number, ID: number, ProductName: string, ReleaseDate: Date, + Released: boolean, Category: string, Items: string, Test: string. */ + public pinnedFlag = false; + public hiddenFlag = false; + public columnGroupingFlag = false; + public data = SampleTestData.generateProductData(11); + @ViewChild('grid', { read: IgxGridComponent }) public grid: IgxGridComponent; + public moveNext(shiftKey: boolean): void { + this.getCurrentEditCell().dispatchEvent(new KeyboardEvent('keydown', { + key: 'tab', + code: 'tab', + shiftKey + })); + } + public focusGridCell(rowIndex: number, columnName: string): IgxGridCellComponent { + const targetCell = this.getCell(rowIndex, columnName); + targetCell.onFocus(new Event('focus')); + return targetCell; + } + + public getCell(rowIndex: number, columnName: string): IgxGridCellComponent { + return this.grid.getCellByColumn(rowIndex, columnName); + } + + public getCurrentEditCell(): IgxGridCellComponent { + const grid = this.grid as any; + const currentCell = grid.gridAPI.get_cell_inEditMode(this.grid.id); + return this.grid.getCellByColumn(currentCell.cellID.rowIndex, currentCell.cell.column.field); + } + + public get gridAPI() { + return (this.grid).gridAPI; + } + + public get cellInEditMode() { + return this.gridAPI.get_cell_inEditMode(this.grid.id).cell; + } +} + +@Component({ + template: ` + + + + Custom template + + ` +}) +export class DefaultGroupBYGridComponent extends DataParent { + public width = '800px'; + public height = null; + + @ViewChild(IgxGridComponent, { read: IgxGridComponent }) + public instance: IgxGridComponent; + + @ViewChild('dropArea', { read: TemplateRef }) + 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; + } +} + +@Component({ + template: ` + + + + + ` +}) +export class GridPinningComponent { + public selectedCell; + public data = [{ + ID: 'ALFKI', + CompanyName: 'Alfreds Futterkiste', + ContactName: 'Maria Anders', + ContactTitle: 'Sales Representative', + Address: 'Obere Str. 57', + City: 'Berlin', + Region: null, + PostalCode: '12209', + Country: 'Germany', + Phone: '030-0074321', + Fax: '030-0076545' + }]; + public columns = [ + { field: 'ID', width: 100 }, + { field: 'CompanyName', width: 300 }, + { field: 'ContactName', width: 200 }, + { field: 'ContactTitle', width: 200 }, + { field: 'Address', width: 300 }, + { field: 'City', width: 100 }, + { field: 'Region', width: 100 }, + { field: 'PostalCode', width: 100 }, + { field: 'Phone', width: 150 }, + { field: 'Fax', width: 150 } + ]; + + @ViewChild(IgxGridComponent, { read: IgxGridComponent }) + public instance: IgxGridComponent; + + public columnPinningHandler($event) { + $event.insertAtIndex = 0; + } + public cellSelected(event: IGridCellEventArgs) { + this.selectedCell = event.cell; + } +} \ No newline at end of file diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-selection.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-selection.spec.ts index cffa7c47d5a..395d2fa01c0 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-selection.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-selection.spec.ts @@ -124,60 +124,7 @@ describe('IgxGrid - Row Selection', () => { expect(grid.getRowByIndex(1).rowData[grid.primaryKey]).toEqual(7); }); - 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.gridSelection1; - 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(30); - spyOn(grid.getCellByKey(3, 'Name'), 'onFocus').and.callThrough(); - fix.detectChanges(); - expect(targetCell.onFocus).toHaveBeenCalledTimes(1); - expect(targetCell.focused).toEqual(true); - - UIInteractions.triggerKeyDownEvtUponElem('arrowdown', targetCellElement, true); - await wait(30); - 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(GridWithSelectionComponent); - fix.detectChanges(); - const grid = fix.componentInstance.gridSelection3; - 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.triggerKeyDownEvtUponElem('arrowdown', targetCellElement, true); - await wait(200); - 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 persist through paging', (async () => { const fix = TestBed.createComponent(GridWithPagingAndSelectionComponent); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts index 9f095e138f3..ac6adb720ea 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts @@ -751,55 +751,6 @@ describe('IgxGrid Component Tests', () => { }); }); - describe('IgxGrid - keyboard navigation tests', () => { - configureTestSuite(); - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - IgxGridDefaultRenderingComponent - ], - imports: [ - NoopAnimationsModule, IgxGridModule.forRoot()] - }).compileComponents(); - })); - - it('should allow pageup/pagedown navigation when the grid is focused', async () => { - const fix = TestBed.createComponent(IgxGridDefaultRenderingComponent); - fix.detectChanges(); - const grid = fix.componentInstance.grid; - const pageDownKeyEvent = new KeyboardEvent('keydown', { - code: 'PageDown', - key: 'PageDown' - }); - const pageUpKeyEvent = new KeyboardEvent('keydown', { - code: 'PageUp', - key: 'PageUp' - }); - let currScrollTop; - grid.width = '800px'; - grid.height = '500px'; - fix.componentInstance.initColumnsRows(25, 25); - await wait(); - fix.detectChanges(); - grid.nativeElement.dispatchEvent(new Event('focus')); - - // testing the pagedown key - grid.nativeElement.dispatchEvent(pageDownKeyEvent); - grid.cdr.detectChanges(); - - await wait(); - currScrollTop = grid.verticalScrollContainer.getVerticalScroll().scrollTop; - expect(currScrollTop).toEqual(grid.verticalScrollContainer.igxForContainerSize); - - // testing the pageup key - grid.nativeElement.dispatchEvent(pageUpKeyEvent); - grid.cdr.detectChanges(); - await wait(); - currScrollTop = grid.parentVirtDir.getHorizontalScroll().scrollTop; - expect(currScrollTop).toEqual(0); - }); - }); - describe('IgxGrid - API methods', () => { configureTestSuite(); beforeEach(async(() => { @@ -1141,371 +1092,7 @@ describe('IgxGrid Component Tests', () => { })); }); - - describe('Row Editing - Navigation - Keyboard', () => { - it(`Should jump from first editable columns to overlay buttons`, fakeAsync(() => { - const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); - fixture.detectChanges(); - const grid = fixture.componentInstance.grid; - const targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); - const firstCellElement = targetCell.nativeElement; - fixture.detectChanges(); - targetCell.onKeydownEnterEditMode({}); - fixture.detectChanges(); - // TO button - fixture.componentInstance.moveNext(true); - fixture.detectChanges(); - expect(document.activeElement.outerHTML).toContain('igxrowedittabstop='); - expect(document.activeElement.textContent).toContain('Done'); - // FROM button to first - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { - key: 'tab', - code: 'tab', - shiftKey: false - })); - tick(); - fixture.detectChanges(); - expect(fixture.componentInstance.getCurrentEditCell().column.field).toEqual('Downloads'); - expect(document.activeElement).toEqual(firstCellElement); - })); - - it(`Should jump from last editable columns to overlay buttons`, (async () => { - const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); - fixture.detectChanges(); - const grid = fixture.componentInstance.grid; - grid.parentVirtDir.getHorizontalScroll().scrollLeft = grid.parentVirtDir.getHorizontalScroll().clientWidth; - await wait(DEBOUNCETIME); - const targetCell = fixture.componentInstance.getCell(0, 'Test'); - const lastCellElement = targetCell.nativeElement; - targetCell.nativeElement.focus(); - fixture.detectChanges(); - targetCell.onKeydownEnterEditMode({}); - fixture.detectChanges(); - // TO button - fixture.componentInstance.moveNext(false); - fixture.detectChanges(); - expect(document.activeElement.outerHTML).toContain('igxrowedittabstop='); - expect(document.activeElement.textContent).toContain('Cancel'); - // FROM button to first - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { - key: 'tab', - code: 'tab', - shiftKey: true - })); - fixture.detectChanges(); - expect(fixture.componentInstance.getCurrentEditCell().column.field).toEqual('Test'); - expect(document.activeElement).toEqual(lastCellElement); - })); - - it(`Should scroll editable column into view when navigating from buttons`, (async () => { - const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); - fixture.detectChanges(); - let currentEditCell: IgxGridCellComponent; - const grid = fixture.componentInstance.grid; - const targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); - fixture.detectChanges(); - grid.parentVirtDir.getHorizontalScroll().scrollLeft = 0; - await wait(500); - targetCell.onKeydownEnterEditMode({}); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - fixture.detectChanges(); - // go to 'Cancel' - (document.activeElement.previousElementSibling).focus(); - fixture.detectChanges(); - // go to LAST editable cell - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', code: 'tab', shiftKey: true })); - fixture.detectChanges(); - await wait(500); - currentEditCell = fixture.componentInstance.getCurrentEditCell(); - expect(grid.parentVirtDir.getHorizontalScroll().scrollLeft).toBeGreaterThan(0); - expect(currentEditCell.column.field).toEqual('Test'); - // move to Cancel - fixture.componentInstance.moveNext(false); - fixture.detectChanges(); - // move to DONE - (document.activeElement.nextElementSibling).focus(); - fixture.detectChanges(); - // move to FIRST editable cell - document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', code: 'tab', shiftKey: false })); - fixture.detectChanges(); - await wait(500); - currentEditCell = fixture.componentInstance.getCurrentEditCell(); - expect(grid.parentVirtDir.getHorizontalScroll().scrollLeft).toEqual(0); - expect(currentEditCell.column.field).toEqual('Downloads'); - })); - - it(`Should skip non-editable columns`, fakeAsync(() => { - const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); - fixture.detectChanges(); - const grid = fixture.componentInstance.grid; - const targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); - fixture.detectChanges(); - targetCell.onKeydownEnterEditMode({}); - tick(); - fixture.detectChanges(); - const navSpyR = spyOn((grid).navigation, 'moveNextEditable').and.callThrough(); - const navSpyL = spyOn((grid).navigation, 'movePreviousEditable').and.callThrough(); - // Move forwards - fixture.componentInstance.moveNext(false); - tick(); - fixture.detectChanges(); - expect(navSpyR).toHaveBeenCalledTimes(1); - const newCell = (grid).gridAPI.get_cell_inEditMode(grid.id); - expect(newCell.cellID.columnID).toEqual(targetCell.columnIndex + 3); - expect(newCell.cell.column.editable).toEqual(true); - // Move backwards - fixture.componentInstance.moveNext(true); - tick(); - fixture.detectChanges(); - expect(navSpyL).toHaveBeenCalledTimes(1); - expect((grid).gridAPI.get_cell_inEditMode(grid.id).cellID.columnID).toEqual(targetCell.columnIndex); - expect((grid).gridAPI.get_cell_inEditMode(grid.id).cell.column.editable).toEqual(true); - - })); - - it(`Should skip non-editable columns when column pinning is enabled`, fakeAsync(() => { - const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); - fixture.detectChanges(); - const grid = fixture.componentInstance.grid; - let targetCell: IgxGridCellComponent; - let editedCell: IgxGridCellComponent; - fixture.componentInstance.pinnedFlag = true; - fixture.detectChanges(); - // from pinned to pinned - targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); - targetCell.onKeydownEnterEditMode({}); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - tick(); - fixture.detectChanges(); - // EXPECT focused cell to be 'Released' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - // from pinned to unpinned - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - tick(); - fixture.detectChanges(); - // EXPECT focused cell to be 'ReleaseDate' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('ReleaseDate'); - expect(editedCell.inEditMode).toEqual(true); - // from unpinned to pinned - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - tick(); - fixture.detectChanges(); - // EXPECT edited cell to be 'Released' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - })); - - it(`Should skip non-editable columns when column hiding is enabled`, fakeAsync(() => { - const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); - fixture.detectChanges(); - const grid = fixture.componentInstance.grid; - let targetCell: IgxGridCellComponent; - let editedCell: IgxGridCellComponent; - fixture.componentInstance.hiddenFlag = true; - fixture.detectChanges(); - // jump over 3 hidden, both editable and not - targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); - targetCell.onKeydownEnterEditMode({}); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - tick(); - fixture.detectChanges(); - // EXPECT focused cell to be 'Released' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - // jump over 1 hidden, editable - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - tick(); - fixture.detectChanges(); - // EXPECT focused cell to be 'Items' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Items'); - expect(editedCell.inEditMode).toEqual(true); - // jump over 1 hidden, editable - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - tick(); - fixture.detectChanges(); - // EXPECT edited cell to be 'Released' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - // jump over 3 hidden, both editable and not - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - tick(); - fixture.detectChanges(); - // EXPECT edited cell to be 'Downloads' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Downloads'); - expect(editedCell.inEditMode).toEqual(true); - })); - - it(`Should skip non-editable columns when column pinning & hiding is enabled`, fakeAsync(() => { - const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); - fixture.detectChanges(); - const grid = fixture.componentInstance.grid; - let targetCell: IgxGridCellComponent; - let editedCell: IgxGridCellComponent; - fixture.componentInstance.hiddenFlag = true; - fixture.componentInstance.pinnedFlag = true; - fixture.detectChanges(); - // jump over 1 hidden, pinned - targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); - targetCell.onKeydownEnterEditMode({}); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - tick(); - fixture.detectChanges(); - // EXPECT focused cell to be 'Released' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - // jump from pinned to unpinned - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - tick(); - fixture.detectChanges(); - // EXPECT focused cell to be 'Items' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Items'); - expect(editedCell.inEditMode).toEqual(true); - // jump back to pinned - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - tick(); - fixture.detectChanges(); - // EXPECT edited cell to be 'Released' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - // jump over 1 hidden, pinned - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - tick(); - fixture.detectChanges(); - // EXPECT edited cell to be 'Downloads' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Downloads'); - expect(editedCell.inEditMode).toEqual(true); - })); - - it(`Should skip non-editable columns when column grouping is enabled`, (async () => { - const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); - fixture.detectChanges(); - const grid = fixture.componentInstance.grid; - let targetCell: IgxGridCellComponent; - let editedCell: IgxGridCellComponent; - fixture.componentInstance.columnGroupingFlag = true; - fixture.detectChanges(); - targetCell = fixture.componentInstance.focusGridCell(0, 'ReleaseDate'); - targetCell.onKeydownEnterEditMode({}); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - fixture.detectChanges(); - // Should disregards the Igx-Column-Group component - // EXPECT focused cell to be 'Released' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - // Go forwards, jump over Category and group end - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - await wait(DEBOUNCETIME); - fixture.detectChanges(); - // EXPECT focused cell to be 'Items' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Items'); - expect(editedCell.inEditMode).toEqual(true); - // Go backwards, jump over group end and return to 'Released' - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - fixture.detectChanges(); - // EXPECT focused cell to be 'Released' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - await wait(DEBOUNCETIME); - // Go to release date - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - fixture.detectChanges(); - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('ReleaseDate'); - expect(editedCell.inEditMode).toEqual(true); - })); - - it(`Should skip non-editable columns when column when all column features are enabled`, fakeAsync(() => { - const fixture = TestBed.createComponent(IgxGridWithEditingAndFeaturesComponent); - fixture.detectChanges(); - const grid = fixture.componentInstance.grid; - let targetCell: IgxGridCellComponent; - let editedCell: IgxGridCellComponent; - fixture.componentInstance.hiddenFlag = true; - fixture.componentInstance.pinnedFlag = true; - fixture.componentInstance.columnGroupingFlag = true; - fixture.detectChanges(); - targetCell = fixture.componentInstance.focusGridCell(0, 'Downloads'); - targetCell.onKeydownEnterEditMode({}); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - tick(); - fixture.detectChanges(); - // Move from Downloads over hidden to Released in Column Group - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(false); - tick(); - fixture.detectChanges(); - // Move from pinned 'Released' (in Column Group) to unpinned 'Items' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Items'); - expect(editedCell.inEditMode).toEqual(true); - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - tick(); - fixture.detectChanges(); - // Move back to pinned 'Released' (in Column Group) - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Released'); - expect(editedCell.inEditMode).toEqual(true); - editedCell.nativeElement.focus(); - fixture.detectChanges(); - fixture.componentInstance.moveNext(true); - tick(); - fixture.detectChanges(); - // Move back to pinned 'Downloads' - editedCell = fixture.componentInstance.getCurrentEditCell(); - expect(editedCell.column.field).toEqual('Downloads'); - expect(editedCell.inEditMode).toEqual(true); - })); - }); - + describe('Row Editing - Exit row editing', () => { it(`Should call correct methods on clicking DONE and CANCEL buttons in row edit overlay`, fakeAsync(() => { const fix = TestBed.createComponent(IgxGridRowEditingComponent); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.groupby.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.groupby.spec.ts index 4a364125754..ef9f8b13e6b 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.groupby.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.groupby.spec.ts @@ -44,39 +44,7 @@ describe('IgxGrid - GroupBy', () => { }).compileComponents(); })); - const expandCollapceGroupRow = - (fix: ComponentFixture, - groupRow: IgxGridGroupByRowComponent, - cell: IgxGridCellComponent) => new Promise(async (resolve, reject) => { - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); - if (cell != null) { - expect(cell.selected).toBe(true); - } - - groupRow.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'arrowleft', code: 'arrowleft', altKey: true })); - await wait(300); - fix.detectChanges(); - - expect(groupRow.expanded).toBe(false); - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); - if (cell != null) { - expect(cell.selected).toBe(true); - } - - groupRow.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'arrowright', code: 'arrowright', altKey: true })); - await wait(100); - fix.detectChanges(); - - expect(groupRow.expanded).toBe(true); - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); - if (cell != null) { - expect(cell.selected).toBe(true); - } - resolve(); - }); + function checkGroups(groupRows, expectedGroupOrder, grExpr?) { // verify group rows are sorted correctly, their indexes in the grid are correct and their group records match the group value. @@ -708,470 +676,7 @@ describe('IgxGrid - GroupBy', () => { })); // GroupBy + Selection integration - it('should toggle expand/collapse state of group row with ArrowRight/ArrowLeft key.', async(() => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - fix.componentInstance.width = '400px'; - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - const gRow = grid.groupsRowList.toArray()[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); - fix.detectChanges(); - - expect(gRow.expanded).toBe(false); - - gRow.element.nativeElement.dispatchEvent(evtArrowRight); - fix.detectChanges(); - expect(gRow.expanded).toBe(true); - })); - - it(`focus should stays over the group row when expand/collapse - with ArrowRight/ArrowLeft keys and grid is scrolled to bottom`, (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - fix.componentInstance.width = '600px'; - fix.componentInstance.height = '500px'; - await wait(30); - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); - await wait(100); - 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')); - await wait(30); - fix.detectChanges(); - - expect(lastGroupRow.classList.contains('igx-grid__group-row--active')).toBeTruthy(); - lastGroupRow.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', altKey: true })); - - await wait(100); - 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'); - })); - - it(`should be able to navigate down to the next row when expand the last group row - and grid is scrolled to bottom`, (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - fix.componentInstance.width = '600px'; - fix.componentInstance.height = '500px'; - await wait(30); - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); - await wait(100); - fix.detectChanges(); - - grid.groupsRowList.last.toggle(); - await wait(30); - fix.detectChanges(); - expect(grid.groupsRowList.last.expanded).toBeFalsy(); - - grid.groupsRowList.last.toggle(); - await wait(30); - 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 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); - - })); - - xit('should allow keyboard navigation through group rows.', (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - - fix.componentInstance.width = '400px'; - fix.componentInstance.height = '300px'; - grid.columnWidth = '200px'; - await wait(); - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - await HelperUtils.navigateVerticallyToIndex(grid, 0, 9); - - let row = grid.getRowByIndex(9); - expect(row instanceof IgxGridRowComponent).toBe(true); - expect(row.focused).toBe(true); - expect(row.cells.toArray()[0].selected).toBe(true); - - await HelperUtils.navigateVerticallyToIndex(grid, 9, 0); - - row = grid.getRowByIndex(0); - expect(row instanceof IgxGridGroupByRowComponent).toBe(true); - expect(row.focused).toBe(true); - })); - - xit('should persist last selected cell column index when navigation down through group rows.', async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - fix.componentInstance.width = '400px'; - fix.componentInstance.height = '300px'; - grid.columnWidth = '200px'; - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - - grid.parentVirtDir.getHorizontalScroll().scrollLeft = 1000; - await wait(); - let cell = grid.getCellByColumn(2, 'Released'); - cell.onFocus(new Event('focus')); - - await HelperUtils.navigateVerticallyToIndex(grid, 0, 9, 4); - - grid.markForCheck(); - fix.detectChanges(); - const row = grid.getRowByIndex(9); - cell = grid.getCellByColumn(9, 'Released'); - expect(row instanceof IgxGridRowComponent).toBe(true); - expect(row.focused).toBe(true); - expect(cell.selected).toBe(true); - }); - - it('keyboard navigation - should focus grouped row when press Tab key and Shift + Tab on a cell', (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - - fix.componentInstance.width = '600px'; - fix.componentInstance.height = '600px'; - grid.columnWidth = '100px'; - await wait(100); - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - let cell = grid.getCellByColumn(2, 'Released'); - cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(100); - fix.detectChanges(); - - UIInteractions.triggerKeyDownEvtUponElem('tab', cell.nativeElement, true); - await wait(100); - fix.detectChanges(); - - let groupRow = grid.groupsRowList.toArray()[1]; - cell = grid.getCellByColumn(2, 'Released'); - await expandCollapceGroupRow(fix, groupRow, cell); - - UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', groupRow.nativeElement, true); - await wait(300); - 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); - 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 })); - await wait(500); - fix.detectChanges(); - - groupRow = grid.groupsRowList.toArray()[2]; - cell = grid.getCellByColumn(7, 'Downloads'); - await expandCollapceGroupRow(fix, groupRow, cell); - })); - - it('keyboard navigation - should correct work when press tab and sft+tab on a grouped row', (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - - fix.componentInstance.width = '600px'; - fix.componentInstance.height = '600px'; - grid.columnWidth = '100px'; - await wait(50); - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - - let groupRow = grid.groupsRowList.toArray()[0]; - groupRow.nativeElement.dispatchEvent(new Event('focus')); - await wait(50); - fix.detectChanges(); - - groupRow = grid.groupsRowList.toArray()[0]; - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); - UIInteractions.triggerKeyDownEvtUponElem('tab', groupRow.nativeElement, true); - await wait(100); - fix.detectChanges(); - - let cell = grid.getCellByColumn(1, 'Downloads'); - expect(cell.selected).toBe(true); - expect(cell.focused).toBe(true); - - groupRow = grid.groupsRowList.toArray()[1]; - groupRow.nativeElement.dispatchEvent(new Event('focus')); - await wait(100); - 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); - fix.detectChanges(); - - cell = grid.getCellByColumn(2, 'Released'); - expect(cell.selected).toBe(true); - expect(cell.focused).toBe(true); - })); - - it('keyboard navigation - should correct work when press tab and sft+tab on a grouped row when have row selectors', (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - - fix.componentInstance.width = '600px'; - fix.componentInstance.height = '600px'; - grid.columnWidth = '100px'; - grid.rowSelectable = true; - await wait(30); - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - await wait(30); - 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(30); - fix.detectChanges(); - - expect(groupRow.focused).toBe(true); - expect(groupRow.nativeElement.classList.contains('igx-grid__group-row--active')).toBe(true); - - UIInteractions.triggerKeyDownEvtUponElem('tab', groupRow.nativeElement, true); - await wait(100); - fix.detectChanges(); - - expect(cell.selected).toBeTruthy(); - expect(cell.focused).toBeTruthy(); - expect(firstRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); - - cell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', shiftKey: true })); - await wait(30); - fix.detectChanges(); - - expect(cell.selected).toBeTruthy(); - expect(cell.focused).toBeFalsy(); - expect(firstRowCheckbox.classList.contains('igx-checkbox--focused')).toBeFalsy(); - await expandCollapceGroupRow(fix, groupRow, cell); - })); - - it('keyboard navigation - expand/colapse row with arrow keys', (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - - fix.componentInstance.width = '600px'; - fix.componentInstance.height = '600px'; - grid.columnWidth = '100px'; - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - - const groupRow = grid.groupsRowList.toArray()[0]; - groupRow.nativeElement.dispatchEvent(new Event('focus')); - await wait(50); - fix.detectChanges(); - - await expandCollapceGroupRow(fix, groupRow, null); - })); - - it('keyboard navigation - should focus grouped row when press arrow keys up or down', (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - - fix.componentInstance.width = '600px'; - fix.componentInstance.height = '600px'; - grid.columnWidth = '100px'; - await wait(50); - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - let cell = grid.getCellByColumn(1, 'ID'); - cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(50); - fix.detectChanges(); - - expect(cell.selected).toBe(true); - expect(cell.focused).toBe(true); - UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', cell.nativeElement, true); - await wait(100); - fix.detectChanges(); - - let groupRow = grid.groupsRowList.toArray()[0]; - cell = grid.getCellByColumn(1, 'ID'); - await expandCollapceGroupRow(fix, groupRow, cell); - - cell = grid.getCellByColumn(2, 'ProductName'); - cell.nativeElement.dispatchEvent(new Event('focus')); - await wait(100); - fix.detectChanges(); - - expect(cell.focused).toBe(true); - expect(cell.selected).toBe(true); - UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', cell.nativeElement, true); - await wait(100); - fix.detectChanges(); - - cell = grid.getCellByColumn(2, 'ProductName'); - groupRow = grid.groupsRowList.toArray()[1]; - - await expandCollapceGroupRow(fix, groupRow, cell); - })); - - it('keyboard navigation - should correct work when press tab and sft+tab when there is a horizontal scroll', (async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - - fix.componentInstance.width = '600px'; - fix.componentInstance.height = '600px'; - grid.columnWidth = '200px'; - await wait(30); - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - await wait(30); - fix.detectChanges(); - - const groupRow = grid.groupsRowList.toArray()[1]; - const secondRow = grid.getRowByIndex(2); - let cell; - - groupRow.nativeElement.dispatchEvent(new Event('focus')); - await wait(30); - fix.detectChanges(); - - expect(groupRow.focused).toBe(true); - groupRow.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab', shiftKey: true })); - await wait(100); - fix.detectChanges(); - - cell = grid.getCellByColumn(2, 'Released'); - expect(cell.focused).toBe(true); - expect(cell.selected).toBe(true); - - UIInteractions.triggerKeyDownEvtUponElem('Tab', cell.nativeElement, true); - await wait(100); - fix.detectChanges(); - expect(cell.selected).toBe(true); - - await expandCollapceGroupRow(fix, groupRow, cell); - - UIInteractions.triggerKeyDownEvtUponElem('Tab', groupRow.nativeElement, true); - await wait(100); - 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 })); - await wait(30); - fix.detectChanges(); - - expect(cell.selected).toBe(true); - expect(groupRow.focused).toBe(true); - })); - - - xit('should persist last selected cell column index when navigation up through group rows.', async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - - fix.componentInstance.width = '400px'; - fix.componentInstance.height = '300px'; - grid.columnWidth = '200px'; - await wait(); - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - grid.parentVirtDir.getHorizontalScroll().scrollLeft = 1000; - await wait(100); - fix.detectChanges(); - grid.verticalScrollContainer.addScrollTop(1000); - await wait(200); - fix.detectChanges(); - const cell = grid.getCellByColumn(20, 'Released'); - cell.onFocus(new Event('focus')); - await wait(50); - fix.detectChanges(); - // await HelperUtils.navigateVerticallyToIndex(grid, 20, 0, 4); - const row = grid.getRowByIndex(0); - expect(row instanceof IgxGridGroupByRowComponent).toBe(true); - expect(row.focused).toBe(true); - }); - - xit('should NOT clear selection from data cells when a group row is focused via KB navigation.', async () => { - const fix = TestBed.createComponent(DefaultGridComponent); - const grid = fix.componentInstance.instance; - - fix.componentInstance.width = '800px'; - fix.componentInstance.height = '300px'; - grid.columnWidth = '200px'; - fix.detectChanges(); - - grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false }); - grid.groupBy({ fieldName: 'Released', dir: SortingDirection.Desc, ignoreCase: false }); - fix.detectChanges(); - const cell = grid.getCellByColumn(2, 'Downloads'); - cell.onClick(null); - await wait(); - expect(cell.selected).toBe(true); - await HelperUtils.navigateVerticallyToIndex(grid, 2, 0); - - fix.detectChanges(); - const row = grid.getRowByIndex(0); - expect(row instanceof IgxGridGroupByRowComponent).toBe(true); - expect(row.focused).toBe(true); - expect(cell.selected).toBe(true); - }); // GroupBy + Virtualization integration it('should virtualize data and group records.', fakeAsync(() => { diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.pinning.spec.ts index 3846cf80ffc..e37cba61dbb 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.pinning.spec.ts @@ -457,43 +457,7 @@ describe('IgxGrid - Column Pinning ', () => { expect(fix.componentInstance.selectedCell.column.field).toMatch('CompanyName'); })); - it('should allow keyboard navigation to first/last cell with Ctrl when there are the pinned columns.', async () => { - const fix = TestBed.createComponent(GridPinningComponent); - fix.detectChanges(); - - await wait(); - const grid = fix.componentInstance.instance; - grid.getColumnByName('CompanyName').pinned = true; - grid.getColumnByName('ContactName').pinned = true; - fix.detectChanges(); - const cells = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS)); - let cell = cells[0]; - - cell.triggerEventHandler('focus', {}); - await wait(); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual('Maria Anders'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('ContactName'); - - cell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'arrowright', ctrlKey: true })); - await wait(30); - fix.detectChanges(); - - expect(fix.componentInstance.selectedCell.value).toEqual('030-0076545'); - expect(fix.componentInstance.selectedCell.column.field).toMatch('Fax'); - - cell = cells[cells.length - 1]; - cell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'arrowleft', ctrlKey: true })); - await wait(30); - 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 hiding/showing pinned column.', fakeAsync(() => { + it('should allow hiding/showing pinned column.', fakeAsync(() => { const fix = TestBed.createComponent(GridPinningComponent); fix.detectChanges(); const grid = fix.componentInstance.instance;