From 8ccc768206ae4207cd71cd3fcab3975e19ac7481 Mon Sep 17 00:00:00 2001 From: ChrisJoosse Date: Mon, 12 Feb 2024 17:19:43 -0800 Subject: [PATCH] Test coverage for shift-click in product grids --- .../components/ui/grids/EditableGrid.java | 47 ++++++++++++++++ .../test/components/ui/grids/QueryGrid.java | 21 +++++++ .../tests/component/EditableGridTest.java | 55 +++++++++++++++++++ .../test/tests/component/GridPanelTest.java | 47 ++++++++++++++++ 4 files changed, 170 insertions(+) diff --git a/src/org/labkey/test/components/ui/grids/EditableGrid.java b/src/org/labkey/test/components/ui/grids/EditableGrid.java index 722902ef64..998873d284 100644 --- a/src/org/labkey/test/components/ui/grids/EditableGrid.java +++ b/src/org/labkey/test/components/ui/grids/EditableGrid.java @@ -7,6 +7,7 @@ import org.labkey.test.WebDriverWrapper; import org.labkey.test.components.Component; import org.labkey.test.components.WebDriverComponent; +import org.labkey.test.components.html.Checkbox; import org.labkey.test.components.html.Input; import org.labkey.test.components.react.ReactDatePicker; import org.labkey.test.components.react.ReactSelect; @@ -145,6 +146,19 @@ public EditableGrid selectRow(int index, boolean checked) return this; } + public boolean isRowSelected(int index) + { + if (hasSelectColumn()) + { + WebElement checkBox = Locator.css("td > input[type=checkbox]").findElement(getRow(index)); + return checkBox.isSelected(); + } + else + { + throw new NoSuchElementException("There is no select checkbox for row " + index); + } + } + public EditableGrid selectAll(boolean checked) { if (hasSelectColumn()) @@ -158,6 +172,39 @@ public EditableGrid selectAll(boolean checked) return this; } + public boolean areAllRowsSelected() + { + if (hasSelectColumn()) + return new Checkbox(elementCache().selectColumn).isSelected(); + else + throw new NoSuchElementException("There is no select checkbox for all rows."); + } + + /** + * Selects a range of rows in the current view. + * If the range is within a range of already-selected rows, will deselect the specified range + * @param start the starting index (0-based), of non-header rows with checkboxes + * @param end the ending index + * @return the current instance + */ + public EditableGrid shiftSelectRange(int start, int end) + { + if (!hasSelectColumn()) + throw new NoSuchElementException("there is no select checkbox for all rows"); + + var checkBoxes = Locator.tag("tr").child("td") + .child(Locator.tagWithAttribute("input", "type", "checkbox")) + .findElements(elementCache().table); + getWrapper().scrollIntoView(checkBoxes.get(0), true); // bring as much of the grid into view as possible + new Actions(getDriver()) + .click(checkBoxes.get(start)) + .keyDown(Keys.SHIFT) + .click(checkBoxes.get(end)) + .keyUp(Keys.SHIFT) + .perform(); + return this; + } + private List getRows() { waitForLoaded(); diff --git a/src/org/labkey/test/components/ui/grids/QueryGrid.java b/src/org/labkey/test/components/ui/grids/QueryGrid.java index fbb32b0648..a154b61bf3 100644 --- a/src/org/labkey/test/components/ui/grids/QueryGrid.java +++ b/src/org/labkey/test/components/ui/grids/QueryGrid.java @@ -13,8 +13,10 @@ import org.labkey.test.components.react.ReactCheckBox; import org.labkey.test.components.ui.FilterStatusValue; import org.labkey.test.util.selenium.WebDriverUtils; +import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.support.ui.ExpectedConditions; import java.util.HashMap; @@ -340,6 +342,25 @@ public QueryGrid clearAllSelections() return this; } + /** + * Selects a range of rows in the current view. + * If the range is within a range of already-selected rows, will deselect the specified range + * @param start the starting index (0-based), of non-header rows with checkboxes + * @param end the ending index + * @return the current instance + */ + public QueryGrid shiftSelectRange(int start, int end) + { + var checkBoxes = Locator.tagWithClass("input", "grid-panel__row-checkbox").findElements(this); + getWrapper().scrollIntoView(checkBoxes.get(0), true); // scroll the top row to the top + new Actions(getDriver()) + .click(checkBoxes.get(start)) + .keyDown(Keys.SHIFT) + .click(checkBoxes.get(end)) + .keyUp(Keys.SHIFT) + .perform(); + return this; + } /** * Select a view from the 'Views' menu. diff --git a/src/org/labkey/test/tests/component/EditableGridTest.java b/src/org/labkey/test/tests/component/EditableGridTest.java index 2f91a32387..e04f5e0601 100644 --- a/src/org/labkey/test/tests/component/EditableGridTest.java +++ b/src/org/labkey/test/tests/component/EditableGridTest.java @@ -241,6 +241,61 @@ public void testDragFillMultipleRows() testGrid.getColumnData(FILL_DATE)); } + @Test + public void testShiftClick() + { + EditableGrid testGrid = goToEditableGrid(PASTING_SAMPLE_TYPE); + testGrid.addRows(15); + testGrid.shiftSelectRange(2, 7); + + // select a range + checker().verifyFalse(String.format("row %d should not be checked", 1), testGrid.isRowSelected(1)); + for (int i=2; i<7; i++) + { + checker().verifyTrue(String.format("row %d should be checked", i), testGrid.isRowSelected(i)); + } + checker().verifyFalse(String.format("row %d should not be checked", 8), testGrid.isRowSelected(8)); + checker().screenShotIfNewError("unexpected selection range"); + + // select a non-adjacent range + testGrid.shiftSelectRange(10, 13); + checker().verifyFalse(String.format("row %d should not be checked", 9), testGrid.isRowSelected(9)); + for (int i=10; i<13; i++) + { + checker().verifyTrue(String.format("row %d should be checked", i), testGrid.isRowSelected(i)); + } + checker().verifyFalse(String.format("row %d should not be checked", 14), testGrid.isRowSelected(14)); + // ensure the first range is still selected + for (int i=2; i<7; i++) + { + checker().verifyTrue(String.format("row %d should be checked", i), testGrid.isRowSelected(i)); + } + checker().screenShotIfNewError("unexpected selections1"); + + // now de-select cells 6 to 3 + testGrid.shiftSelectRange(6, 3); + // ensure they are deselected + for (int i=3; i<6; i++) + { + checker().verifyFalse(String.format("row %d should not be checked", i), testGrid.isRowSelected(i)); + } + // make sure 2 and 7 are still selected + checker().verifyTrue(String.format("row %d should be checked", 2), testGrid.isRowSelected(2)); + checker().verifyTrue(String.format("row %d should be checked", 7), testGrid.isRowSelected(7)); + // make sure 10-13 are still selected + for (int i=10; i<13; i++) + { + checker().verifyTrue(String.format("row %d should be checked", i), testGrid.isRowSelected(i)); + } + checker().screenShotIfNewError("unexpected selections2"); + + // now select 0-14 + testGrid.shiftSelectRange(0, 14); + checker().withScreenshot("all_rows_not_selected") + .verifyTrue("not all rows are selected", + testGrid.areAllRowsSelected()); + } + @Test public void testExpandedPaste() throws Exception { diff --git a/src/org/labkey/test/tests/component/GridPanelTest.java b/src/org/labkey/test/tests/component/GridPanelTest.java index d3c7f6b361..4bbc6fd0fd 100644 --- a/src/org/labkey/test/tests/component/GridPanelTest.java +++ b/src/org/labkey/test/tests/component/GridPanelTest.java @@ -300,6 +300,53 @@ else if(sampleId % 7 == 0 && stringWithNumCount < NUMBER_STRING_COUNT) } + @Test + public void testShiftClick() + { + QueryGrid grid = beginAtQueryGrid(FILTER_SAMPLE_TYPE); + log("foo"); + + + // select a range of rows + grid.shiftSelectRange(2, 11); + + // verify rows 2-11 are selected, 1 and 12 are not + checker().verifyFalse("row1 should remain unchecked", grid.isRowSelected(1)); + for (int i=2; i<12; i++) + { + checker().verifyTrue(String.format("row %d should be selected", i), grid.isRowSelected(i)); + } + checker().verifyFalse("row12 should remain unchecked", grid.isRowSelected(12)); + checker().verifyEquals("expect selection status to equal", + "10 of 300 selected" ,grid.getSelectionStatusCount()); + checker().screenShotIfNewError("unexpected range select"); + + + // negatively select from within a selected range - uncheck 7, shift down, uncheck 4 + grid.shiftSelectRange(7, 4); + + // verify 4567 are unchecked, 3 and 8 remain checked + checker().verifyTrue("row3 should remain checked", grid.isRowSelected(3)); + for (int i=4; i<8; i++) + { + checker().verifyFalse(String.format("row %d should be unchecked", i), grid.isRowSelected(i)); + } + checker().verifyTrue("row8 should remain checked", grid.isRowSelected(8)); + checker().verifyEquals("expect selection status to equal", + "6 of 300 selected" ,grid.getSelectionStatusCount()); + checker().screenShotIfNewError("unexpected range select"); + + // select a non-adjacent range, verify + grid.shiftSelectRange(13, 17); + for (int i=13; i<17; i++) + { + checker().verifyTrue(String.format("row %d should be checked", i), grid.isRowSelected(i)); + } + checker().verifyEquals("expect selection status to equal", + "11 of 300 selected" ,grid.getSelectionStatusCount()); + checker().screenShotIfNewError("unexpected range select"); + } + /** * Validate that using the 'First Page' and 'Last Page' navigation works as expected. */