All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.flow.component.grid.testbench.GridElement Maven / Gradle / Ivy

There is a newer version: 24.5.5
Show newest version
/*
 * Copyright 2000-2024 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.vaadin.flow.component.grid.testbench;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;

import com.vaadin.flow.component.checkbox.testbench.CheckboxElement;
import com.vaadin.testbench.TestBenchElement;
import com.vaadin.testbench.elementsbase.Element;

/**
 * A TestBench element representing a <vaadin-grid> element.
 */
@Element("vaadin-grid")
public class GridElement extends TestBenchElement {

    protected void waitUntilLoadingFinished() {
        waitUntil(e -> !isLoading());
    }

    protected boolean isLoading() {
        return (Boolean) executeScript(
                "return arguments[0]._dataProviderController.isLoading() || (!!arguments[0].$connector && arguments[0].$connector.hasRootRequestQueue())",
                this);
    }

    /**
     * Scrolls to the row with the given index.
     *
     * @param row
     *            the row to scroll to
     */
    public void scrollToRow(int row) {
        callFunction("scrollToIndex", row);
        waitUntilLoadingFinished();
    }

    /**
     * Scrolls to the row with the given flat row index.
     *
     * @param row
     *            the row to scroll to
     */
    protected void scrollToFlatRow(int row) {
        callFunction("_scrollToFlatIndex", row);
        waitUntilLoadingFinished();
    }

    /**
     * Gets the page size used when fetching data.
     *
     * @return the page size
     */
    public int getPageSize() {
        return getPropertyInteger("pageSize");
    }

    /**
     * Gets the index of the first row which is at least partially visible.
     *
     * @return the index of the first visible row, -1 if Grid is empty
     */
    public int getFirstVisibleRowIndex() {
        Object index = executeScript("return arguments[0]._firstVisibleIndex",
                this);
        if (index != null) {
            return ((Long) index).intValue();
        } else {
            return -1;
        }
    }

    /**
     * Gets the total number of rows.
     *
     * @return the number of rows
     */
    public int getRowCount() {
        waitUntilLoadingFinished();
        return getPropertyDouble("_flatSize").intValue();
    }

    /**
     * Gets the grid cell for the given row and column index.
     * 

* For the column index, only visible columns are taken into account. *

* Automatically scrolls the given row into view * * @param rowIndex * the row index * @param colIndex * the column index * @return the grid cell for the given coordinates */ public GridTHTDElement getCell(int rowIndex, int colIndex) { GridColumnElement column = getVisibleColumns().get(colIndex); return getCell(rowIndex, column); } /** * Gets the grid cell for the given row and column. *

* Automatically scrolls the given row into view * * @param rowIndex * the row index * @param column * the column element for the column * @return the grid cell for the given coordinates */ public GridTHTDElement getCell(int rowIndex, GridColumnElement column) { if (!isRowInView(rowIndex)) { scrollToFlatRow(rowIndex); } GridTRElement row = getRow(rowIndex); return row.getCell(column); } /** * Finds the first cell inside the rendered range with a text content * matching the given string. * * @param contents * the string to look for * @return a grid cell containing the given string * @throws NoSuchElementException * if no cell with the given string was found */ public GridTHTDElement getCell(String contents) throws NoSuchElementException { String script = "const grid = arguments[0];" + "const contents = arguments[1];" + "const rowsInDom = Array.from(arguments[0].$.items.children);" + "var tds = [];" + "rowsInDom.forEach(function(tr) { Array.from(tr.children).forEach(function(td) { tds.push(td);})});" + "const matches = tds.filter(function(td) { return td._content.textContent == contents});" + "return matches.length ? matches[0] : null;"; TestBenchElement td = (TestBenchElement) executeScript(script, this, contents); if (td == null) { throw new NoSuchElementException( "No cell with text content '" + contents + "' found"); } return td.wrap(GridTHTDElement.class); } /** * Gets the index of the last row which is at least partially visible. * * @return the index of the last visible row, -1 if Grid is empty */ public int getLastVisibleRowIndex() { Object index = executeScript("return arguments[0]._lastVisibleIndex", this); if (index != null) { return ((Long) index).intValue(); } else { return -1; } } /** * Checks if the given row is in the visible viewport. * * @param rowIndex * the row to check * @return true if the row is at least partially in view, * false otherwise */ private boolean isRowInView(int rowIndex) { return (getFirstVisibleRowIndex() <= rowIndex && rowIndex <= getLastVisibleRowIndex()); } /** * Gets the rows (present in the DOM) specified by the lower and upper row * indexes. * * @param firstRowIndex * the lower row index to be retrieved (inclusive) * @param lastRowIndex * the upper row index to be retrieved (inclusive) * @return a {@link GridTRElement} list with the rows contained between the * given coordinates. * @throws IndexOutOfBoundsException * if either of the provided row indexes do not exist */ public List getRows(int firstRowIndex, int lastRowIndex) throws IndexOutOfBoundsException { int rowCount = getRowCount(); if (firstRowIndex < 0 || lastRowIndex < 0 || firstRowIndex >= rowCount || lastRowIndex >= rowCount) { throw new IndexOutOfBoundsException( "firstRowIndex and lastRowIndex: expected to be 0.." + (rowCount - 1) + " but were " + firstRowIndex + " and " + lastRowIndex); } String script = "var grid = arguments[0];" + "var firstRowIndex = arguments[1];" + "var lastRowIndex = arguments[2];" + "var rowsInDom = grid._getRenderedRows();" + "return Array.from(rowsInDom).filter((row) => { return row.index >= firstRowIndex && row.index <= lastRowIndex;});"; Object rows = executeScript(script, this, firstRowIndex, lastRowIndex); if (rows != null) { return ((ArrayList) rows).stream().map( elem -> ((TestBenchElement) elem).wrap(GridTRElement.class)) .toList(); } else { return new ArrayList<>(); } } /** * Gets the tr element for the given row index. * * @param rowIndex * the row index * @return the tr element for the row * @throws IndexOutOfBoundsException * if no row with given index exists */ public GridTRElement getRow(int rowIndex) throws IndexOutOfBoundsException { var rows = getRows(rowIndex, rowIndex); return rows.size() == 1 ? rows.get(0) : null; } /** * Gets all columns defined for the grid, including any selection checkbox * column. * * @return a list of grid column elements which can be used to refer to the * given column */ public List getAllColumns() { generatedColumnIdsIfNeeded(); String getVisibleColumnsJS = "return arguments[0]._getColumns().sort(function(a,b) { return a._order - b._order;}).map(function(column) { return column.__generatedTbId;});"; @SuppressWarnings("unchecked") List elements = (List) executeScript(getVisibleColumnsJS, this); return elements.stream() .map(generatedId -> new GridColumnElement(generatedId, this)) .collect(Collectors.toList()); } protected void generatedColumnIdsIfNeeded() { String generateIds = "const grid = arguments[0];" + "if (!grid.__generatedTbId) {"// + " grid.__generatedTbId = 1;"// + "}" // + "grid._getColumns().forEach(function(column) {" + " if (!column.__generatedTbId) {" + " column.__generatedTbId = grid.__generatedTbId++;" // + " }" // + "});"; executeScript(generateIds, this); // } /** * Gets the currently visible columns in the grid, including any selection * checkbox column. * * @return a list of grid column elements which can be used to refer to the * given column */ public List getVisibleColumns() { generatedColumnIdsIfNeeded(); String getVisibleColumnsJS = "return arguments[0]._getColumns().filter(function(column) {return !column.hidden;}).sort(function(a,b) { return a._order - b._order;}).map(function(column) { return column.__generatedTbId;});"; List elements = (List) executeScript(getVisibleColumnsJS, this); return elements.stream().map(id -> new GridColumnElement(id, this)) .collect(Collectors.toList()); } /** * Gets the column with the given header text. *

* If multiple columns are found with the same header text, returns the * first column. * * @param headerText * the text in the header * @return the grid column element for the given column * @throws NoSuchElementException * if no column was found */ public GridColumnElement getColumn(String headerText) throws NoSuchElementException { return getVisibleColumns().stream().filter( column -> headerText.equals(column.getHeaderCell().getText())) .findFirst() .orElseThrow(() -> new NoSuchElementException( "No column with header '" + headerText + "' was found")); } /** * Gets the header cell for the given visible column index. * * @param columnIndex * the index of the column * @return a cell element for the header cell */ public GridTHTDElement getHeaderCell(int columnIndex) { return getVisibleColumns().get(columnIndex).getHeaderCell(); } /** * Finds the vaadin-grid-cell-content element for the given row and column * in header. * * @param rowIndex * the index of the row in the header * @param columnIndex * the index of the column in the header * @return the vaadin-grid-cell-content element for the given row and column * in header. */ public TestBenchElement getHeaderCellContent(int rowIndex, int columnIndex) { WebElement thead = $("*").id("header"); List headerRows = thead.findElements(By.tagName("tr")); List headerCells = headerRows.get(rowIndex) .findElements(By.tagName("th")); String slotName = headerCells.get(columnIndex) .findElement(By.tagName("slot")).getAttribute("name"); return findElement(By.cssSelector( "vaadin-grid-cell-content[slot='" + slotName + "']")); } /** * Gets the footer cell for the given visible column index. * * @param columnIndex * the index of the column * @return a cell element for the footer cell */ public GridTHTDElement getFooterCell(int columnIndex) { return getVisibleColumns().get(columnIndex).getFooterCell(); } /** * Selects the row with the given index. * * @param rowIndex * the row to select */ public void select(int rowIndex) { select(getRow(rowIndex)); } /** * Selects the row. * * @param row * the row to select */ void select(GridTRElement row) { GridColumnElement multiSelectColumn = getMultiSelectColumn(); if (multiSelectColumn != null) { GridTHTDElement cell = row.getCell(multiSelectColumn); CheckboxElement checkbox = wrapElement(cell.getFirstChildElement(), getCommandExecutor()).wrap(CheckboxElement.class); if (!checkbox.isChecked()) { checkbox.click(); } } else { setActiveItem(row); } } /** * Deselects the row with the given index. * * @param rowIndex * the row to deselect */ public void deselect(int rowIndex) { deselect(getRow(rowIndex)); } /** * Deselects the row with the given index. * * @param row * the row to deselect */ void deselect(GridTRElement row) { GridColumnElement multiSelectColumn = getMultiSelectColumn(); if (multiSelectColumn != null) { GridTHTDElement cell = row.getCell(multiSelectColumn); CheckboxElement checkbox = wrapElement(cell.getFirstChildElement(), getCommandExecutor()).wrap(CheckboxElement.class); if (checkbox.isChecked()) { checkbox.click(); } } else { removeActiveItem(row); } } private void setActiveItem(GridTRElement row) { executeScript("arguments[0].activeItem=arguments[1]._item", this, row); } private void removeActiveItem(GridTRElement row) { final String JS_DEACTIVATE_IF_ACTIVE = "if(arguments[0]._itemsEqual(arguments[0].activeItem, " + "arguments[1]._item)) { arguments[0].activeItem=null;}"; executeScript(JS_DEACTIVATE_IF_ACTIVE, this, row); } /** * Get the multi-select column of the grid. Returns null, if the grid is not * in multi-selection mode, or doesn't have a multi-selection column. * * @return the multi-select column, or null */ private GridColumnElement getMultiSelectColumn() { generatedColumnIdsIfNeeded(); List columnIds = (List) executeScript( "return arguments[0]._getColumns().filter(function(col) { return typeof col.selectAll != 'undefined';}).map(function(column) { return column.__generatedTbId;});", this); if (columnIds.isEmpty()) return null; return new GridColumnElement(columnIds.get(0), this); } /** * Click select all check box */ public void clickSelectAll() { CheckboxElement selectAllCheckbox = $(CheckboxElement.class) .id("selectAllCheckbox"); selectAllCheckbox.click(); } /** * Gets all the currently visible rows. * * @return a {@link GridTRElement} list representing the currently visible * rows. */ public List getVisibleRows() { return getRows(getFirstVisibleRowIndex(), getLastVisibleRowIndex()); } /** * Gets the grid cells for the given row and column elements. * * @param rowIndex * the row index * @param columnElements * the column elements * @return a {@link GridTHTDElement} list with the cells for the given * coordinates. */ public List getCells(int rowIndex, GridColumnElement... columnElements) { GridTRElement row = getRow(rowIndex); return row != null ? row.getCells(columnElements) : new ArrayList<>(); } /** * Gets the grid cells for the given row. * * @param rowIndex * the row index * @return a {@link GridTHTDElement} list with the cells for the given * coordinates. */ public List getCells(int rowIndex) { return getCells(rowIndex, getAllColumns().toArray(new GridColumnElement[0])); } /** * Gets the empty state content. * * @return the empty state content * @throws NoSuchElementException * if no empty state content was found */ public TestBenchElement getEmptyStateContent() { try { return findElement(By.cssSelector("[slot='empty-state']")); } catch (NoSuchElementException e) { throw new NoSuchElementException( "No empty state content was found"); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy