UNPKG

igniteui-angular-sovn

Version:

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

475 lines (400 loc) 24.5 kB
import { By } from '@angular/platform-browser'; import { IgxTreeGridComponent } from '../grids/tree-grid/public_api'; import { CellType } from '../grids/common/grid.interface'; import { IgxCheckboxComponent } from '../checkbox/checkbox.component'; import { UIInteractions, wait } from './ui-interactions.spec'; import { GridFunctions } from './grid-functions.spec'; import { IgxRowDirective } from '../grids/row.directive'; import { IgxGridCellComponent } from '../grids/cell.component'; import { DebugElement } from '@angular/core'; // CSS class should end with a number that specified the row's level const TREE_CELL_DIV_INDENTATION_CSS_CLASS = '.igx-grid__tree-cell--padding-level-'; const DEBOUNCETIME = 30; export const TREE_ROW_DIV_SELECTION_CHECKBOX_CSS_CLASS = '.igx-grid__cbx-selection'; export const TREE_ROW_SELECTION_CSS_CLASS = 'igx-grid__tr--selected'; export const TREE_CELL_SELECTION_CSS_CLASS = 'igx-grid__td--selected'; export const TREE_HEADER_ROW_CSS_CLASS = '.igx-grid-thead'; export const CHECKBOX_INPUT_CSS_CLASS = '.igx-checkbox__input'; export const TREE_CELL_INDICATOR_CSS_CLASS = '.igx-grid__tree-grouping-indicator'; export const TREE_CELL_LOADING_CSS_CLASS = '.igx-grid__tree-loading-indicator'; export const NUMBER_CELL_CSS_CLASS = 'igx-grid__td--number'; export const CELL_VALUE_DIV_CSS_CLASS = '.igx-grid__td-text'; export const ROW_EDITING_BANNER_OVERLAY_CLASS = 'igx-overlay__content'; export class TreeGridFunctions { public static getHeaderRow(fix) { return fix.debugElement.query(By.css(TREE_HEADER_ROW_CSS_CLASS)); } public static getAllRows(fix): DebugElement [] { return fix.debugElement.queryAll(By.css('igx-tree-grid-row')); } public static getTreeCell(rowDOM) { return rowDOM.query(By.css('igx-tree-grid-cell')); } public static getCell(fix, rowIndex, columnKey) { const rowDOM = TreeGridFunctions.sortElementsVertically(TreeGridFunctions.getAllRows(fix))[rowIndex]; const rowCells = [TreeGridFunctions.getTreeCell(rowDOM)].concat(TreeGridFunctions.getNormalCells(rowDOM)); return rowCells.filter(domCell => domCell.componentInstance.column.field === columnKey)[0]; } public static getTreeCells(fix) { return fix.debugElement.queryAll(By.css('igx-tree-grid-cell')); } public static getNormalCells(rowDOM) { return rowDOM.queryAll(By.css('igx-grid-cell')); } public static getColumnCells(fix, columnKey) { const allTreeCells = fix.debugElement.queryAll(By.css('igx-tree-grid-cell')); const allNormalCells = fix.debugElement.queryAll(By.css('igx-grid-cell')); const allDOMCells = allTreeCells.concat(allNormalCells); return allDOMCells.filter(domCell => domCell.componentInstance.column.field === columnKey); } public static getAllCells(fix) { const allTreeCells = fix.debugElement.queryAll(By.css('igx-tree-grid-cell')); const allNormalCells = fix.debugElement.queryAll(By.css('igx-grid-cell')); return allTreeCells.concat(allNormalCells); } public static getCellValue(fix, rowIndex, columnKey) { const rowDOM = TreeGridFunctions.sortElementsVertically(TreeGridFunctions.getAllRows(fix))[rowIndex]; const rowCells = [TreeGridFunctions.getTreeCell(rowDOM)].concat(TreeGridFunctions.getNormalCells(rowDOM)); const cell = rowCells.filter(domCell => domCell.componentInstance.column.field === columnKey)[0]; const valueDiv = cell.query(By.css(CELL_VALUE_DIV_CSS_CLASS)); return valueDiv.nativeElement.textContent; } public static getExpansionIndicatorDiv(rowDOM) { const treeGridCell = TreeGridFunctions.getTreeCell(rowDOM); return treeGridCell.query(By.css(TREE_CELL_INDICATOR_CSS_CLASS)); } public static getLoadingIndicatorDiv(rowDOM) { const treeGridCell = TreeGridFunctions.getTreeCell(rowDOM); return treeGridCell.query(By.css(TREE_CELL_LOADING_CSS_CLASS)); } public static getHeaderCell(fix, columnKey) { const headerCells = fix.debugElement.queryAll(By.css('igx-grid-header')); const headerCell = headerCells.filter((cell) => cell.nativeElement.textContent.indexOf(columnKey) !== -1)[0]; return headerCell; } public static getHeaderCellMultiColHeaders(fix, columnKey) { const headerCells = fix.debugElement.queryAll(By.css('igx-grid-header')); const headerCell = headerCells.filter((cell) => cell.nativeElement.textContent.indexOf(columnKey) !== -1).pop(); return headerCell; } public static getRowCheckbox(rowDOM) { const checkboxDiv = TreeGridFunctions.getRowCheckboxDiv(rowDOM); return checkboxDiv.query(By.css(CHECKBOX_INPUT_CSS_CLASS)); } public static getRowCheckboxDiv(rowDOM) { return rowDOM.query(By.css(TREE_ROW_DIV_SELECTION_CHECKBOX_CSS_CLASS)); } public static clickHeaderCell(fix, columnKey) { const cell = TreeGridFunctions.getHeaderCell(fix, columnKey); cell.nativeElement.dispatchEvent(new Event('click')); } public static clickRowSelectionCheckbox(fix, rowIndex) { const rowDOM = TreeGridFunctions.sortElementsVertically(TreeGridFunctions.getAllRows(fix))[rowIndex]; const checkbox = TreeGridFunctions.getRowCheckboxDiv(rowDOM); checkbox.nativeElement.dispatchEvent(new Event('click')); } public static clickHeaderRowSelectionCheckbox(fix) { const headerRow = TreeGridFunctions.getHeaderRow(fix); const checkbox = TreeGridFunctions.getRowCheckboxDiv(headerRow); checkbox.nativeElement.dispatchEvent(new Event('click')); } public static clickRowIndicator(fix, rowIndex) { const rowDOM = TreeGridFunctions.sortElementsVertically(TreeGridFunctions.getAllRows(fix))[rowIndex]; const indicatorDiv = TreeGridFunctions.getExpansionIndicatorDiv(rowDOM); indicatorDiv.triggerEventHandler('click', new Event('click')); } /** * Verifies that the first cell of every row is its tree cell. */ public static verifyCellsPosition(rowsDOM, expectedColumnsCount) { rowsDOM.forEach((row) => { // Verify each row's cell count const treeCell = TreeGridFunctions.getTreeCell(row); const normalCells = TreeGridFunctions.getNormalCells(row); expect(1 + normalCells.length).toBe(expectedColumnsCount, 'incorrect cell count for a row'); const treeCellRectRight = treeCell.nativeElement.getBoundingClientRect().right; normalCells.forEach((normalCell) => { // Verify that the treeCell is the first cell (on the left of all the other cells) const normalCellRectLeft = normalCell.nativeElement.getBoundingClientRect().left; expect(treeCellRectRight <= normalCellRectLeft).toBe(true, 'TreeCell is not on the left of a normal cell.'); }); }); } /** * Verifies both the RowComponent and the respective DOM Row are with the expected indentation level. */ public static verifyRowIndentationLevel(rowComponent, rowDOM, expectedIndentationLevel) { const treeCell = TreeGridFunctions.getTreeCell(rowDOM); const divChildren = treeCell.queryAll(By.css('div')); // If 'expectedIndentationLevel' is 0, we expect the row to be a root level row // and thus it has no indentation div. const indentationDiv = treeCell.query(By.css(TREE_CELL_DIV_INDENTATION_CSS_CLASS + expectedIndentationLevel)); if (expectedIndentationLevel === 0) { expect(divChildren.length).toBe(2, 'root treeCell has incorrect divs count'); expect(indentationDiv).toBeNull(); } else { expect(divChildren.length).toBe(3, 'child treeCell has incorrect divs count'); expect(indentationDiv).toBeDefined(); expect(indentationDiv).not.toBeNull(); } // Verify rowComponent's indentation API. expect(rowComponent.treeRow.level).toBe(expectedIndentationLevel); // Verify expand/collapse icon's position. TreeGridFunctions.verifyTreeRowIconPosition(rowDOM, expectedIndentationLevel); } /** * Verifies both the RowComponent and the respective DOM Row are with the expected indentation level. * The rowIndex is the index of the row in ascending order (if rowIndex is 0, then the top-most row in view will be verified). */ public static verifyRowIndentationLevelByIndex(fix, rowIndex, expectedIndentationLevel) { const treeGrid = fix.debugElement.query(By.css('igx-tree-grid')).componentInstance as IgxTreeGridComponent; const rowComponent = treeGrid.getRowByIndex(rowIndex); const rowDOM = TreeGridFunctions.sortElementsVertically(TreeGridFunctions.getAllRows(fix))[rowIndex]; TreeGridFunctions.verifyRowIndentationLevel(rowComponent, rowDOM, expectedIndentationLevel); } /** * Verifies that the specified column is the tree column, that contains the tree cells. */ public static verifyTreeColumn(fix, expectedTreeColumnKey, expectedColumnsCount) { const headerCell = TreeGridFunctions.getHeaderCell(fix, expectedTreeColumnKey).parent; const treeCells = TreeGridFunctions.getTreeCells(fix); const rows = TreeGridFunctions.getAllRows(fix); // Verify the tree cells are first (on the left) in comparison to the rest of the cells. TreeGridFunctions.verifyCellsPosition(rows, expectedColumnsCount); // Verify the tree cells are exactly under the respective header cell. const headerCellRect = headerCell.nativeElement.getBoundingClientRect(); treeCells.forEach(treeCell => { const treeCellRect = treeCell.nativeElement.getBoundingClientRect(); expect(headerCellRect.bottom <= treeCellRect.top).toBe(true, 'headerCell is not on top of a treeCell'); expect(headerCellRect.left).toBe(treeCellRect.left, 'headerCell and treeCell are not left-aligned'); expect(headerCellRect.right).toBe(treeCellRect.right, 'headerCell and treeCell are not right-aligned'); }); } /** * Verifies that the specified column is the tree column, that contains the tree cells, when there are multi column headers. */ public static verifyTreeColumnInMultiColHeaders(fix, expectedTreeColumnKey, expectedColumnsCount) { const headersDOM = TreeGridFunctions.sortElementsHorizontally(fix.debugElement.queryAll(By.css('igx-grid-header'))); const leftMostHeaders = headersDOM.filter(x => x.nativeElement.getBoundingClientRect().left === headersDOM[0].nativeElement.getBoundingClientRect().left); const headerCell = TreeGridFunctions.getElementWithMinHeight(leftMostHeaders); const treeCells = TreeGridFunctions.getTreeCells(fix); const rows = TreeGridFunctions.getAllRows(fix); // Verify the tree cells are first (on the left) in comparison to the rest of the cells. TreeGridFunctions.verifyCellsPosition(rows, expectedColumnsCount); // Verify the tree cells are exactly under the respective header cell. const headerCellRect = headerCell.nativeElement.getBoundingClientRect(); treeCells.forEach(treeCell => { const treeCellRect = treeCell.nativeElement.getBoundingClientRect(); expect(headerCellRect.bottom <= treeCellRect.top).toBe(true, 'headerCell is not above a treeCell'); expect(headerCellRect.left).toBe(treeCellRect.left, 'headerCell and treeCell are not left-aligned'); expect(headerCellRect.right).toBe(treeCellRect.right, 'headerCell and treeCell are not right-aligned'); }); } public static getElementWithMinHeight(arr) { return arr.reduce((a, b) => (a.nativeElement.getBoundingClientRect().height < b.nativeElement.getBoundingClientRect().height) ? a : b); } public static sortElementsVertically(arr) { return arr.sort((a, b) => a.nativeElement.getBoundingClientRect().top - b.nativeElement.getBoundingClientRect().top); } public static sortElementsHorizontally(arr) { return arr.sort((a, b) => a.nativeElement.getBoundingClientRect().left - b.nativeElement.getBoundingClientRect().left); } public static verifyTreeRowHasCollapsedIcon(treeRowDOM) { const indicatorDiv = TreeGridFunctions.getExpansionIndicatorDiv(treeRowDOM); const igxIcon = indicatorDiv.query(By.css('igx-icon')); expect(igxIcon.nativeElement.textContent).toEqual('chevron_right'); } public static verifyTreeRowHasExpandedIcon(treeRowDOM) { const indicatorDiv = TreeGridFunctions.getExpansionIndicatorDiv(treeRowDOM); const igxIcon = indicatorDiv.query(By.css('igx-icon')); expect(igxIcon.nativeElement.textContent).toEqual('expand_more'); } public static verifyTreeRowExpandIndicatorVisibility(treeRowDOM, visibility = 'visible') { const indicatorDiv = TreeGridFunctions.getExpansionIndicatorDiv(treeRowDOM); expect(indicatorDiv.nativeElement.style.visibility).toBe(visibility); } public static verifyTreeRowIconPosition(treeRowDOM, indentationLevel) { const treeCell = TreeGridFunctions.getTreeCell(treeRowDOM); const treeCellPaddingLeft = parseInt(window.getComputedStyle(treeCell.nativeElement).paddingLeft, 10); const treeCellRect = treeCell.nativeElement.getBoundingClientRect(); let indentation = 0; if (indentationLevel !== 0) { const indentationDiv = treeCell.query(By.css(TREE_CELL_DIV_INDENTATION_CSS_CLASS + indentationLevel)); const indentationDivRect = indentationDiv.nativeElement.getBoundingClientRect(); indentation = indentationDivRect.width; } const iconDiv = TreeGridFunctions.getExpansionIndicatorDiv(treeRowDOM); const iconDivRect = iconDiv.nativeElement.getBoundingClientRect(); expect((iconDivRect.left - (treeCellRect.left + treeCellPaddingLeft + indentation)) < 2) .toBe(true, 'TreeRow icon has incorrect position'); } /** * Returns true if a tree-grid row is 'grayed out' because of filtering */ public static checkRowIsGrayedOut(row: IgxRowDirective): boolean { return row.nativeElement.classList.contains('igx-grid__tr--filtered'); } /** * Returns true if a tree-grid row is NOT 'grayed out' because of filtering */ public static checkRowIsNotGrayedOut(row: IgxRowDirective): boolean { return !row.nativeElement.classList.contains('igx-grid__tr--filtered'); } /** * Verifies the selection of both the RowComponent and the respective DOM Row. */ public static verifyTreeRowSelection(treeGridComponent, rowComponent, rowDOM, expectedSelection: boolean) { // Verfiy selection of checkbox const checkboxDiv = rowDOM.query(By.css(TREE_ROW_DIV_SELECTION_CHECKBOX_CSS_CLASS)); const checkboxComponent = checkboxDiv.query(By.css('igx-checkbox')).componentInstance as IgxCheckboxComponent; expect(checkboxComponent.checked).toBe(expectedSelection, 'Incorrect checkbox selection state'); expect(checkboxComponent.nativeCheckbox.nativeElement.checked).toBe(expectedSelection, 'Incorrect native checkbox selection state'); // Verify selection of row expect(rowComponent.selected).toBe(expectedSelection, 'Incorrect row selection state'); expect(rowDOM.nativeElement.classList.contains(TREE_ROW_SELECTION_CSS_CLASS)).toBe(expectedSelection); // Verify selection of row through treeGrid const selectedRows = (treeGridComponent as IgxTreeGridComponent).selectedRows; expect(selectedRows.includes(rowComponent.key)).toBe(expectedSelection); } /** * Verifies the selection of both the RowComponent and the respective DOM Row. * The rowIndex is the index of the row in ascending order (if rowIndex is 0, then the top-most row in view will be verified). */ public static verifyTreeRowSelectionByIndex(fix, rowIndex, expectedSelection: boolean) { const treeGrid = fix.debugElement.query(By.css('igx-tree-grid')).componentInstance as IgxTreeGridComponent; const rowComponent = treeGrid.getRowByIndex(rowIndex); const rowDOM = TreeGridFunctions.sortElementsVertically(TreeGridFunctions.getAllRows(fix))[rowIndex]; TreeGridFunctions.verifyTreeRowSelection(treeGrid, rowComponent, rowDOM, expectedSelection); } /** * Verifies the selection of the treeGrid rows. * Every index of the provided array is the index of the respective row in ascending order * (if rowIndex is 0, then the top-most row in view will be verified). */ public static verifyDataRowsSelection(fix, expectedSelectedRowIndices: any[], expectedSelection: boolean) { if (expectedSelection) { const treeGrid = fix.debugElement.query(By.css('igx-tree-grid')).componentInstance as IgxTreeGridComponent; expect(treeGrid.selectedRows.length).toBe(expectedSelectedRowIndices.length, 'Incorrect number of rows that are selected.'); } expectedSelectedRowIndices.forEach(rowIndex => { TreeGridFunctions.verifyTreeRowSelectionByIndex(fix, rowIndex, expectedSelection); }); } /** * Verifies the selection and checkbox state of the treeGrid row. */ public static verifyRowByIndexSelectionAndCheckboxState(fix, rowIndex: any, expectedSelection: boolean, expectedCheckboxState: boolean | null) { const treeGrid = fix.debugElement.query(By.css('igx-tree-grid')).componentInstance as IgxTreeGridComponent; const rowComponent = treeGrid.getRowByIndex(rowIndex); const rowDOM = TreeGridFunctions.sortElementsVertically(TreeGridFunctions.getAllRows(fix))[rowIndex]; // Verfiy selection of checkbox const checkboxDiv = rowDOM.query(By.css(TREE_ROW_DIV_SELECTION_CHECKBOX_CSS_CLASS)); const checkboxComponent = checkboxDiv.query(By.css('igx-checkbox')).componentInstance as IgxCheckboxComponent; if (expectedCheckboxState === null) { expect(checkboxComponent.indeterminate).toBe(true); expect(checkboxComponent.checked).toBe(false, 'Incorrect checkbox selection state'); expect(checkboxComponent.nativeCheckbox.nativeElement.checked).toBe(false, 'Incorrect native checkbox selection state'); // Verify selection of row expect(rowComponent.selected).toBe(false, 'Incorrect row selection state'); expect((rowDOM.nativeElement as HTMLElement).classList.contains(TREE_ROW_SELECTION_CSS_CLASS)).toBe(false); // Verify selection of row through treeGrid const selectedRows = (treeGrid as IgxTreeGridComponent).selectedRows; expect(selectedRows.includes(rowComponent.key)).toBe(false); } else { expect(checkboxComponent.checked).toBe(expectedCheckboxState, 'Incorrect checkbox selection state'); expect(checkboxComponent.nativeCheckbox.nativeElement.checked).toBe( expectedCheckboxState, 'Incorrect native checkbox selection state'); // Verify selection of row expect(rowComponent.selected).toBe(expectedSelection, 'Incorrect row selection state'); expect((rowDOM.nativeElement as HTMLElement).classList.contains(TREE_ROW_SELECTION_CSS_CLASS)).toBe(expectedSelection); // Verify selection of row through treeGrid const selectedRows = (treeGrid as IgxTreeGridComponent).selectedRows; expect(selectedRows.includes(rowComponent.key)).toBe(expectedSelection); } } /** * Verifies the selection of the header checkbox. * The expected value can be true, false or null (indeterminate). */ public static verifyHeaderCheckboxSelection(fix, expectedSelection: boolean | null) { const headerRow = TreeGridFunctions.getHeaderRow(fix); const checkboxDiv = headerRow.query(By.css(TREE_ROW_DIV_SELECTION_CHECKBOX_CSS_CLASS)); const checkboxComponent = checkboxDiv.query(By.css('igx-checkbox')).componentInstance as IgxCheckboxComponent; if (expectedSelection === null) { expect(checkboxComponent.indeterminate).toBe(true); expect(checkboxComponent.checked).toBe(false, 'Incorrect checkbox selection state'); expect(checkboxComponent.nativeCheckbox.nativeElement.checked).toBe(false, 'Incorrect native checkbox selection state'); } else { expect(checkboxComponent.indeterminate).toBe(false); expect(checkboxComponent.checked).toBe(expectedSelection, 'Incorrect checkbox selection state'); expect(checkboxComponent.nativeCheckbox.nativeElement.checked).toBe(expectedSelection, 'Incorrect native checkbox selection state'); } } public static verifyGridCellHasSelectedClass(cellDOM) { return cellDOM.nativeElement.classList.contains(TREE_CELL_SELECTION_CSS_CLASS); } public static verifyTreeGridCellSelected(treeGrid: IgxTreeGridComponent, cell: IgxGridCellComponent | CellType, selected = true) { expect(cell).toBeDefined(); if (cell) { expect(TreeGridFunctions.verifyGridCellHasSelectedClass(cell)).toBe(selected); if (selected) { const selectedCell = treeGrid.selectedCells[0]; expect(selectedCell).toBeDefined(); if (selectedCell) { expect(selectedCell.value).toEqual(cell.value); expect(selectedCell.column.field).toEqual(cell.column.field); expect(selectedCell.row.index).toEqual(cell.row.index); expect(selectedCell.value).toEqual(cell.value); } } } } public static verifyTreeRowIndicator(row, isLoading: boolean, isExpandVisible = true) { const indicatorDiv = TreeGridFunctions.getExpansionIndicatorDiv(row); const loadingDiv = TreeGridFunctions.getLoadingIndicatorDiv(row); if (isLoading) { expect(loadingDiv).toBeDefined(); expect(indicatorDiv).toBeNull(); } else { expect(loadingDiv).toBeNull(); expect(indicatorDiv).toBeDefined(); expect(indicatorDiv.nativeElement.style.visibility).toBe(isExpandVisible ? 'visible' : 'hidden'); } } public static moveCellUpDown(fix, treeGrid: IgxTreeGridComponent, rowIndex: number, columnName: string, moveDown = true) { const cell = treeGrid.gridAPI.get_cell_by_index(rowIndex, columnName); const newRowIndex = moveDown ? rowIndex + 1 : rowIndex - 1; const keyboardEventKey = moveDown ? 'ArrowDown' : 'ArrowUp'; const gridContent = GridFunctions.getGridContent(fix); UIInteractions.triggerEventHandlerKeyDown(keyboardEventKey, gridContent); fix.detectChanges(); TreeGridFunctions.verifyTreeGridCellSelected(treeGrid, cell, false); const newCell = treeGrid.gridAPI.get_cell_by_index(newRowIndex, columnName); TreeGridFunctions.verifyTreeGridCellSelected(treeGrid, newCell); } public static moveCellLeftRight(fix, treeGrid: IgxTreeGridComponent, rowIndex: number, firstColumnName: string, nextColumnName: string, moveRight = true) { const cell = treeGrid.gridAPI.get_cell_by_index(rowIndex, firstColumnName); const keyboardEventKey = moveRight ? 'ArrowRight' : 'ArrowLeft'; const gridContent = GridFunctions.getGridContent(fix); UIInteractions.triggerEventHandlerKeyDown(keyboardEventKey, gridContent); fix.detectChanges(); TreeGridFunctions.verifyTreeGridCellSelected(treeGrid, cell, false); const newCell = treeGrid.gridAPI.get_cell_by_index(rowIndex, nextColumnName); TreeGridFunctions.verifyTreeGridCellSelected(treeGrid, newCell); } public static moveGridCellWithTab = (fix, cell: IgxGridCellComponent | CellType) => new Promise<void>(async resolve => { UIInteractions.triggerKeyDownEvtUponElem('Tab', cell.nativeElement, true); await wait(DEBOUNCETIME); fix.detectChanges(); resolve(); }); }