diff options
author | Pekka Hyvönen <pekka@vaadin.com> | 2015-04-30 13:40:45 +0300 |
---|---|---|
committer | Pekka Hyvönen <pekka@vaadin.com> | 2015-04-30 13:40:52 +0300 |
commit | ef9fb276a93d1a7967ef0e6405dee56c8aa2a148 (patch) | |
tree | 622280f6e6e2904fef61c3483fe36e14ab6b924d /uitest | |
parent | a9bc160aee00b93340ac3f047505e032d4a696b0 (diff) | |
parent | bbf30fff168fd4a9552d23c8341e27aa1821884b (diff) | |
download | vaadin-framework-ef9fb276a93d1a7967ef0e6405dee56c8aa2a148.tar.gz vaadin-framework-ef9fb276a93d1a7967ef0e6405dee56c8aa2a148.zip |
Merge branch 'grid-7.5'
Change-Id: Ifa976fa4be1258fd35999de17775da70afedb2a8
Diffstat (limited to 'uitest')
25 files changed, 5212 insertions, 402 deletions
diff --git a/uitest/src/com/vaadin/testbench/elements/GridElement.java b/uitest/src/com/vaadin/testbench/elements/GridElement.java deleted file mode 100644 index 68ddfc878e..0000000000 --- a/uitest/src/com/vaadin/testbench/elements/GridElement.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright 2000-2014 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.testbench.elements; - -import java.util.ArrayList; -import java.util.List; - -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -import com.vaadin.testbench.By; -import com.vaadin.testbench.TestBenchElement; -import com.vaadin.testbench.elementsbase.AbstractElement; -import com.vaadin.testbench.elementsbase.ServerClass; - -/** - * TestBench Element API for Grid - * - * @since - * @author Vaadin Ltd - */ -@ServerClass("com.vaadin.ui.Grid") -public class GridElement extends AbstractComponentElement { - - public static class GridCellElement extends AbstractElement { - - private static final String FOCUSED_CELL_CLASS_NAME = "-cell-focused"; - private static final String FROZEN_CLASS_NAME = "frozen"; - - public boolean isFocused() { - return getAttribute("class").contains(FOCUSED_CELL_CLASS_NAME); - } - - public boolean isFrozen() { - return getAttribute("class").contains(FROZEN_CLASS_NAME); - } - } - - public static class GridRowElement extends AbstractElement { - - private static final String FOCUSED_CLASS_NAME = "-row-focused"; - private static final String SELECTED_CLASS_NAME = "-row-selected"; - - public boolean isFocused() { - return getAttribute("class").contains(FOCUSED_CLASS_NAME); - } - - @Override - public boolean isSelected() { - return getAttribute("class").contains(SELECTED_CLASS_NAME); - } - } - - public static class GridEditorElement extends AbstractElement { - - private GridElement grid; - - private GridEditorElement setGrid(GridElement grid) { - this.grid = grid; - return this; - } - - /** - * Gets the editor field for column in given index. - * - * @param colIndex - * the column index - * @return the editor field for given location - * - * @throws NoSuchElementException - * if {@code isEditable(colIndex) == false} - */ - public TestBenchElement getField(int colIndex) { - return grid.getSubPart("#editor[" + colIndex + "]"); - } - - /** - * Gets whether the column with the given index is editable, that is, - * has an associated editor field. - * - * @param colIndex - * the column index - * @return {@code true} if the column has an editor field, {@code false} - * otherwise - */ - public boolean isEditable(int colIndex) { - return grid - .isElementPresent(By.vaadin("#editor[" + colIndex + "]")); - } - - /** - * Checks whether a field is marked with an error. - * - * @param colIndex - * column index - * @return <code>true</code> iff the field is marked with an error - */ - public boolean isFieldErrorMarked(int colIndex) { - return getField(colIndex).getAttribute("class").contains("error"); - } - - /** - * Saves the fields of this editor. - * <p> - * <em>Note:</em> that this closes the editor making this element - * useless. - */ - public void save() { - findElement(By.className("v-grid-editor-save")).click(); - } - - /** - * Cancels this editor. - * <p> - * <em>Note:</em> that this closes the editor making this element - * useless. - */ - public void cancel() { - findElement(By.className("v-grid-editor-cancel")).click(); - } - - /** - * Gets the error message text, or <code>null</code> if no message is - * present. - */ - public String getErrorMessage() { - WebElement messageWrapper = findElement(By - .className("v-grid-editor-message")); - List<WebElement> divs = messageWrapper.findElements(By - .tagName("div")); - if (divs.isEmpty()) { - return null; - } else { - return divs.get(0).getText(); - } - } - } - - /** - * Scrolls Grid element so that wanted row is displayed - * - * @param index - * Target row - */ - public void scrollToRow(int index) { - try { - getSubPart("#cell[" + index + "]"); - } catch (NoSuchElementException e) { - // Expected, ignore it. - } - } - - /** - * Gets cell element with given row and column index. - * - * @param rowIndex - * Row index - * @param colIndex - * Column index - * @return Cell element with given indices. - */ - public GridCellElement getCell(int rowIndex, int colIndex) { - scrollToRow(rowIndex); - return getSubPart("#cell[" + rowIndex + "][" + colIndex + "]").wrap( - GridCellElement.class); - } - - /** - * Gets row element with given row index. - * - * @param index - * Row index - * @return Row element with given index. - */ - public GridRowElement getRow(int index) { - scrollToRow(index); - return getSubPart("#cell[" + index + "]").wrap(GridRowElement.class); - } - - /** - * Gets header cell element with given row and column index. - * - * @param rowIndex - * Row index - * @param colIndex - * Column index - * @return Header cell element with given indices. - */ - public GridCellElement getHeaderCell(int rowIndex, int colIndex) { - return getSubPart("#header[" + rowIndex + "][" + colIndex + "]").wrap( - GridCellElement.class); - } - - /** - * Gets footer cell element with given row and column index. - * - * @param rowIndex - * Row index - * @param colIndex - * Column index - * @return Footer cell element with given indices. - */ - public GridCellElement getFooterCell(int rowIndex, int colIndex) { - return getSubPart("#footer[" + rowIndex + "][" + colIndex + "]").wrap( - GridCellElement.class); - } - - /** - * Gets list of header cell elements on given row. - * - * @param rowIndex - * Row index - * @return Header cell elements on given row. - */ - public List<GridCellElement> getHeaderCells(int rowIndex) { - List<GridCellElement> headers = new ArrayList<GridCellElement>(); - for (TestBenchElement e : TestBenchElement.wrapElements( - getSubPart("#header[" + rowIndex + "]").findElements( - By.xpath("./th")), getCommandExecutor())) { - headers.add(e.wrap(GridCellElement.class)); - } - return headers; - } - - /** - * Gets list of header cell elements on given row. - * - * @param rowIndex - * Row index - * @return Header cell elements on given row. - */ - public List<GridCellElement> getFooterCells(int rowIndex) { - List<GridCellElement> footers = new ArrayList<GridCellElement>(); - for (TestBenchElement e : TestBenchElement.wrapElements( - getSubPart("#footer[" + rowIndex + "]").findElements( - By.xpath("./td")), getCommandExecutor())) { - footers.add(e.wrap(GridCellElement.class)); - } - return footers; - } - - /** - * Get header row count - * - * @return Header row count - */ - public int getHeaderCount() { - return getSubPart("#header").findElements(By.xpath("./tr")).size(); - } - - /** - * Get footer row count - * - * @return Footer row count - */ - public int getFooterCount() { - return getSubPart("#footer").findElements(By.xpath("./tr")).size(); - } - - /** - * Get a header row by index - * - * @param rowIndex - * Row index - * @return The th element of the row - */ - public TestBenchElement getHeaderRow(int rowIndex) { - return getSubPart("#header[" + rowIndex + "]"); - } - - /** - * Get a footer row by index - * - * @param rowIndex - * Row index - * @return The tr element of the row - */ - public TestBenchElement getFooterRow(int rowIndex) { - return getSubPart("#footer[" + rowIndex + "]"); - } - - /** - * Get the vertical scroll element - * - * @return The element representing the vertical scrollbar - */ - public TestBenchElement getVerticalScroller() { - List<WebElement> rootElements = findElements(By.xpath("./div")); - return (TestBenchElement) rootElements.get(0); - } - - /** - * Get the horizontal scroll element - * - * @return The element representing the horizontal scrollbar - */ - public TestBenchElement getHorizontalScroller() { - List<WebElement> rootElements = findElements(By.xpath("./div")); - return (TestBenchElement) rootElements.get(1); - } - - /** - * Get the header element - * - * @return The thead element - */ - public TestBenchElement getHeader() { - return getSubPart("#header"); - } - - /** - * Get the body element - * - * @return the tbody element - */ - public TestBenchElement getBody() { - return getSubPart("#cell"); - } - - /** - * Get the footer element - * - * @return the tfoot element - */ - public TestBenchElement getFooter() { - return getSubPart("#footer"); - } - - /** - * Get the element wrapping the table element - * - * @return The element that wraps the table element - */ - public TestBenchElement getTableWrapper() { - List<WebElement> rootElements = findElements(By.xpath("./div")); - return (TestBenchElement) rootElements.get(2); - } - - public GridEditorElement getEditor() { - return getSubPart("#editor").wrap(GridEditorElement.class) - .setGrid(this); - } - - /** - * Helper function to get Grid subparts wrapped correctly - * - * @param subPartSelector - * SubPart to be used in ComponentLocator - * @return SubPart element wrapped in TestBenchElement class - */ - private TestBenchElement getSubPart(String subPartSelector) { - return (TestBenchElement) findElement(By.vaadin(subPartSelector)); - } -} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocation.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocation.java new file mode 100644 index 0000000000..2880df44b0 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocation.java @@ -0,0 +1,121 @@ +/* + * Copyright 2000-2014 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.tests.components.grid; + +import com.vaadin.annotations.Theme; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.util.Person; +import com.vaadin.tests.util.PersonContainer; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Component; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.DetailsGenerator; +import com.vaadin.ui.Grid.RowReference; +import com.vaadin.ui.Grid.SelectionMode; +import com.vaadin.ui.Label; +import com.vaadin.ui.Layout; +import com.vaadin.ui.TextField; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; + +@Theme(ValoTheme.THEME_NAME) +public class GridDetailsLocation extends UI { + + private final DetailsGenerator detailsGenerator = new DetailsGenerator() { + @Override + public Component getDetails(RowReference rowReference) { + Person person = (Person) rowReference.getItemId(); + Label label = new Label(person.getFirstName() + " " + + person.getLastName()); + // currently the decorator row doesn't change its height when the + // content height is different. + label.setHeight("30px"); + return label; + } + }; + + private TextField numberTextField; + private Grid grid; + + @Override + protected void init(VaadinRequest request) { + + Layout layout = new VerticalLayout(); + + grid = new Grid(PersonContainer.createWithTestData(1000)); + grid.setSelectionMode(SelectionMode.NONE); + layout.addComponent(grid); + + final CheckBox checkbox = new CheckBox("Details generator"); + checkbox.addValueChangeListener(new ValueChangeListener() { + @Override + @SuppressWarnings("boxing") + public void valueChange(ValueChangeEvent event) { + if (checkbox.getValue()) { + grid.setDetailsGenerator(detailsGenerator); + } else { + grid.setDetailsGenerator(DetailsGenerator.NULL); + } + } + }); + layout.addComponent(checkbox); + + numberTextField = new TextField("Row"); + numberTextField.setImmediate(true); + layout.addComponent(numberTextField); + + layout.addComponent(new Button("Toggle and scroll", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + toggle(); + scrollTo(); + } + })); + layout.addComponent(new Button("Scroll and toggle", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + scrollTo(); + toggle(); + } + })); + + setContent(layout); + } + + private void toggle() { + Object itemId = getItemId(); + boolean isVisible = grid.isDetailsVisible(itemId); + grid.setDetailsVisible(itemId, !isVisible); + } + + private void scrollTo() { + grid.scrollTo(getItemId()); + } + + private Object getItemId() { + int row = Integer.parseInt(numberTextField.getValue()); + Object itemId = grid.getContainerDataSource().getIdByIndex(row); + return itemId; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java new file mode 100644 index 0000000000..c14503fb8d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java @@ -0,0 +1,361 @@ +/* + * Copyright 2000-2014 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.tests.components.grid; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.Keys; +import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.CheckBoxElement; +import com.vaadin.testbench.elements.GridElement.GridRowElement; +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.testbench.parallel.Browser; +import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.components.grid.basicfeatures.element.CustomGridElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +@TestCategory("grid") +public class GridDetailsLocationTest extends MultiBrowserTest { + + private static final int detailsDefaultHeight = 51; + private static final int detailsDefinedHeight = 33; + private static final int detailsDefinedHeightIE8 = 31; + + private static class Param { + private final int rowIndex; + private final boolean useGenerator; + private final boolean scrollFirstToBottom; + + public Param(int rowIndex, boolean useGenerator, + boolean scrollFirstToBottom) { + this.rowIndex = rowIndex; + this.useGenerator = useGenerator; + this.scrollFirstToBottom = scrollFirstToBottom; + } + + public int getRowIndex() { + return rowIndex; + } + + public boolean useGenerator() { + return useGenerator; + } + + public boolean scrollFirstToBottom() { + return scrollFirstToBottom; + } + + @Override + public String toString() { + return "Param [rowIndex=" + getRowIndex() + ", useGenerator=" + + useGenerator() + ", scrollFirstToBottom=" + + scrollFirstToBottom() + "]"; + } + + } + + public static Collection<Param> parameters() { + List<Param> data = new ArrayList<Param>(); + + int[] params = new int[] { 0, 500, 999 }; + + for (int rowIndex : params) { + + data.add(new Param(rowIndex, false, false)); + data.add(new Param(rowIndex, true, false)); + data.add(new Param(rowIndex, false, true)); + data.add(new Param(rowIndex, true, true)); + } + + return data; + } + + @Before + public void setUp() { + setDebug(true); + } + + @Test + public void toggleAndScroll() throws Throwable { + for (Param param : parameters()) { + try { + openTestURL(); + useGenerator(param.useGenerator()); + scrollToBottom(param.scrollFirstToBottom()); + + // the tested method + toggleAndScroll(param.getRowIndex()); + + verifyLocation(param); + } catch (Throwable t) { + throw new Throwable("" + param, t); + } + } + } + + @Test + public void scrollAndToggle() throws Throwable { + for (Param param : parameters()) { + try { + openTestURL(); + useGenerator(param.useGenerator()); + scrollToBottom(param.scrollFirstToBottom()); + + // the tested method + scrollAndToggle(param.getRowIndex()); + + verifyLocation(param); + + } catch (Throwable t) { + throw new Throwable("" + param, t); + } + } + } + + @Test + public void testDetailsHeightWithNoGenerator() { + openTestURL(); + toggleAndScroll(5); + + verifyDetailsRowHeight(5, detailsDefaultHeight, 0); + verifyDetailsDecoratorLocation(5, 0, 0); + + toggleAndScroll(0); + + verifyDetailsRowHeight(0, detailsDefaultHeight, 0); + verifyDetailsDecoratorLocation(0, 0, 1); + + verifyDetailsRowHeight(5, detailsDefaultHeight, 1); + verifyDetailsDecoratorLocation(5, 1, 0); + } + + @Test + public void testDetailsHeightWithGenerator() { + openTestURL(); + useGenerator(true); + toggleAndScroll(5); + + verifyDetailsRowHeight(5, getDefinedHeight(), 0); + verifyDetailsDecoratorLocation(5, 0, 0); + + toggleAndScroll(0); + + verifyDetailsRowHeight(0, getDefinedHeight(), 0); + // decorator elements are in DOM in the order they have been added + verifyDetailsDecoratorLocation(0, 0, 1); + + verifyDetailsRowHeight(5, getDefinedHeight(), 1); + verifyDetailsDecoratorLocation(5, 1, 0); + } + + private int getDefinedHeight() { + boolean ie8 = isIE8(); + return ie8 ? detailsDefinedHeightIE8 : detailsDefinedHeight; + } + + private void verifyDetailsRowHeight(int rowIndex, int expectedHeight, + int visibleIndexOfSpacer) { + waitForDetailsVisible(); + WebElement details = getDetailsElement(visibleIndexOfSpacer); + Assert.assertEquals("Wrong details row height", expectedHeight, details + .getSize().getHeight()); + } + + private void verifyDetailsDecoratorLocation(int row, + int visibleIndexOfSpacer, int visibleIndexOfDeco) { + WebElement detailsElement = getDetailsElement(visibleIndexOfSpacer); + WebElement detailsDecoElement = getDetailsDecoElement(visibleIndexOfDeco); + GridRowElement rowElement = getGrid().getRow(row); + + Assert.assertEquals( + "Details deco top position does not match row top pos", + rowElement.getLocation().getY(), detailsDecoElement + .getLocation().getY()); + Assert.assertEquals( + "Details deco bottom position does not match details bottom pos", + detailsElement.getLocation().getY() + + detailsElement.getSize().getHeight(), + detailsDecoElement.getLocation().getY() + + detailsDecoElement.getSize().getHeight()); + } + + private void verifyLocation(Param param) { + Assert.assertFalse("Notification was present", + isElementPresent(By.className("v-Notification"))); + + TestBenchElement headerRow = getGrid().getHeaderRow(0); + final int topBoundary = headerRow.getLocation().getX() + + headerRow.getSize().height; + final int bottomBoundary = getGrid().getLocation().getX() + + getGrid().getSize().getHeight() + - getHorizontalScrollbar().getSize().height; + + GridRowElement row = getGrid().getRow(param.getRowIndex()); + final int rowTop = row.getLocation().getX(); + + waitForDetailsVisible(); + WebElement details = getDetailsElement(); + final int detailsBottom = details.getLocation().getX() + + details.getSize().getHeight(); + + assertGreaterOrEqual("Row top should be inside grid, gridTop:" + + topBoundary + " rowTop" + rowTop, topBoundary, rowTop); + assertLessThanOrEqual( + "Decorator bottom should be inside grid, gridBottom:" + + bottomBoundary + " decoratorBotton:" + detailsBottom, + detailsBottom, bottomBoundary); + + verifyDetailsRowHeight(param.getRowIndex(), + param.useGenerator() ? getDefinedHeight() + : detailsDefaultHeight, 0); + verifyDetailsDecoratorLocation(param.getRowIndex(), 0, 0); + + Assert.assertFalse("Notification was present", + isElementPresent(By.className("v-Notification"))); + } + + private final By locator = By.className("v-grid-spacer"); + + private WebElement getDetailsElement() { + return getDetailsElement(0); + } + + private WebElement getDetailsElement(int index) { + return findElements(locator).get(index); + } + + private WebElement getDetailsDecoElement(int index) { + return findElements(By.className("v-grid-spacer-deco")).get(index); + } + + private void waitForDetailsVisible() { + waitUntil(new ExpectedCondition<WebElement>() { + + @Override + public WebElement apply(WebDriver driver) { + try { + WebElement detailsElement = getDetailsElement(); + return detailsElement.isDisplayed() + && detailsElement.getSize().getHeight() > 3 ? detailsElement + : null; + } catch (StaleElementReferenceException e) { + return null; + } + } + + @Override + public String toString() { + return "visibility of element located by " + locator; + } + + }, 5); + waitForElementVisible(By.className("v-grid-spacer")); + } + + private void scrollToBottom(boolean scrollFirstToBottom) { + if (scrollFirstToBottom) { + executeScript("arguments[0].scrollTop = 9999999", + getVerticalScrollbar()); + } + } + + private void useGenerator(boolean use) { + CheckBoxElement checkBox = $(CheckBoxElement.class).first(); + boolean isChecked = isCheckedValo(checkBox); + if (use != isChecked) { + clickValo(checkBox); + } + } + + private boolean isIE8() { + DesiredCapabilities desiredCapabilities = getDesiredCapabilities(); + DesiredCapabilities ie8Capabilities = Browser.IE8 + .getDesiredCapabilities(); + return desiredCapabilities.getBrowserName().equals( + ie8Capabilities.getBrowserName()) + && desiredCapabilities.getVersion().equals( + ie8Capabilities.getVersion()); + } + + @SuppressWarnings("boxing") + private boolean isCheckedValo(CheckBoxElement checkBoxElement) { + WebElement checkbox = checkBoxElement.findElement(By.tagName("input")); + Object value = executeScript("return arguments[0].checked;", checkbox); + return (Boolean) value; + } + + private void clickValo(CheckBoxElement checkBoxElement) { + checkBoxElement.findElement(By.tagName("label")).click(); + } + + private Object executeScript(String string, Object... param) { + return ((JavascriptExecutor) getDriver()).executeScript(string, param); + } + + private void scrollAndToggle(int row) { + setRow(row); + getScrollAndToggle().click(); + } + + private void toggleAndScroll(int row) { + setRow(row); + getToggleAndScroll().click(); + } + + private ButtonElement getScrollAndToggle() { + return $(ButtonElement.class).caption("Scroll and toggle").first(); + } + + private ButtonElement getToggleAndScroll() { + return $(ButtonElement.class).caption("Toggle and scroll").first(); + } + + private void setRow(int row) { + $(TextFieldElement.class).first().clear(); + $(TextFieldElement.class).first().sendKeys(String.valueOf(row), + Keys.ENTER, Keys.TAB); + } + + private CustomGridElement getGrid() { + return $(CustomGridElement.class).first(); + } + + private WebElement getVerticalScrollbar() { + WebElement scrollBar = getGrid().findElement( + By.className("v-grid-scroller-vertical")); + return scrollBar; + } + + private WebElement getHorizontalScrollbar() { + WebElement scrollBar = getGrid().findElement( + By.className("v-grid-scroller-horizontal")); + return scrollBar; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java index e03d50415c..c1b8028cbf 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java @@ -19,6 +19,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.util.List; + import org.openqa.selenium.By; import org.openqa.selenium.Dimension; import org.openqa.selenium.JavascriptExecutor; @@ -29,15 +31,21 @@ import com.vaadin.testbench.TestBenchElement; import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; -@TestCategory("escalator") +@TestCategory("grid") public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest { + + private static final String LOGICAL_ROW_ATTRIBUTE_NAME = "vLogicalRow"; + private static final String SPACER_CSS_CLASS = "v-escalator-spacer"; + protected static final String COLUMNS_AND_ROWS = "Columns and Rows"; protected static final String COLUMNS = "Columns"; protected static final String ADD_ONE_COLUMN_TO_BEGINNING = "Add one column to beginning"; protected static final String ADD_ONE_ROW_TO_BEGINNING = "Add one row to beginning"; + protected static final String ADD_ONE_ROW_TO_END = "Add one row to end"; protected static final String REMOVE_ONE_COLUMN_FROM_BEGINNING = "Remove one column from beginning"; protected static final String REMOVE_ONE_ROW_FROM_BEGINNING = "Remove one row from beginning"; + protected static final String REMOVE_ALL_ROWS = "Remove all rows"; protected static final String REMOVE_50_ROWS_FROM_BOTTOM = "Remove 50 rows from bottom"; protected static final String REMOVE_50_ROWS_FROM_ALMOST_BOTTOM = "Remove 50 rows from almost bottom"; protected static final String ADD_ONE_OF_EACH_ROW = "Add one of each row"; @@ -48,6 +56,8 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest protected static final String BODY_ROWS = "Body Rows"; protected static final String FOOTER_ROWS = "Footer Rows"; + protected static final String SCROLL_TO = "Scroll to..."; + protected static final String REMOVE_ALL_INSERT_SCROLL = "Remove all, insert 30 and scroll 40px"; protected static final String GENERAL = "General"; @@ -65,6 +75,20 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest protected static final String COLUMN_SPANNING = "Column spanning"; protected static final String COLSPAN_NORMAL = "Apply normal colspan"; protected static final String COLSPAN_NONE = "Apply no colspan"; + protected static final String SET_100PX = "Set 100px"; + protected static final String SPACERS = "Spacers"; + protected static final String FOCUSABLE_UPDATER = "Focusable Updater"; + protected static final String SCROLL_HERE_ANY_0PADDING = "Scroll here (ANY, 0)"; + protected static final String SCROLL_HERE_SPACERBELOW_ANY_0PADDING = "Scroll here row+spacer below (ANY, 0)"; + protected static final String REMOVE = "Remove"; + + protected static final String ROW_MINUS1 = "Row -1"; + protected static final String ROW_0 = "Row 0"; + protected static final String ROW_1 = "Row 1"; + protected static final String ROW_25 = "Row 25"; + protected static final String ROW_50 = "Row 50"; + protected static final String ROW_75 = "Row 75"; + protected static final String ROW_99 = "Row 99"; @Override protected Class<?> getUIClass() { @@ -163,15 +187,16 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest private TestBenchElement getRow(String sectionTag, int row) { TestBenchElement escalator = getEscalator(); WebElement tableSection = escalator.findElement(By.tagName(sectionTag)); - By xpath; + String xpathExpression = "tr[not(@class='" + SPACER_CSS_CLASS + "')]"; if (row >= 0) { int fromFirst = row + 1; - xpath = By.xpath("tr[" + fromFirst + "]"); + xpathExpression += "[" + fromFirst + "]"; } else { int fromLast = Math.abs(row + 1); - xpath = By.xpath("tr[last() - " + fromLast + "]"); + xpathExpression += "[last() - " + fromLast + "]"; } + By xpath = By.xpath(xpathExpression); if (tableSection != null && ((TestBenchElement) tableSection).isElementPresent(xpath)) { return (TestBenchElement) tableSection.findElement(xpath); @@ -235,17 +260,26 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest } protected void scrollVerticallyTo(int px) { - executeScript("arguments[0].scrollTop = " + px, getVerticalScrollbar()); + getVerticalScrollbar().scroll(px); } - protected TestBenchElement getVerticalScrollbar() { + protected long getScrollTop() { + return ((Long) executeScript("return arguments[0].scrollTop;", + getVerticalScrollbar())).longValue(); + } + + private TestBenchElement getVerticalScrollbar() { return (TestBenchElement) getEscalator().findElement( By.className("v-escalator-scroller-vertical")); } protected void scrollHorizontallyTo(int px) { - executeScript("arguments[0].scrollLeft = " + px, - getHorizontalScrollbar()); + getHorizontalScrollbar().scrollLeft(px); + } + + protected long getScrollLeft() { + return ((Long) executeScript("return arguments[0].scrollLeft;", + getHorizontalScrollbar())).longValue(); } protected TestBenchElement getHorizontalScrollbar() { @@ -260,4 +294,29 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest protected void populate() { selectMenuPath(GENERAL, POPULATE_COLUMN_ROW); } + + private List<WebElement> getSpacers() { + return getEscalator().findElements(By.className(SPACER_CSS_CLASS)); + } + + protected boolean spacersAreFoundInDom() { + List<WebElement> spacers = getSpacers(); + return spacers != null && !spacers.isEmpty(); + } + + @SuppressWarnings("boxing") + protected WebElement getSpacer(int logicalRowIndex) { + List<WebElement> spacers = getSpacers(); + System.out.println("size: " + spacers.size()); + for (WebElement spacer : spacers) { + System.out.println(spacer + ", " + logicalRowIndex); + Boolean isInDom = (Boolean) executeScript("return arguments[0]['" + + LOGICAL_ROW_ATTRIBUTE_NAME + "'] === arguments[1]", + spacer, logicalRowIndex); + if (isInDom) { + return spacer; + } + } + return null; + } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java index ad3e1fe5eb..754529d10d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java @@ -15,13 +15,15 @@ */ package com.vaadin.tests.components.grid.basicfeatures; +import java.util.List; + import org.openqa.selenium.Dimension; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import com.vaadin.testbench.By; import com.vaadin.testbench.TestBenchElement; -import com.vaadin.testbench.elements.GridElement; +import com.vaadin.tests.components.grid.basicfeatures.element.CustomGridElement; /** * GridBasicClientFeatures. @@ -79,13 +81,27 @@ public abstract class GridBasicClientFeaturesTest extends GridBasicFeaturesTest } @Override - protected GridElement getGridElement() { + protected CustomGridElement getGridElement() { if (composite) { // Composite requires the basic client features widget for subparts return ((TestBenchElement) findElement(By - .vaadin("//TestWidgetComponent"))).wrap(GridElement.class); + .vaadin("//TestWidgetComponent"))) + .wrap(CustomGridElement.class); } else { return super.getGridElement(); } } + + @Override + protected void assertColumnHeaderOrder(int... indices) { + List<TestBenchElement> headers = getGridHeaderRowCells(); + for (int i = 0; i < indices.length; i++) { + assertColumnHeader("HEADER (0," + indices[i] + ")", headers.get(i)); + } + } + + protected void toggleColumnReorder() { + selectMenuPath("Component", "State", "Column Reordering"); + } + } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index e5a46894b8..8c60deaf3c 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -46,10 +46,17 @@ import com.vaadin.tests.components.AbstractComponentTest; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Component; +import com.vaadin.ui.CssLayout; import com.vaadin.ui.Grid; import com.vaadin.ui.Grid.CellReference; import com.vaadin.ui.Grid.CellStyleGenerator; import com.vaadin.ui.Grid.Column; +import com.vaadin.ui.Grid.ColumnReorderEvent; +import com.vaadin.ui.Grid.ColumnReorderListener; +import com.vaadin.ui.Grid.ColumnVisibilityChangeEvent; +import com.vaadin.ui.Grid.ColumnVisibilityChangeListener; +import com.vaadin.ui.Grid.DetailsGenerator; import com.vaadin.ui.Grid.FooterCell; import com.vaadin.ui.Grid.HeaderCell; import com.vaadin.ui.Grid.HeaderRow; @@ -58,6 +65,9 @@ import com.vaadin.ui.Grid.RowReference; import com.vaadin.ui.Grid.RowStyleGenerator; import com.vaadin.ui.Grid.SelectionMode; import com.vaadin.ui.Grid.SelectionModel; +import com.vaadin.ui.Label; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Panel; import com.vaadin.ui.renderers.DateRenderer; import com.vaadin.ui.renderers.HtmlRenderer; import com.vaadin.ui.renderers.NumberRenderer; @@ -109,6 +119,74 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { } }; + private ColumnReorderListener columnReorderListener = new ColumnReorderListener() { + + @Override + public void columnReorder(ColumnReorderEvent event) { + log("Columns reordered, userOriginated: " + + event.isUserOriginated()); + } + }; + + private ColumnVisibilityChangeListener columnVisibilityListener = new ColumnVisibilityChangeListener() { + @Override + public void columnVisibilityChanged(ColumnVisibilityChangeEvent event) { + log("Visibility changed: "// + + "propertyId: " + event.getColumn().getPropertyId() // + + ", isHidden: " + event.getColumn().isHidden() // + + ", userOriginated: " + event.isUserOriginated()); + } + }; + + private Panel detailsPanel; + + private final DetailsGenerator detailedDetailsGenerator = new DetailsGenerator() { + @Override + public Component getDetails(final RowReference rowReference) { + CssLayout cssLayout = new CssLayout(); + cssLayout.setHeight("200px"); + cssLayout.setWidth("100%"); + + Item item = rowReference.getItem(); + for (Object propertyId : item.getItemPropertyIds()) { + Property<?> prop = item.getItemProperty(propertyId); + String string = prop.getValue().toString(); + cssLayout.addComponent(new Label(string)); + } + + final int rowIndex = grid.getContainerDataSource().indexOfId( + rowReference.getItemId()); + ClickListener clickListener = new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + Notification.show("You clicked on the " + + "button in the details for " + "row " + rowIndex); + } + }; + cssLayout.addComponent(new Button("Press me", clickListener)); + return cssLayout; + } + }; + + private final DetailsGenerator watchingDetailsGenerator = new DetailsGenerator() { + private int id = 0; + + @Override + public Component getDetails(RowReference rowReference) { + return new Label("You are watching item id " + + rowReference.getItemId() + " (" + (id++) + ")"); + } + }; + + private final DetailsGenerator hierarchicalDetailsGenerator = new DetailsGenerator() { + @Override + public Component getDetails(RowReference rowReference) { + detailsPanel = new Panel(); + detailsPanel.setContent(new Label("One")); + return detailsPanel; + } + }; + @Override @SuppressWarnings("unchecked") protected Grid constructComponent() { @@ -213,7 +291,9 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { // Set varying column widths for (int col = 0; col < COLUMNS; col++) { - grid.getColumn(getColumnProperty(col)).setWidth(100 + col * 50); + Column column = grid.getColumn(getColumnProperty(col)); + column.setWidth(100 + col * 50); + column.setHidable(isColumnHidableByDefault(col)); } grid.addSortListener(new SortListener() { @@ -248,10 +328,35 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { addFilterActions(); + addInternalActions(); + + createDetailsActions(); + this.grid = grid; return grid; } + protected boolean isColumnHidableByDefault(int col) { + return false; + } + + protected boolean isColumnHiddenByDefault(int col) { + return false; + } + + private void addInternalActions() { + createClickAction("Update column order without updating client", + "Internals", new Command<Grid, Void>() { + @Override + public void execute(Grid grid, Void value, Object data) { + List<Column> columns = grid.getColumns(); + grid.setColumnOrder(columns.get(1).getPropertyId(), + columns.get(0).getPropertyId()); + grid.getUI().getConnectorTracker().markClean(grid); + } + }, null); + } + private void addFilterActions() { createClickAction("Column 1 starts with \"(23\"", "Filter", new Command<Grid, Void>() { @@ -494,6 +599,29 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { } }); + createBooleanAction("ColumnReorderListener", "State", false, + new Command<Grid, Boolean>() { + + @Override + public void execute(Grid grid, Boolean value, Object data) { + if (value) { + grid.addColumnReorderListener(columnReorderListener); + } else { + grid.removeColumnReorderListener(columnReorderListener); + } + } + }); + createBooleanAction("ColumnVisibilityChangeListener", "State", false, + new Command<Grid, Boolean>() { + @Override + public void execute(Grid grid, Boolean value, Object data) { + if (value) { + grid.addColumnVisibilityChangeListener(columnVisibilityListener); + } else { + grid.removeColumnVisibilityChangeListener(columnVisibilityListener); + } + } + }); createBooleanAction("Single select allow deselect", "State", singleSelectAllowDeselect, new Command<Grid, Boolean>() { @@ -508,6 +636,14 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { } } }); + createBooleanAction("Column Reordering Allowed", "State", false, + new Command<Grid, Boolean>() { + + @Override + public void execute(Grid c, Boolean value, Object data) { + c.setColumnReorderingAllowed(value); + } + }); } protected void createHeaderActions() { @@ -630,9 +766,9 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { }, null); } + @SuppressWarnings("boxing") protected void createColumnActions() { createCategory("Columns", null); - for (int c = 0; c < COLUMNS; c++) { final int index = c; createCategory(getColumnProperty(c), "Columns"); @@ -640,16 +776,55 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { createClickAction("Add / Remove", getColumnProperty(c), new Command<Grid, String>() { + boolean wasHidable; + boolean wasHidden; + String wasColumnHidingToggleCaption; + @Override public void execute(Grid grid, String value, Object data) { String columnProperty = getColumnProperty((Integer) data); - if (grid.getColumn(columnProperty) == null) { - grid.addColumn(columnProperty); + Column column = grid.getColumn(columnProperty); + if (column == null) { + column = grid.addColumn(columnProperty); + column.setHidable(wasHidable); + column.setHidden(wasHidden); + column.setHidingToggleCaption(wasColumnHidingToggleCaption); } else { + wasHidable = column.isHidable(); + wasHidden = column.isHidden(); + wasColumnHidingToggleCaption = column + .getHidingToggleCaption(); grid.removeColumn(columnProperty); } } }, null, c); + createClickAction("Move left", getColumnProperty(c), + new Command<Grid, String>() { + + @Override + public void execute(Grid grid, String value, Object data) { + final String columnProperty = getColumnProperty((Integer) data); + List<Column> cols = grid.getColumns(); + List<Object> reordered = new ArrayList<Object>(); + boolean addAsLast = false; + for (int i = 0; i < cols.size(); i++) { + Column col = cols.get(i); + if (col.getPropertyId().equals(columnProperty)) { + if (i == 0) { + addAsLast = true; + } else { + reordered.add(i - 1, columnProperty); + } + } else { + reordered.add(col.getPropertyId()); + } + } + if (addAsLast) { + reordered.add(columnProperty); + } + grid.setColumnOrder(reordered.toArray()); + } + }, null, c); createBooleanAction("Sortable", getColumnProperty(c), true, new Command<Grid, Boolean>() { @@ -663,6 +838,37 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { } }, c); + createBooleanAction("Hidable", getColumnProperty(c), + isColumnHidableByDefault(c), new Command<Grid, Boolean>() { + @Override + public void execute(Grid c, Boolean hidable, + Object propertyId) { + grid.getColumn(propertyId).setHidable(hidable); + } + }, getColumnProperty(c)); + + createBooleanAction("Hidden", getColumnProperty(c), + isColumnHiddenByDefault(c), new Command<Grid, Boolean>() { + @Override + public void execute(Grid c, Boolean hidden, + Object propertyId) { + grid.getColumn(propertyId).setHidden(hidden); + } + }, getColumnProperty(c)); + createClickAction("Change hiding toggle caption", + getColumnProperty(c), new Command<Grid, String>() { + int count = 0; + + @Override + public void execute(Grid grid, String value, Object data) { + final String columnProperty = getColumnProperty((Integer) data); + grid.getColumn(columnProperty) + .setHidingToggleCaption( + columnProperty + " caption " + + count++); + } + }, null, c); + createCategory("Column " + c + " Width", getColumnProperty(c)); createClickAction("Auto", "Column " + c + " Width", @@ -680,7 +886,6 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { createClickAction("25.5px", "Column " + c + " Width", new Command<Grid, Void>() { @Override - @SuppressWarnings("boxing") public void execute(Grid grid, Void value, Object columnIndex) { grid.getColumns().get((Integer) columnIndex) @@ -778,6 +983,17 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { }, c); } + createBooleanAction("All columns hidable", "Columns", false, + new Command<Grid, Boolean>() { + + @Override + public void execute(Grid c, Boolean value, Object data) { + for (Column col : grid.getColumns()) { + col.setHidable(value); + } + + } + }); } private static String getColumnProperty(int c) { @@ -1051,6 +1267,67 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> { }, null); } + private void createDetailsActions() { + Command<Grid, DetailsGenerator> swapDetailsGenerator = new Command<Grid, DetailsGenerator>() { + @Override + public void execute(Grid c, DetailsGenerator generator, Object data) { + grid.setDetailsGenerator(generator); + } + }; + + Command<Grid, Boolean> openOrCloseItemId = new Command<Grid, Boolean>() { + @Override + @SuppressWarnings("boxing") + public void execute(Grid g, Boolean visible, Object itemId) { + g.setDetailsVisible(itemId, visible); + } + }; + + createCategory("Generators", "Details"); + createClickAction("NULL", "Generators", swapDetailsGenerator, + DetailsGenerator.NULL); + createClickAction("\"Watching\"", "Generators", swapDetailsGenerator, + watchingDetailsGenerator); + createClickAction("Detailed", "Generators", swapDetailsGenerator, + detailedDetailsGenerator); + createClickAction("Hierarchical", "Generators", swapDetailsGenerator, + hierarchicalDetailsGenerator); + + createClickAction("- Change Component", "Generators", + new Command<Grid, Void>() { + @Override + public void execute(Grid c, Void value, Object data) { + Label label = (Label) detailsPanel.getContent(); + if (label.getValue().equals("One")) { + detailsPanel.setContent(new Label("Two")); + } else { + detailsPanel.setContent(new Label("One")); + } + } + }, null); + + createClickAction("Toggle firstItemId", "Details", + new Command<Grid, Void>() { + @Override + public void execute(Grid g, Void value, Object data) { + Object firstItemId = g.getContainerDataSource() + .firstItemId(); + boolean toggle = g.isDetailsVisible(firstItemId); + g.setDetailsVisible(firstItemId, !toggle); + g.setDetailsVisible(firstItemId, toggle); + } + }, null); + + createBooleanAction("Open firstItemId", "Details", false, + openOrCloseItemId, ds.firstItemId()); + + createBooleanAction("Open 1", "Details", false, openOrCloseItemId, + ds.getIdByIndex(1)); + + createBooleanAction("Open 995", "Details", false, openOrCloseItemId, + ds.getIdByIndex(995)); + } + @Override protected Integer getTicketNumber() { return 12829; diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java index e22fcc422b..469bf37c2f 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java @@ -15,6 +15,9 @@ */ package com.vaadin.tests.components.grid.basicfeatures; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.util.ArrayList; import java.util.List; @@ -25,13 +28,18 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import com.vaadin.testbench.TestBenchElement; -import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.elements.GridElement.GridCellElement; import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.components.grid.basicfeatures.element.CustomGridElement; import com.vaadin.tests.tb3.MultiBrowserTest; @TestCategory("grid") public abstract class GridBasicFeaturesTest extends MultiBrowserTest { + public enum CellSide { + LEFT, RIGHT; + } + @Override protected boolean requireWindowFocusForIE() { return true; @@ -59,9 +67,9 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { } } - protected GridElement getGridElement() { + protected CustomGridElement getGridElement() { return ((TestBenchElement) findElement(By.id("testComponent"))) - .wrap(GridElement.class); + .wrap(CustomGridElement.class); } protected void scrollGridVerticallyTo(double px) { @@ -69,6 +77,11 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { getGridVerticalScrollbar()); } + protected void scrollGridHorizontallyTo(double px) { + executeScript("arguments[0].scrollLeft = " + px, + getGridHorizontalScrollbar()); + } + protected int getGridVerticalScrollPos() { return ((Number) executeScript("return arguments[0].scrollTop", getGridVerticalScrollbar())).intValue(); @@ -117,6 +130,12 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { By.xpath("//div[contains(@class, \"v-grid-scroller-vertical\")]")); } + protected WebElement getGridHorizontalScrollbar() { + return getDriver() + .findElement( + By.xpath("//div[contains(@class, \"v-grid-scroller-horizontal\")]")); + } + /** * Reloads the page without restartApplication. This occasionally breaks * stuff. @@ -127,4 +146,118 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { testUrl = testUrl.replace("?&", "?"); driver.get(testUrl); } + + protected void focusCell(int row, int column) { + getGridElement().getCell(row, column).click(); + } + + protected void setFrozenColumns(int numberOfFrozenColumns) { + selectMenuPath("Component", "State", "Frozen column count", + Integer.toString(numberOfFrozenColumns)); + } + + protected void assertColumnHeaderOrder(int... indices) { + List<TestBenchElement> headers = getGridHeaderRowCells(); + for (int i = 0; i < indices.length; i++) { + assertColumnHeader("Column " + indices[i], headers.get(i)); + } + } + + protected void assertColumnHeader(String expectedHeaderCaption, + TestBenchElement testBenchElement) { + assertEquals(expectedHeaderCaption.toLowerCase(), testBenchElement + .getText().toLowerCase()); + } + + protected GridCellElement getDefaultColumnHeader(int index) { + List<GridCellElement> headerRowCells = getGridElement().getHeaderCells( + 0); + return headerRowCells.get(index); + } + + protected void dragAndDropDefaultColumnHeader(int draggedColumnHeaderIndex, + int onTopOfColumnHeaderIndex, CellSide cellSide) { + GridCellElement columnHeader = getDefaultColumnHeader(onTopOfColumnHeaderIndex); + new Actions(getDriver()) + .clickAndHold(getDefaultColumnHeader(draggedColumnHeaderIndex)) + .moveToElement( + columnHeader, + getHorizontalOffsetForDragAndDrop(columnHeader, + cellSide), 0).release().perform(); + } + + private int getHorizontalOffsetForDragAndDrop(GridCellElement columnHeader, + CellSide cellSide) { + if (cellSide == CellSide.LEFT) { + return 5; + } else { + int half = columnHeader.getSize().getWidth() / 2; + return half + (half / 2); + } + } + + protected void dragAndDropColumnHeader(int headerRow, + int draggedColumnHeaderIndex, int onTopOfColumnHeaderIndex, + CellSide cellSide) { + GridCellElement headerCell = getGridElement().getHeaderCell(headerRow, + onTopOfColumnHeaderIndex); + new Actions(getDriver()) + .clickAndHold( + getGridElement().getHeaderCell(headerRow, + draggedColumnHeaderIndex)) + .moveToElement( + headerCell, + getHorizontalOffsetForDragAndDrop(headerCell, cellSide), + 0).release().perform(); + } + + protected void dragAndDropColumnHeader(int headerRow, + int draggedColumnHeaderIndex, int onTopOfColumnHeaderIndex, + int horizontalOffset) { + GridCellElement headerCell = getGridElement().getHeaderCell(headerRow, + onTopOfColumnHeaderIndex); + new Actions(getDriver()) + .clickAndHold( + getGridElement().getHeaderCell(headerRow, + draggedColumnHeaderIndex)) + .moveToElement(headerCell, horizontalOffset, 0).release() + .perform(); + } + + protected void assertColumnIsSorted(int index) { + WebElement columnHeader = getDefaultColumnHeader(index); + assertTrue(columnHeader.getAttribute("class").contains("sort")); + } + + protected void assertFocusedCell(int row, int column) { + assertTrue(getGridElement().getCell(row, column).getAttribute("class") + .contains("focused")); + } + + protected WebElement getSidebar() { + List<WebElement> elements = findElements(By.className("v-grid-sidebar")); + return elements.isEmpty() ? null : elements.get(0); + } + + protected WebElement getSidebarOpenButton() { + List<WebElement> elements = findElements(By + .className("v-grid-sidebar-button")); + return elements.isEmpty() ? null : elements.get(0); + } + + /** + * Returns the toggle inside the sidebar for hiding the column at the given + * index, or null if not found. + */ + protected WebElement getColumnHidingToggle(int columnIndex) { + WebElement sidebar = getSidebar(); + List<WebElement> elements = sidebar.findElements(By + .className("column-hiding-toggle")); + for (WebElement e : elements) { + if ((e.getText().toLowerCase()).startsWith("column " + columnIndex)) { + return e; + } + } + return null; + } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java new file mode 100644 index 0000000000..b446bdef48 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java @@ -0,0 +1,994 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.GridElement.GridCellElement; +import com.vaadin.testbench.parallel.TestCategory; + +@TestCategory("grid") +public class GridColumnHidingTest extends GridBasicClientFeaturesTest { + + private static final String CAPTION_0_1 = "Join column cells 0, 1"; + private static final String CAPTION_1_2 = "Join columns 1, 2"; + private static final String CAPTION_3_4_5 = "Join columns 3, 4, 5"; + private static final String CAPTION_ALL = "Join all columns"; + + @Before + public void before() { + openTestURL(); + } + + @Test + public void testColumnHiding_hidingColumnsFromAPI_works() { + selectMenuPath("Component", "State", "Width", "1000px"); + assertColumnHeaderOrder(0, 1, 2, 3, 4, 5, 6); + + toggleHideColumnAPI(0); + assertColumnHeaderOrder(1, 2, 3, 4, 5, 6); + + toggleHideColumnAPI(1); + toggleHideColumnAPI(2); + toggleHideColumnAPI(3); + assertColumnHeaderOrder(4, 5, 6, 7, 8); + } + + @Test + public void testColumnHiding_unhidingColumnsFromAPI_works() { + selectMenuPath("Component", "State", "Width", "1000px"); + assertColumnHeaderOrder(0, 1, 2, 3, 4, 5, 6); + + toggleHideColumnAPI(0); + assertColumnHeaderOrder(1, 2, 3, 4, 5, 6); + + toggleHideColumnAPI(0); + assertColumnHeaderOrder(0, 1, 2, 3, 4, 5, 6); + + toggleHideColumnAPI(1); + toggleHideColumnAPI(2); + toggleHideColumnAPI(3); + assertColumnHeaderOrder(0, 4, 5, 6, 7, 8); + + toggleHideColumnAPI(1); + toggleHideColumnAPI(2); + assertColumnHeaderOrder(0, 1, 2, 4, 5, 6); + } + + @Test + public void testColumnHiding_hidingUnhidingFromAPI_works() { + selectMenuPath("Component", "State", "Width", "1000px"); + assertColumnHeaderOrder(0, 1, 2, 3, 4, 5, 6); + + toggleHideColumnAPI(2); + assertColumnHeaderOrder(0, 1, 3, 4, 5, 6); + + toggleHideColumnAPI(2); + assertColumnHeaderOrder(0, 1, 2, 3, 4, 5, 6); + + toggleHideColumnAPI(2); + assertColumnHeaderOrder(0, 1, 3, 4, 5, 6); + + toggleHideColumnAPI(2); + assertColumnHeaderOrder(0, 1, 2, 3, 4, 5, 6); + } + + @Test + public void testColumnHiding_changeVisibilityAPI_triggersClientSideEvent() { + assertColumnHeaderOrder(0, 1, 2, 3, 4); + selectMenuPath("Component", "Internals", "Listeners", + "Add Column Visibility Change listener"); + + toggleHideColumnAPI(2); + assertColumnHeaderOrder(0, 1, 3, 4); + + WebElement webElement = findElement(By.id("columnvisibility")); + int counter = Integer.parseInt(webElement.getAttribute("counter")); + int columnIndex = Integer.parseInt(webElement + .getAttribute("columnindex")); + boolean userOriginated = Boolean.parseBoolean(webElement + .getAttribute("useroriginated")); + boolean hidden = Boolean.parseBoolean(webElement + .getAttribute("ishidden")); + + assertNotNull("no event fired", webElement); + assertEquals(1, counter); + assertEquals(2, columnIndex); + assertEquals(false, userOriginated); + assertEquals(true, hidden); + + toggleHideColumnAPI(2); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + webElement = findElement(By.id("columnvisibility")); + counter = Integer.parseInt(webElement.getAttribute("counter")); + columnIndex = Integer.parseInt(webElement.getAttribute("columnIndex")); + userOriginated = Boolean.parseBoolean(webElement + .getAttribute("userOriginated")); + hidden = Boolean.parseBoolean(webElement.getAttribute("ishidden")); + + assertNotNull("no event fired", webElement); + assertEquals(2, counter); + assertEquals(2, columnIndex); + assertEquals(false, userOriginated); + assertEquals(false, hidden); + } + + @Test + public void testColumnHiding_changeVisibilityToggle_triggersClientSideEvent() { + assertColumnHeaderOrder(0, 1, 2, 3, 4); + selectMenuPath("Component", "Internals", "Listeners", + "Add Column Visibility Change listener"); + + toggleHidableColumnAPI(2); + clickSidebarOpenButton(); + getColumnHidingToggle(2).click(); + assertColumnHeaderOrder(0, 1, 3, 4); + + WebElement webElement = findElement(By.id("columnvisibility")); + int counter = Integer.parseInt(webElement.getAttribute("counter")); + int columnIndex = Integer.parseInt(webElement + .getAttribute("columnindex")); + boolean userOriginated = Boolean.parseBoolean(webElement + .getAttribute("useroriginated")); + boolean hidden = Boolean.parseBoolean(webElement + .getAttribute("ishidden")); + + assertNotNull("no event fired", webElement); + assertEquals(1, counter); + assertEquals(2, columnIndex); + assertEquals(true, userOriginated); + assertEquals(true, hidden); + + getColumnHidingToggle(2).click(); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + webElement = findElement(By.id("columnvisibility")); + counter = Integer.parseInt(webElement.getAttribute("counter")); + columnIndex = Integer.parseInt(webElement.getAttribute("columnIndex")); + userOriginated = Boolean.parseBoolean(webElement + .getAttribute("userOriginated")); + hidden = Boolean.parseBoolean(webElement.getAttribute("ishidden")); + + assertNotNull("no event fired", webElement); + assertEquals(2, counter); + assertEquals(2, columnIndex); + assertEquals(true, userOriginated); + assertEquals(false, hidden); + } + + @Test + public void testColumnHidability_onTriggerColumnHidability_showsSidebarButton() { + WebElement sidebar = getSidebar(); + assertNull(sidebar); + + toggleHidableColumnAPI(0); + + sidebar = getSidebar(); + assertNotNull(sidebar); + } + + @Test + public void testColumnHidability_triggeringColumnHidabilityWithSeveralColumns_showsAndHidesSiderbarButton() { + verifySidebarNotVisible(); + + toggleHidableColumnAPI(3); + toggleHidableColumnAPI(4); + + verifySidebarVisible(); + + toggleHidableColumnAPI(3); + + verifySidebarVisible(); + + toggleHidableColumnAPI(4); + + verifySidebarNotVisible(); + } + + @Test + public void testColumnHidability_clickingSidebarButton_opensClosesSidebar() { + toggleHidableColumnAPI(0); + verifySidebarClosed(); + + clickSidebarOpenButton(); + + verifySidebarOpened(); + + clickSidebarOpenButton(); + + verifySidebarClosed(); + } + + @Test + public void testColumnHidability_settingColumnHidable_showsToggleInSidebar() { + toggleHidableColumnAPI(0); + verifySidebarClosed(); + clickSidebarOpenButton(); + verifySidebarOpened(); + + verifyColumnHidingOption(0, false); + } + + @Test + public void testColumnHiding_hidingColumnWithToggle_works() { + assertColumnHeaderOrder(0, 1, 2, 3, 4); + toggleHidableColumnAPI(0); + verifySidebarClosed(); + clickSidebarOpenButton(); + verifySidebarOpened(); + verifyColumnHidingOption(0, false); + + getColumnHidingToggle(0).click(); + verifyColumnHidingOption(0, true); + assertColumnHeaderOrder(1, 2, 3, 4); + + getColumnHidingToggle(0).click(); + verifyColumnHidingOption(0, false); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + } + + @Test + public void testColumnHiding_updatingHiddenWhileSidebarClosed_updatesToggleValue() { + toggleHidableColumnAPI(0); + toggleHidableColumnAPI(3); + toggleHideColumnAPI(3); + assertColumnHeaderOrder(0, 1, 2, 4); + verifySidebarClosed(); + + clickSidebarOpenButton(); + verifySidebarOpened(); + verifyColumnHidingOption(0, false); + verifyColumnHidingOption(3, true); + + clickSidebarOpenButton(); + verifySidebarClosed(); + + toggleHideColumnAPI(0); + toggleHideColumnAPI(3); + + clickSidebarOpenButton(); + verifySidebarOpened(); + verifyColumnHidingOption(0, true); + verifyColumnHidingOption(3, false); + + } + + @Test + public void testColumnHiding_hidingMultipleColumnsWithToggle_hidesColumns() { + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + toggleHideColumnAPI(1); + toggleHidableColumnAPI(0); + toggleHidableColumnAPI(1); + toggleHidableColumnAPI(2); + toggleHidableColumnAPI(3); + toggleHidableColumnAPI(4); + verifySidebarClosed(); + assertColumnHeaderOrder(0, 2, 3, 4); + + clickSidebarOpenButton(); + verifySidebarOpened(); + verifyColumnHidingOption(0, false); + verifyColumnHidingOption(1, true); + verifyColumnHidingOption(2, false); + verifyColumnHidingOption(3, false); + verifyColumnHidingOption(4, false); + + // must be done in a funny order so that the header indexes won't break + // (because of data source uses counter) + getColumnHidingToggle(1).click(); + getColumnHidingToggle(2).click(); + getColumnHidingToggle(3).click(); + getColumnHidingToggle(4).click(); + getColumnHidingToggle(0).click(); + verifyColumnHidingOption(0, true); + verifyColumnHidingOption(1, false); + verifyColumnHidingOption(2, true); + verifyColumnHidingOption(3, true); + verifyColumnHidingOption(4, true); + + assertColumnHeaderOrder(1, 5, 6, 7); + + getColumnHidingToggle(0).click(); + getColumnHidingToggle(2).click(); + getColumnHidingToggle(1).click(); + verifyColumnHidingOption(0, false); + verifyColumnHidingOption(1, true); + verifyColumnHidingOption(2, false); + assertColumnHeaderOrder(0, 2, 5, 6); + } + + @Test + public void testColumnHidability_changingHidabilityWhenSidebarClosed_addsRemovesToggles() { + toggleHideColumnAPI(0); + toggleHideColumnAPI(4); + assertColumnHeaderOrder(1, 2, 3, 5); + toggleHidableColumnAPI(0); + toggleHidableColumnAPI(3); + toggleHidableColumnAPI(4); + verifySidebarClosed(); + + clickSidebarOpenButton(); + verifySidebarOpened(); + verifyColumnHidingOption(0, true); + verifyColumnHidingOption(3, false); + verifyColumnHidingOption(4, true); + + clickSidebarOpenButton(); + verifySidebarClosed(); + + toggleHidableColumnAPI(0); + toggleHidableColumnAPI(3); + + verifySidebarClosed(); + clickSidebarOpenButton(); + verifySidebarOpened(); + verifyColumnHidingOption(4, true); + + assertNull(getColumnHidingToggle(0)); + assertNull(getColumnHidingToggle(3)); + } + + @Test + public void testColumnHidability_togglingHidability_placesTogglesInRightOrder() { + toggleHidableColumnAPI(3); + toggleHidableColumnAPI(2); + clickSidebarOpenButton(); + + verifyColumnHidingTogglesOrder(2, 3); + + toggleHidableColumnAPI(1); + toggleHidableColumnAPI(2); + toggleHidableColumnAPI(6); + toggleHidableColumnAPI(0); + + verifyColumnHidingTogglesOrder(0, 1, 3, 6); + + clickSidebarOpenButton(); + + toggleHidableColumnAPI(2); + toggleHidableColumnAPI(4); + toggleHidableColumnAPI(7); + + clickSidebarOpenButton(); + + verifyColumnHidingTogglesOrder(0, 1, 2, 3, 4, 6, 7); + } + + @Test + public void testColumnHidability_reorderingColumns_updatesColumnToggleOrder() { + selectMenuPath("Component", "State", "Width", "1000px"); + toggleHidableColumnAPI(0); + toggleHidableColumnAPI(1); + toggleHidableColumnAPI(3); + toggleHidableColumnAPI(4); + clickSidebarOpenButton(); + verifyColumnHidingTogglesOrder(0, 1, 3, 4); + clickSidebarOpenButton(); + + toggleColumnReorder(); + dragAndDropColumnHeader(0, 3, 0, CellSide.LEFT); + + assertColumnHeaderOrder(3, 0, 1, 2, 4); + clickSidebarOpenButton(); + verifyColumnHidingTogglesOrder(3, 0, 1, 4); + + clickSidebarOpenButton(); + dragAndDropColumnHeader(0, 1, 3, CellSide.RIGHT); + dragAndDropColumnHeader(0, 4, 0, CellSide.LEFT); + dragAndDropColumnHeader(0, 3, 0, CellSide.LEFT); + + assertColumnHeaderOrder(2, 4, 3, 1, 0); + clickSidebarOpenButton(); + verifyColumnHidingTogglesOrder(4, 3, 1, 0); + } + + @Test + public void testColumnHidingAndReorder_reorderingOverHiddenColumn_orderIsKept() { + selectMenuPath("Component", "State", "Width", "1000px"); + toggleColumnReorder(); + toggleHideColumnAPI(0); + assertColumnHeaderOrder(1, 2, 3, 4, 5); + + dragAndDropColumnHeader(0, 1, 0, CellSide.LEFT); + assertColumnHeaderOrder(2, 1, 3, 4, 5); + + toggleHideColumnAPI(0); + assertColumnHeaderOrder(0, 2, 1, 3, 4, 5); + + toggleHideColumnAPI(1); + assertColumnHeaderOrder(0, 2, 3, 4, 5); + + // right side of hidden column + dragAndDropColumnHeader(0, 0, 2, CellSide.LEFT); + assertColumnHeaderOrder(2, 0, 3, 4, 5); + + toggleHideColumnAPI(1); + assertColumnHeaderOrder(2, 1, 0, 3, 4, 5); + + toggleHideColumnAPI(0); + assertColumnHeaderOrder(2, 1, 3, 4, 5); + + // left side of hidden column + dragAndDropColumnHeader(0, 0, 1, CellSide.RIGHT); + assertColumnHeaderOrder(1, 2, 3, 4, 5); + + toggleHideColumnAPI(0); + assertColumnHeaderOrder(1, 0, 2, 3, 4, 5); + } + + @Test + public void testColumnHidingAndReorder_reorderingWithMultipleHiddenColumns_works() { + selectMenuPath("Component", "State", "Width", "1000px"); + toggleColumnReorder(); + toggleHideColumnAPI(2); + toggleHideColumnAPI(3); + assertColumnHeaderOrder(0, 1, 4, 5, 6); + + dragAndDropDefaultColumnHeader(0, 2, CellSide.LEFT); + assertColumnHeaderOrder(1, 0, 4, 5, 6); + + toggleHideColumnAPI(3); + assertColumnHeaderOrder(1, 3, 0, 4, 5, 6); + + toggleHideColumnAPI(2); + assertColumnHeaderOrder(1, 2, 3, 0, 4, 5, 6); + + toggleHideColumnAPI(0); + toggleHideColumnAPI(4); + assertColumnHeaderOrder(1, 2, 3, 5, 6); + + dragAndDropDefaultColumnHeader(4, 3, CellSide.LEFT); + assertColumnHeaderOrder(1, 2, 3, 6, 5); + + dragAndDropDefaultColumnHeader(4, 2, CellSide.RIGHT); + assertColumnHeaderOrder(1, 2, 3, 5, 6); + + toggleHideColumnAPI(0); + assertColumnHeaderOrder(1, 2, 3, 0, 5, 6); + + toggleHideColumnAPI(4); + assertColumnHeaderOrder(1, 2, 3, 0, 4, 5, 6); + } + + @Test + public void testReorderingHiddenColumns_movingHiddenColumn_indexIsUpdated() { + selectMenuPath("Component", "State", "Width", "1000px"); + toggleHideColumnAPI(2); + toggleHideColumnAPI(3); + assertColumnHeaderOrder(0, 1, 4, 5, 6); + + moveColumnLeft(3); + assertColumnHeaderOrder(0, 1, 4, 5, 6); + + toggleHideColumnAPI(3); + assertColumnHeaderOrder(0, 1, 3, 4, 5, 6); + toggleHideColumnAPI(2); + assertColumnHeaderOrder(0, 1, 3, 2, 4, 5, 6); + + toggleHideColumnAPI(2); + toggleHideColumnAPI(3); + assertColumnHeaderOrder(0, 1, 4, 5, 6); + + moveColumnLeft(2); + moveColumnLeft(2); + moveColumnLeft(2); + assertColumnHeaderOrder(0, 1, 4, 5, 6); + + toggleHideColumnAPI(2); + assertColumnHeaderOrder(2, 0, 1, 4, 5, 6); + toggleHideColumnAPI(3); + assertColumnHeaderOrder(2, 0, 1, 3, 4, 5, 6); + } + + // keyboard actions not working in client side test case? + @Test + @Ignore + public void testNavigationWithHiddenColumns_navigatingOverHiddenColumn_goesToNextVisibleColumn() { + selectMenuPath("Component", "State", "Width", "1000px"); + toggleHideColumnAPI(2); + toggleHideColumnAPI(3); + assertColumnHeaderOrder(0, 1, 4, 5, 6); + + getGridElement().getCell(2, 4).click(); + GridCellElement cell = getGridElement().getCell(2, 4); + assertTrue(cell.isFocused()); + + new Actions(getDriver()).sendKeys(Keys.ARROW_LEFT); + cell = getGridElement().getCell(2, 1); + assertTrue(cell.isFocused()); + + new Actions(getDriver()).sendKeys(Keys.ARROW_RIGHT); + cell = getGridElement().getCell(2, 4); + assertTrue(cell.isFocused()); + } + + @Test + public void testNavigationWithHiddenColumns_hiddenFirstAndLastColumn_keepsNavigation() { + selectMenuPath("Component", "State", "Width", "1000px"); + toggleHideColumnAPI(0); + assertColumnHeaderOrder(1, 2, 3, 4, 5, 6); + + getGridElement().getCell(2, 1).click(); + assertTrue(getGridElement().getCell(2, 1).isFocused()); + + new Actions(getDriver()).sendKeys(Keys.ARROW_LEFT); + GridCellElement cell = getGridElement().getCell(2, 1); + assertTrue(cell.isFocused()); + + scrollGridHorizontallyTo(10000); + + // + getGridElement().getHeaderCell(0, 9).click(); + cell = getGridElement().getHeaderCell(0, 9); + assertTrue(cell.isFocused()); + toggleHideColumnAPI(10); + toggleHideColumnAPI(11); + + new Actions(getDriver()).sendKeys(Keys.ARROW_RIGHT); + new Actions(getDriver()).sendKeys(Keys.ARROW_RIGHT); + toggleHideColumnAPI(10); + toggleHideColumnAPI(11); + cell = getGridElement().getHeaderCell(0, 9); + assertTrue(cell.isFocused()); + } + + @Test + public void testFrozenColumnHiding_lastFrozenColumnHidden_isFrozenWhenMadeVisible() { + toggleFrozenColumns(2); + toggleHidableColumnAPI(0); + toggleHidableColumnAPI(1); + getSidebarOpenButton().click(); + verifyColumnIsFrozen(0); + verifyColumnIsFrozen(1); + verifyColumnIsNotFrozen(2); + assertColumnHeaderOrder(0, 1, 2, 3); + + getColumnHidingToggle(1).click(); + verifyColumnIsFrozen(0); + // the grid element indexing doesn't take hidden columns into account! + verifyColumnIsNotFrozen(1); + assertColumnHeaderOrder(0, 2, 3); + + getColumnHidingToggle(0).click(); + verifyColumnIsNotFrozen(0); + assertColumnHeaderOrder(2, 3, 4); + + getColumnHidingToggle(0).click(); + assertColumnHeaderOrder(0, 2, 3); + verifyColumnIsFrozen(0); + verifyColumnIsNotFrozen(1); + + getColumnHidingToggle(1).click(); + assertColumnHeaderOrder(0, 1, 2, 3); + verifyColumnIsFrozen(0); + verifyColumnIsFrozen(1); + verifyColumnIsNotFrozen(2); + } + + @Test + public void testFrozenColumnHiding_columnHiddenFrozenCountChanged_columnIsFrozenWhenVisible() { + toggleHidableColumnAPI(1); + toggleHidableColumnAPI(2); + getSidebarOpenButton().click(); + getColumnHidingToggle(1).click(); + getColumnHidingToggle(2).click(); + assertColumnHeaderOrder(0, 3, 4); + + toggleFrozenColumns(3); + verifyColumnIsFrozen(0); + // the grid element indexing doesn't take hidden columns into account! + verifyColumnIsNotFrozen(1); + verifyColumnIsNotFrozen(2); + + getColumnHidingToggle(2).click(); + verifyColumnIsFrozen(0); + verifyColumnIsFrozen(1); + verifyColumnIsNotFrozen(2); + verifyColumnIsNotFrozen(3); + + getColumnHidingToggle(1).click(); + verifyColumnIsFrozen(0); + verifyColumnIsFrozen(1); + verifyColumnIsFrozen(2); + verifyColumnIsNotFrozen(3); + verifyColumnIsNotFrozen(4); + } + + @Test + public void testSpannedCells_hidingColumnInBeginning_rendersSpannedCellCorrectly() { + loadSpannedCellsFixture(); + verifySpannedCellsFixtureStart(); + + toggleHideColumnAPI(0); + + verifyNumberOfCellsInHeader(0, 7); + verifyNumberOfCellsInHeader(1, 5); + verifyNumberOfCellsInHeader(2, 6); + verifyNumberOfCellsInHeader(3, 1); + verifyHeaderCellContent(1, 0, CAPTION_0_1); + verifyHeaderCellContent(1, 2, CAPTION_3_4_5); + verifyHeaderCellContent(2, 0, CAPTION_1_2); + verifyHeaderCellContent(3, 0, CAPTION_ALL); + verifyHeaderCellColspan(1, 0, 1); + verifyHeaderCellColspan(1, 2, 3); + verifyHeaderCellColspan(2, 1, 2); + + toggleHideColumnAPI(0); + + verifySpannedCellsFixtureStart(); + + toggleHideColumnAPI(1); + + verifyNumberOfCellsInHeader(0, 7); + verifyNumberOfCellsInHeader(1, 5); + verifyNumberOfCellsInHeader(2, 7); + verifyNumberOfCellsInHeader(3, 1); + verifyHeaderCellContent(1, 0, CAPTION_0_1); + verifyHeaderCellContent(1, 2, CAPTION_3_4_5); + verifyHeaderCellContent(2, 1, CAPTION_1_2); + verifyHeaderCellContent(3, 0, CAPTION_ALL); + verifyHeaderCellColspan(1, 0, 1); + verifyHeaderCellColspan(1, 2, 3); + verifyHeaderCellColspan(2, 1, 1); + + toggleHideColumnAPI(3); + + verifyNumberOfCellsInHeader(0, 6); + verifyNumberOfCellsInHeader(1, 5); + verifyNumberOfCellsInHeader(2, 6); + verifyNumberOfCellsInHeader(3, 1); + verifyHeaderCellContent(1, 0, CAPTION_0_1); + verifyHeaderCellContent(1, 2, CAPTION_3_4_5); + verifyHeaderCellContent(2, 1, CAPTION_1_2); + verifyHeaderCellContent(3, 0, CAPTION_ALL); + verifyHeaderCellColspan(1, 0, 1); + verifyHeaderCellColspan(1, 2, 2); + verifyHeaderCellColspan(2, 1, 1); + + toggleHideColumnAPI(1); + + verifyNumberOfCellsInHeader(0, 7); + verifyNumberOfCellsInHeader(1, 5); + verifyNumberOfCellsInHeader(2, 6); + verifyNumberOfCellsInHeader(3, 1); + verifyHeaderCellContent(1, 0, CAPTION_0_1); + verifyHeaderCellContent(1, 3, CAPTION_3_4_5); + verifyHeaderCellContent(2, 1, CAPTION_1_2); + verifyHeaderCellContent(3, 0, CAPTION_ALL); + verifyHeaderCellColspan(1, 0, 2); + verifyHeaderCellColspan(1, 3, 2); + verifyHeaderCellColspan(2, 1, 2); + + toggleHideColumnAPI(3); + + verifySpannedCellsFixtureStart(); + } + + @Test + public void testSpannedCells_hidingColumnInMiddle_rendersSpannedCellCorrectly() { + loadSpannedCellsFixture(); + verifySpannedCellsFixtureStart(); + + toggleHideColumnAPI(4); + + verifyNumberOfCellsInHeader(0, 7); + verifyNumberOfCellsInHeader(1, 5); + verifyNumberOfCellsInHeader(2, 6); + verifyNumberOfCellsInHeader(3, 1); + verifyHeaderCellContent(1, 0, CAPTION_0_1); + verifyHeaderCellContent(1, 3, CAPTION_3_4_5); + verifyHeaderCellContent(2, 1, CAPTION_1_2); + verifyHeaderCellContent(3, 0, CAPTION_ALL); + verifyHeaderCellColspan(1, 0, 2); + verifyHeaderCellColspan(1, 3, 2); + verifyHeaderCellColspan(2, 1, 2); + + toggleHideColumnAPI(4); + + verifySpannedCellsFixtureStart(); + } + + @Test + public void testSpannedCells_hidingColumnInEnd_rendersSpannedCellCorrectly() { + loadSpannedCellsFixture(); + verifySpannedCellsFixtureStart(); + + toggleHideColumnAPI(1); + + verifyNumberOfCellsInHeader(0, 7); + verifyNumberOfCellsInHeader(1, 5); + verifyNumberOfCellsInHeader(2, 7); + verifyNumberOfCellsInHeader(3, 1); + verifyHeaderCellContent(1, 0, CAPTION_0_1); + verifyHeaderCellContent(1, 2, CAPTION_3_4_5); + verifyHeaderCellContent(2, 1, CAPTION_1_2); + verifyHeaderCellContent(3, 1, CAPTION_ALL); + verifyHeaderCellColspan(1, 0, 1); + verifyHeaderCellColspan(1, 2, 3); + verifyHeaderCellColspan(2, 1, 1); + + toggleHideColumnAPI(1); + + verifySpannedCellsFixtureStart(); + + toggleHideColumnAPI(2); + + verifyNumberOfCellsInHeader(0, 7); + verifyNumberOfCellsInHeader(1, 4); + verifyNumberOfCellsInHeader(2, 7); + verifyNumberOfCellsInHeader(3, 1); + verifyHeaderCellContent(1, 0, CAPTION_0_1); + verifyHeaderCellContent(1, 3, CAPTION_3_4_5); + verifyHeaderCellContent(2, 1, CAPTION_1_2); + verifyHeaderCellContent(3, 0, CAPTION_ALL); + verifyHeaderCellColspan(1, 0, 2); + verifyHeaderCellColspan(1, 3, 3); + verifyHeaderCellColspan(2, 1, 1); + + toggleHideColumnAPI(5); + + verifyNumberOfCellsInHeader(0, 6); + verifyNumberOfCellsInHeader(1, 4); + verifyNumberOfCellsInHeader(2, 6); + verifyNumberOfCellsInHeader(3, 1); + verifyHeaderCellContent(1, 0, CAPTION_0_1); + verifyHeaderCellContent(1, 3, CAPTION_3_4_5); + verifyHeaderCellContent(2, 1, CAPTION_1_2); + verifyHeaderCellContent(3, 0, CAPTION_ALL); + verifyHeaderCellColspan(1, 0, 2); + verifyHeaderCellColspan(1, 3, 2); + verifyHeaderCellColspan(2, 1, 1); + + toggleHideColumnAPI(5); + toggleHideColumnAPI(2); + + verifySpannedCellsFixtureStart(); + } + + @Test + public void testSpannedCells_spanningCellOverHiddenColumn_rendersSpannedCellCorrectly() { + selectMenuPath("Component", "State", "Width", "1000px"); + appendHeaderRow(); + toggleHideColumnAPI(4); + toggleHideColumnAPI(8); + toggleHideColumnAPI(9); + toggleHideColumnAPI(10); + toggleHideColumnAPI(11); + assertColumnHeaderOrder(0, 1, 2, 3, 5, 6, 7); + verifyNumberOfCellsInHeader(1, 7); + + mergeHeaderCellsTwoThreeFour(2); + + verifyNumberOfCellsInHeader(1, 6); + verifyHeaderCellContent(1, 3, CAPTION_3_4_5); + verifyHeaderCellColspan(1, 3, 2); + } + + @Test + public void testSpannedCells_spanningCellAllHiddenColumns_rendersSpannedCellCorrectly() { + selectMenuPath("Component", "State", "Width", "1000px"); + appendHeaderRow(); + toggleHideColumnAPI(3); + toggleHideColumnAPI(4); + toggleHideColumnAPI(5); + toggleHideColumnAPI(8); + toggleHideColumnAPI(9); + toggleHideColumnAPI(10); + toggleHideColumnAPI(11); + assertColumnHeaderOrder(0, 1, 2, 6, 7); + verifyNumberOfCellsInHeader(1, 5); + + mergeHeaderCellsTwoThreeFour(2); + + verifyNumberOfCellsInHeader(1, 5); + verifyHeaderCellColspan(1, 0, 1); + verifyHeaderCellColspan(1, 1, 1); + verifyHeaderCellColspan(1, 2, 1); + verifyHeaderCellColspan(1, 3, 1); + verifyHeaderCellColspan(1, 4, 1); + } + + private void loadSpannedCellsFixture() { + selectMenuPath("Component", "State", "Width", "1000px"); + appendHeaderRow(); + appendHeaderRow(); + appendHeaderRow(); + mergeHeaderCellsTwoThreeFour(2); + mergeHeaderCellsZeroOne(2); + mergeHeaderCellsOneTwo(3); + mergeHeaderCellsAll(4); + toggleHideColumnAPI(8); + toggleHideColumnAPI(9); + toggleHideColumnAPI(10); + toggleHideColumnAPI(11); + } + + private void verifySpannedCellsFixtureStart() { + assertColumnHeaderOrder(0, 1, 2, 3, 4, 5, 6, 7); + verifyNumberOfCellsInHeader(0, 8); + verifyNumberOfCellsInHeader(1, 5); + verifyNumberOfCellsInHeader(2, 7); + verifyNumberOfCellsInHeader(3, 1); + verifyHeaderCellContent(1, 0, CAPTION_0_1); + verifyHeaderCellContent(1, 3, CAPTION_3_4_5); + verifyHeaderCellContent(2, 1, CAPTION_1_2); + verifyHeaderCellContent(3, 0, CAPTION_ALL); + verifyHeaderCellColspan(1, 0, 2); + verifyHeaderCellColspan(1, 3, 3); + verifyHeaderCellColspan(2, 1, 2); + } + + private void toggleFrozenColumns(int count) { + selectMenuPath("Component", "State", "Frozen column count", count + + " columns"); + } + + private void verifyHeaderCellColspan(int row, int column, int colspan) { + assertEquals(Integer.valueOf(colspan), Integer.valueOf(Integer + .parseInt(getGridElement().getHeaderCell(row, column) + .getAttribute("colspan")))); + } + + private void verifyNumberOfCellsInHeader(int row, int numberOfCells) { + int size = 0; + for (TestBenchElement cell : getGridElement().getHeaderCells(row)) { + if (cell.isDisplayed()) { + size++; + } + } + assertEquals(numberOfCells, size); + } + + private void verifyHeaderCellContent(int row, int column, String content) { + GridCellElement headerCell = getGridElement() + .getHeaderCell(row, column); + assertEquals(content.toLowerCase(), headerCell.getText().toLowerCase()); + assertTrue(headerCell.isDisplayed()); + } + + private void verifyColumnIsFrozen(int index) { + assertTrue(getGridElement().getHeaderCell(0, index).isFrozen()); + } + + private void verifyColumnIsNotFrozen(int index) { + assertFalse(getGridElement().getHeaderCell(0, index).isFrozen()); + } + + private void verifyColumnHidingTogglesOrder(int... indices) { + WebElement sidebar = getSidebar(); + List<WebElement> elements = sidebar.findElements(By + .className("column-hiding-toggle")); + for (int i = 0; i < indices.length; i++) { + WebElement e = elements.get(i); + assertTrue(("Header (0," + indices[i] + ")").equalsIgnoreCase(e + .getText())); + } + } + + private void verifyColumnHidingOption(int columnIndex, boolean hidden) { + WebElement columnHidingToggle = getColumnHidingToggle(columnIndex); + assertEquals(hidden, + columnHidingToggle.getAttribute("class").contains("hidden")); + } + + private void verifySidebarOpened() { + WebElement sidebar = getSidebar(); + assertTrue(sidebar.getAttribute("class").contains("opened")); + } + + private void verifySidebarClosed() { + WebElement sidebar = getSidebar(); + assertFalse(sidebar.getAttribute("class").contains("opened")); + } + + private void verifySidebarNotVisible() { + WebElement sidebar = getSidebar(); + assertNull(sidebar); + } + + private void verifySidebarVisible() { + WebElement sidebar = getSidebar(); + assertNotNull(sidebar); + } + + @Override + protected WebElement getSidebar() { + List<WebElement> elements = findElements(By.className("v-grid-sidebar")); + return elements.isEmpty() ? null : elements.get(0); + } + + @Override + protected WebElement getSidebarOpenButton() { + List<WebElement> elements = findElements(By + .className("v-grid-sidebar-button")); + return elements.isEmpty() ? null : elements.get(0); + } + + /** + * Returns the toggle inside the sidebar for hiding the column at the given + * index, or null if not found. + */ + @Override + protected WebElement getColumnHidingToggle(int columnIndex) { + WebElement sidebar = getSidebar(); + List<WebElement> elements = sidebar.findElements(By + .className("column-hiding-toggle")); + for (WebElement e : elements) { + if (("Header (0," + columnIndex + ")") + .equalsIgnoreCase(e.getText())) { + return e; + } + } + return null; + } + + private void clickSidebarOpenButton() { + getSidebarOpenButton().click(); + } + + private void moveColumnLeft(int index) { + selectMenuPath("Component", "Columns", "Column " + index, + "Move column left"); + } + + private void toggleHidableColumnAPI(int columnIndex) { + selectMenuPath("Component", "Columns", "Column " + columnIndex, + "Hidable"); + } + + private void toggleHideColumnAPI(int columnIndex) { + selectMenuPath("Component", "Columns", "Column " + columnIndex, + "Hidden"); + } + + private void appendHeaderRow() { + selectMenuPath("Component", "Header", "Append row"); + } + + private void mergeHeaderCellsZeroOne(int row) { + selectMenuPath("Component", "Header", "Row " + row, CAPTION_0_1); + } + + private void mergeHeaderCellsOneTwo(int row) { + selectMenuPath("Component", "Header", "Row " + row, CAPTION_1_2); + } + + private void mergeHeaderCellsTwoThreeFour(int row) { + selectMenuPath("Component", "Header", "Row " + row, CAPTION_3_4_5); + } + + private void mergeHeaderCellsAll(int row) { + selectMenuPath("Component", "Header", "Row " + row, CAPTION_ALL); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderTest.java new file mode 100644 index 0000000000..d779a5c81a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderTest.java @@ -0,0 +1,649 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.elements.GridElement.GridCellElement; +import com.vaadin.testbench.parallel.TestCategory; + +/** + * + * @author Vaadin Ltd + */ +@TestCategory("grid") +public class GridColumnReorderTest extends GridBasicClientFeaturesTest { + + @Before + public void before() { + openTestURL(); + } + + @Test + public void columnReorderEventTriggered() { + final int firstIndex = 3; + final int secondIndex = 4; + final String firstHeaderText = getGridElement().getHeaderCell(0, + firstIndex).getText(); + final String secondHeaderText = getGridElement().getHeaderCell(0, + secondIndex).getText(); + selectMenuPath("Component", "Internals", "Listeners", + "Add ColumnReorder listener"); + selectMenuPath("Component", "Columns", "Column " + secondIndex, + "Move column left"); + // columns 3 and 4 should have swapped to 4 and 3 + GridCellElement headerCell = getGridElement().getHeaderCell(0, + firstIndex); + assertEquals(secondHeaderText, headerCell.getText()); + headerCell = getGridElement().getHeaderCell(0, secondIndex); + assertEquals(firstHeaderText, headerCell.getText()); + + // the reorder event should have typed the order to this label + WebElement columnReorderElement = findElement(By.id("columnreorder")); + int eventIndex = Integer.parseInt(columnReorderElement + .getAttribute("columns")); + assertEquals(1, eventIndex); + + // trigger another event + selectMenuPath("Component", "Columns", "Column " + secondIndex, + "Move column left"); + columnReorderElement = findElement(By.id("columnreorder")); + eventIndex = Integer.parseInt(columnReorderElement + .getAttribute("columns")); + assertEquals(2, eventIndex); + } + + @Test + public void testColumnReorder_onReorder_columnReorderEventTriggered() { + final int firstIndex = 3; + final int secondIndex = 4; + final String firstHeaderText = getGridElement().getHeaderCell(0, + firstIndex).getText(); + final String secondHeaderText = getGridElement().getHeaderCell(0, + secondIndex).getText(); + selectMenuPath("Component", "Internals", "Listeners", + "Add ColumnReorder listener"); + selectMenuPath("Component", "Columns", "Column " + secondIndex, + "Move column left"); + // columns 3 and 4 should have swapped to 4 and 3 + GridCellElement headerCell = getGridElement().getHeaderCell(0, + firstIndex); + assertEquals(secondHeaderText, headerCell.getText()); + headerCell = getGridElement().getHeaderCell(0, secondIndex); + assertEquals(firstHeaderText, headerCell.getText()); + + // the reorder event should have typed the order to this label + WebElement columnReorderElement = findElement(By.id("columnreorder")); + int eventIndex = Integer.parseInt(columnReorderElement + .getAttribute("columns")); + assertEquals(1, eventIndex); + + // trigger another event + selectMenuPath("Component", "Columns", "Column " + secondIndex, + "Move column left"); + columnReorderElement = findElement(By.id("columnreorder")); + eventIndex = Integer.parseInt(columnReorderElement + .getAttribute("columns")); + assertEquals(2, eventIndex); + } + + @Test + public void testColumnReorder_draggingSortedColumn_sortIndicatorShownOnDraggedElement() { + // given + toggleColumnReorder(); + toggleSortableColumn(0); + sortColumn(0); + + // when + startDragButDontDropOnDefaultColumnHeader(0); + + // then + WebElement draggedElement = getDraggedHeaderElement(); + assertTrue(draggedElement.getAttribute("class").contains("sort")); + } + + @Test + public void testColumnReorder_draggingSortedColumn_sortStays() { + // given + toggleColumnReorder(); + toggleSortableColumn(0); + sortColumn(0); + + // when + dragAndDropDefaultColumnHeader(0, 2, CellSide.LEFT); + + // then + assertColumnIsSorted(1); + } + + @Test + public void testColumnReorder_draggingFocusedHeader_focusShownOnDraggedElement() { + // given + toggleColumnReorder(); + focusDefaultHeader(0); + + // when + startDragButDontDropOnDefaultColumnHeader(0); + + // then + WebElement draggedElement = getDraggedHeaderElement(); + assertTrue(draggedElement.getAttribute("class").contains("focused")); + } + + @Test + public void testColumnReorder_draggingFocusedHeader_focusIsKeptOnHeader() { + // given + toggleColumnReorder(); + focusDefaultHeader(0); + + // when + dragAndDropDefaultColumnHeader(0, 3, CellSide.LEFT); + + // then + WebElement defaultColumnHeader = getDefaultColumnHeader(2); + String attribute = defaultColumnHeader.getAttribute("class"); + assertTrue(attribute.contains("focused")); + } + + @Test + public void testColumnReorder_draggingFocusedCellColumn_focusIsKeptOnCell() { + // given + toggleColumnReorder(); + focusCell(2, 2); + + // when + dragAndDropDefaultColumnHeader(2, 0, CellSide.LEFT); + + // then + assertFocusedCell(2, 0); + } + + @Test + public void testColumnReorderWithHiddenColumn_draggingFocusedCellColumnOverHiddenColumn_focusIsKeptOnCell() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Columns", "Column 1", "Hidden"); + focusCell(2, 2); + assertFocusedCell(2, 2); + + // when + dragAndDropDefaultColumnHeader(1, 0, CellSide.LEFT); + + // then + assertFocusedCell(2, 2); + + // when + dragAndDropDefaultColumnHeader(0, 2, CellSide.LEFT); + + // then + assertFocusedCell(2, 2); + } + + @Test + public void testColumnReorder_dragColumnFromRightToLeftOfFocusedCellColumn_focusIsKept() { + // given + toggleColumnReorder(); + focusCell(1, 3); + + // when + dragAndDropDefaultColumnHeader(4, 1, CellSide.LEFT); + + // then + assertFocusedCell(1, 4); + } + + @Test + public void testColumnReorder_dragColumnFromLeftToRightOfFocusedCellColumn_focusIsKept() { + // given + toggleColumnReorder(); + focusCell(4, 2); + + // when + dragAndDropDefaultColumnHeader(0, 4, CellSide.LEFT); + + // then + assertFocusedCell(4, 1); + } + + @Test + public void testColumnReorder_draggingHeaderRowThatHasColumnHeadersSpanned_cantDropInsideSpannedHeaderFromOutside() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + int horizontalOffset = (getGridElement().getHeaderCell(1, 1).getSize() + .getWidth() / 2) - 10; + dragAndDropColumnHeader(1, 3, 1, horizontalOffset); + + // then + assertColumnHeaderOrder(0, 3, 1, 2, 4); + } + + @Test + public void testColumnReorder_anotherRowHasColumnHeadersSpanned_cantDropInsideSpannedHeaderFromOutside() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + int horizontalOffset = (getGridElement().getHeaderCell(1, 1).getSize() + .getWidth() / 2) + 10; + dragAndDropColumnHeader(0, 0, 2, horizontalOffset); + + // then + assertColumnHeaderOrder(1, 2, 0, 3, 4); + } + + @Test + public void testColumnReorder_cellInsideSpannedHeader_cantBeDroppedOutsideSpannedArea() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + dragAndDropColumnHeader(0, 2, 0, CellSide.LEFT); + + // then + assertColumnHeaderOrder(0, 2, 1, 3, 4); + } + + @Test + public void testColumnReorder_cellInsideTwoCrossingSpanningHeaders_cantTouchThis() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join column cells 0, 1"); + selectMenuPath("Component", "Header", "Row 3", "Join columns 1, 2"); + dragAndDropColumnHeader(0, 3, 0, CellSide.LEFT); + assertColumnHeaderOrder(3, 0, 1, 2, 4); + + // when + dragAndDropColumnHeader(0, 2, 0, CellSide.LEFT); + + // then + assertColumnHeaderOrder(3, 0, 1, 2, 4); + } + + @Test + public void testColumnReorder_cellsInsideSpannedHeaderAndBlockedByOtherSpannedCells_cantTouchThose() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join column cells 0, 1"); + selectMenuPath("Component", "Header", "Row 3", "Join columns 1, 2"); + dragAndDropColumnHeader(0, 3, 0, CellSide.LEFT); + assertColumnHeaderOrder(3, 0, 1, 2, 4); + + // when then + dragAndDropColumnHeader(0, 1, 3, CellSide.LEFT); + assertColumnHeaderOrder(3, 0, 1, 2, 4); + + dragAndDropColumnHeader(1, 2, 1, CellSide.LEFT); + assertColumnHeaderOrder(3, 0, 1, 2, 4); + + dragAndDropColumnHeader(2, 1, 2, CellSide.RIGHT); + assertColumnHeaderOrder(3, 0, 1, 2, 4); + } + + @Test + public void testColumnReorder_cellsInsideSpannedHeaderAndBlockedByOtherSpannedCells_reorderingLimited() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "State", "Width", "750px"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 3, 4, 5"); + dragAndDropColumnHeader(0, 0, 4, CellSide.RIGHT); + selectMenuPath("Component", "Header", "Row 3", "Join columns 1, 2"); + scrollGridHorizontallyTo(0); + assertColumnHeaderOrder(1, 2, 3, 4, 5); + + // when then + dragAndDropColumnHeader(0, 1, 4, CellSide.LEFT); + scrollGridHorizontallyTo(0); + assertColumnHeaderOrder(1, 2, 3, 4, 5); + + dragAndDropColumnHeader(0, 2, 4, CellSide.LEFT); + scrollGridHorizontallyTo(0); + assertColumnHeaderOrder(1, 2, 3, 4, 5); + + dragAndDropColumnHeader(0, 3, 4, CellSide.RIGHT); + scrollGridHorizontallyTo(0); + assertColumnHeaderOrder(1, 2, 3, 5, 4); + + dragAndDropColumnHeader(0, 4, 2, CellSide.RIGHT); + scrollGridHorizontallyTo(0); + assertColumnHeaderOrder(1, 2, 3, 4, 5); + + dragAndDropColumnHeader(2, 3, 4, CellSide.RIGHT); + scrollGridHorizontallyTo(0); + assertColumnHeaderOrder(1, 2, 3, 5, 4); + + dragAndDropColumnHeader(2, 4, 2, CellSide.RIGHT); + scrollGridHorizontallyTo(0); + assertColumnHeaderOrder(1, 2, 3, 4, 5); + } + + @Test + public void testColumnReorder_cellsInsideTwoAdjacentSpannedHeaders_reorderingLimited() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "State", "Width", "750px"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 3, 4, 5"); + dragAndDropColumnHeader(0, 0, 4, CellSide.RIGHT); + scrollGridHorizontallyTo(0); + dragAndDropColumnHeader(0, 1, 4, CellSide.RIGHT); + scrollGridHorizontallyTo(0); + selectMenuPath("Component", "Header", "Row 3", "Join columns 1, 2"); + assertColumnHeaderOrder(1, 3, 4, 5, 2); + + // when then + dragAndDropColumnHeader(0, 1, 4, CellSide.LEFT); + assertColumnHeaderOrder(1, 4, 3, 5, 2); + + dragAndDropColumnHeader(0, 2, 4, CellSide.LEFT); + assertColumnHeaderOrder(1, 4, 3, 5, 2); + + dragAndDropColumnHeader(0, 2, 0, CellSide.LEFT); + assertColumnHeaderOrder(1, 3, 4, 5, 2); + } + + @Test + public void testColumnReorder_footerHasSpannedCells_cantDropInside() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Footer", "Append row"); + selectMenuPath("Component", "Footer", "Row 1", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + dragAndDropColumnHeader(0, 3, 1, CellSide.RIGHT); + + // then + assertColumnHeaderOrder(0, 3, 1, 2, 4); + } + + @Test + public void testColumnReorder_cellInsideASpannedFooter_cantBeDroppedOutsideSpannedArea() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Footer", "Append row"); + selectMenuPath("Component", "Footer", "Row 1", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + dragAndDropColumnHeader(0, 2, 0, CellSide.LEFT); + + // then + assertColumnHeaderOrder(0, 2, 1, 3, 4); + } + + @Test + public void testColumnReorder_cellInsideTwoCrossingSpanningFooters_cantTouchThis() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Footer", "Append row"); + selectMenuPath("Component", "Footer", "Append row"); + selectMenuPath("Component", "Footer", "Row 1", "Join column cells 0, 1"); + selectMenuPath("Component", "Footer", "Row 2", "Join columns 1, 2"); + dragAndDropColumnHeader(0, 3, 0, CellSide.LEFT); + assertColumnHeaderOrder(3, 0, 1, 2, 4); + + // when + dragAndDropColumnHeader(0, 2, 0, CellSide.LEFT); + + // then + assertColumnHeaderOrder(3, 0, 1, 2, 4); + } + + @Test + public void testColumnReorder_cellsInsideTwoAdjacentSpannedHeaderAndFooter_reorderingLimited() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "State", "Width", "750px"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Footer", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 3, 4, 5"); + dragAndDropColumnHeader(0, 0, 5, CellSide.LEFT); + scrollGridHorizontallyTo(0); + dragAndDropColumnHeader(0, 1, 5, CellSide.LEFT); + scrollGridHorizontallyTo(0); + selectMenuPath("Component", "Footer", "Row 1", "Join columns 1, 2"); + assertColumnHeaderOrder(1, 3, 4, 5, 2); + + // when then + dragAndDropColumnHeader(0, 1, 3, CellSide.RIGHT); + assertColumnHeaderOrder(1, 4, 3, 5, 2); + + dragAndDropColumnHeader(0, 2, 4, CellSide.RIGHT); + assertColumnHeaderOrder(1, 4, 3, 5, 2); + + dragAndDropColumnHeader(0, 2, 0, CellSide.RIGHT); + assertColumnHeaderOrder(1, 3, 4, 5, 2); + } + + @Test + public void testColumnReorder_draggingASpannedCell_dragWorksNormally() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + dragAndDropColumnHeader(1, 1, 4, CellSide.LEFT); + scrollGridHorizontallyTo(0); + + // then + assertColumnHeaderOrder(0, 3, 1, 2, 4); + } + + @Test + public void testColumnReorder_twoEqualSpannedCells_bothCanBeDragged() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 3", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + dragAndDropColumnHeader(1, 1, 4, CellSide.LEFT); + scrollGridHorizontallyTo(0); + + // then + assertColumnHeaderOrder(0, 3, 1, 2, 4); + + // when + dragAndDropColumnHeader(2, 3, 0, CellSide.LEFT); + + // then + assertColumnHeaderOrder(1, 2, 0, 3, 4); + } + + @Test + public void testColumReorder_twoCrossingSpanningHeaders_neitherCanBeDragged() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 3", "Join column cells 0, 1"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + dragAndDropColumnHeader(1, 1, 4, CellSide.LEFT); + + // then + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + dragAndDropColumnHeader(2, 0, 3, CellSide.RIGHT); + + // then + assertColumnHeaderOrder(0, 1, 2, 3, 4); + } + + @Test + public void testColumnReorder_spannedCellHasAnotherSpannedCellInside_canBeDraggedNormally() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "State", "Width", "750px"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 3, 4, 5"); + dragAndDropColumnHeader(1, 3, 1, CellSide.LEFT); + scrollGridHorizontallyTo(0); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 3", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 3, 4, 5, 1); + + // when + dragAndDropColumnHeader(1, 1, 0, CellSide.LEFT); + + // then + assertColumnHeaderOrder(3, 4, 5, 0, 1); + } + + @Test + public void testColumnReorder_spannedCellInsideAnotherSpanned_canBeDraggedWithBoundaries() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "State", "Width", "750px"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 3, 4, 5"); + dragAndDropColumnHeader(1, 3, 1, CellSide.LEFT); + scrollGridHorizontallyTo(0); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 3", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 3, 4, 5, 1); + + // when + dragAndDropColumnHeader(2, 1, 3, CellSide.RIGHT); + scrollGridHorizontallyTo(0); + + // then + assertColumnHeaderOrder(0, 5, 3, 4, 1); + + // when + dragAndDropColumnHeader(2, 2, 0, CellSide.LEFT); + scrollGridHorizontallyTo(0); + + // then + assertColumnHeaderOrder(0, 3, 4, 5, 1); + } + + @Test + public void testColumnReorder_cellInsideAndNextToSpannedCells_canBeDraggedWithBoundaries() { + // given + toggleColumnReorder(); + selectMenuPath("Component", "State", "Width", "750px"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 3, 4, 5"); + dragAndDropColumnHeader(1, 3, 1, CellSide.LEFT); + scrollGridHorizontallyTo(0); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 3", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 3, 4, 5, 1); + + // when + dragAndDropColumnHeader(2, 3, 0, CellSide.LEFT); + scrollGridHorizontallyTo(0); + + // then + assertColumnHeaderOrder(0, 5, 3, 4, 1); + + // when + dragAndDropColumnHeader(2, 1, 4, CellSide.LEFT); + scrollGridHorizontallyTo(0); + + // then + assertColumnHeaderOrder(0, 3, 4, 5, 1); + } + + @Test + public void testColumnReorder_multipleSpannedCells_dragWorksNormally() { + toggleColumnReorder(); + selectMenuPath("Component", "State", "Width", "750px"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 2", "Join columns 3, 4, 5"); + selectMenuPath("Component", "Header", "Append row"); + selectMenuPath("Component", "Header", "Row 3", "Join columns 1, 2"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + dragAndDropColumnHeader(1, 3, 1, CellSide.RIGHT); + scrollGridHorizontallyTo(0); + + // then + assertColumnHeaderOrder(0, 3, 4, 5, 1); + + // when + scrollGridHorizontallyTo(100); + dragAndDropColumnHeader(2, 4, 2, CellSide.LEFT); + scrollGridHorizontallyTo(0); + + // then + assertColumnHeaderOrder(0, 1, 2, 3, 4); + + // when + dragAndDropColumnHeader(0, 0, 3, CellSide.LEFT); + scrollGridHorizontallyTo(0); + + // then + assertColumnHeaderOrder(1, 2, 0, 3, 4); + } + + private void toggleSortableColumn(int index) { + selectMenuPath("Component", "Columns", "Column " + index, "Sortable"); + } + + private void startDragButDontDropOnDefaultColumnHeader(int index) { + new Actions(getDriver()) + .clickAndHold(getGridHeaderRowCells().get(index)) + .moveByOffset(100, 0).perform(); + } + + private void sortColumn(int index) { + getGridHeaderRowCells().get(index).click(); + } + + private void focusDefaultHeader(int index) { + getGridHeaderRowCells().get(index).click(); + } + + private WebElement getDraggedHeaderElement() { + return findElement(By.className("dragged-column-header")); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSidebarFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSidebarFeatures.java new file mode 100644 index 0000000000..9494988cf4 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridSidebarFeatures.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures; + +public class GridSidebarFeatures extends GridBasicFeatures { + + @Override + protected boolean isColumnHidableByDefault(int col) { + return true; + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java new file mode 100644 index 0000000000..88158c7f6f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java @@ -0,0 +1,241 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures.client; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; + +import com.vaadin.shared.ui.grid.Range; +import com.vaadin.shared.ui.grid.ScrollDestination; +import com.vaadin.testbench.By; +import com.vaadin.testbench.ElementQuery; +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.NotificationElement; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; + +public class GridDetailsClientTest extends GridBasicClientFeaturesTest { + + private static final String[] SET_GENERATOR = new String[] { "Component", + "Row details", "Set generator" }; + private static final String[] SET_FAULTY_GENERATOR = new String[] { + "Component", "Row details", "Set faulty generator" }; + private static final String[] SET_EMPTY_GENERATOR = new String[] { + "Component", "Row details", "Set empty generator" }; + + @Before + public void setUp() { + setDebug(true); + openTestURL(); + } + + @Test(expected = NoSuchElementException.class) + public void noDetailsByDefault() { + assertNull("details for row 1 should not exist at the start", + getGridElement().getDetails(1)); + } + + @Test + public void nullRendererShowsDetailsPlaceholder() { + toggleDetailsFor(1); + TestBenchElement details = getGridElement().getDetails(1); + assertNotNull("details for row 1 should not exist at the start", + details); + assertTrue("details should've been empty for null renderer", details + .getText().isEmpty()); + } + + @Test + public void applyRendererThenOpenDetails() { + selectMenuPath(SET_GENERATOR); + toggleDetailsFor(1); + + TestBenchElement details = getGridElement().getDetails(1); + assertTrue("Unexpected details content", + details.getText().startsWith("Row: 1.")); + } + + @Test + public void openDetailsThenAppyRenderer() { + toggleDetailsFor(1); + selectMenuPath(SET_GENERATOR); + + TestBenchElement details = getGridElement().getDetails(1); + assertTrue("Unexpected details content", + details.getText().startsWith("Row: 1.")); + } + + @Test + public void openHiddenDetailsThenScrollToIt() { + try { + getGridElement().getDetails(100); + fail("details row for 100 was apparently found, while it shouldn't have been."); + } catch (NoSuchElementException e) { + // expected + } + + selectMenuPath(SET_GENERATOR); + toggleDetailsFor(100); + + // scroll a bit beyond so we see below. + getGridElement().scrollToRow(101); + + TestBenchElement details = getGridElement().getDetails(100); + assertTrue("Unexpected details content", + details.getText().startsWith("Row: 100.")); + } + + @Test + public void errorUpdaterShowsErrorNotification() { + assertFalse("No notifications should've been at the start", + $(NotificationElement.class).exists()); + + toggleDetailsFor(1); + selectMenuPath(SET_FAULTY_GENERATOR); + + ElementQuery<NotificationElement> notification = $(NotificationElement.class); + assertTrue("Was expecting an error notification here", + notification.exists()); + notification.first().close(); + + assertEquals("The error details element should be empty", "", + getGridElement().getDetails(1).getText()); + } + + @Test + public void updaterStillWorksAfterError() { + toggleDetailsFor(1); + + selectMenuPath(SET_FAULTY_GENERATOR); + $(NotificationElement.class).first().close(); + selectMenuPath(SET_GENERATOR); + + assertNotEquals( + "New details should've been generated even after error", "", + getGridElement().getDetails(1).getText()); + } + + @Test + public void updaterRendersExpectedWidgets() { + selectMenuPath(SET_GENERATOR); + toggleDetailsFor(1); + + TestBenchElement detailsElement = getGridElement().getDetails(1); + assertNotNull(detailsElement.findElement(By.className("gwt-Label"))); + assertNotNull(detailsElement.findElement(By.className("gwt-Button"))); + } + + @Test + public void widgetsInUpdaterWorkAsExpected() { + selectMenuPath(SET_GENERATOR); + toggleDetailsFor(1); + + TestBenchElement detailsElement = getGridElement().getDetails(1); + WebElement button = detailsElement.findElement(By + .className("gwt-Button")); + button.click(); + + WebElement label = detailsElement + .findElement(By.className("gwt-Label")); + assertEquals("clicked", label.getText()); + } + + @Test + public void emptyGenerator() { + selectMenuPath(SET_EMPTY_GENERATOR); + toggleDetailsFor(1); + + assertEquals("empty generator did not produce an empty details row", + "", getGridElement().getDetails(1).getText()); + } + + @Test(expected = NoSuchElementException.class) + public void removeDetailsRow() { + selectMenuPath(SET_GENERATOR); + toggleDetailsFor(1); + toggleDetailsFor(1); + + getGridElement().getDetails(1); + } + + @Test + public void rowElementClassNames() { + toggleDetailsFor(0); + toggleDetailsFor(1); + + List<WebElement> elements = getGridElement().findElements( + By.className("v-grid-spacer")); + assertEquals("v-grid-spacer", elements.get(0).getAttribute("class")); + assertEquals("v-grid-spacer stripe", + elements.get(1).getAttribute("class")); + } + + @Test + public void scrollDownToRowWithDetails() { + toggleDetailsFor(100); + scrollToRow(100, ScrollDestination.ANY); + + Range validScrollRange = Range.between(1700, 1715); + assertTrue(validScrollRange.contains(getGridVerticalScrollPos())); + } + + @Test + public void scrollUpToRowWithDetails() { + toggleDetailsFor(100); + scrollGridVerticallyTo(999999); + scrollToRow(100, ScrollDestination.ANY); + + Range validScrollRange = Range.between(1990, 2010); + assertTrue(validScrollRange.contains(getGridVerticalScrollPos())); + } + + @Test + public void cannotScrollBeforeTop() { + toggleDetailsFor(1); + scrollToRow(0, ScrollDestination.END); + assertEquals(0, getGridVerticalScrollPos()); + } + + @Test + public void cannotScrollAfterBottom() { + toggleDetailsFor(999); + scrollToRow(999, ScrollDestination.START); + + Range expectedRange = Range.withLength(19680, 20); + assertTrue(expectedRange.contains(getGridVerticalScrollPos())); + } + + private void scrollToRow(int rowIndex, ScrollDestination destination) { + selectMenuPath(new String[] { "Component", "State", "Scroll to...", + "Row " + rowIndex + "...", "Destination " + destination }); + } + + private void toggleDetailsFor(int rowIndex) { + selectMenuPath(new String[] { "Component", "Row details", + "Toggle details for...", "Row " + rowIndex }); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridSidebarContentTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridSidebarContentTest.java new file mode 100644 index 0000000000..c5092a9c22 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridSidebarContentTest.java @@ -0,0 +1,156 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures.client; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; +import com.vaadin.tests.components.grid.basicfeatures.element.CustomGridElement; + +public class GridSidebarContentTest extends GridBasicClientFeaturesTest { + + @Test + public void testSidebarWithHidableColumn() { + openTestURL(); + CustomGridElement gridElement = getGridElement(); + + Assert.assertEquals("Sidebar should not be initially present", 0, + countBySelector(".v-grid-sidebar")); + + selectMenuPath("Component", "Columns", "Column 0", "Hidable"); + + gridElement.findElement(By.className("v-grid-sidebar-button")).click(); + + WebElement toggle = gridElement.findElement(By + .className("column-hiding-toggle")); + + Assert.assertEquals("Column 0 should be togglable", "Header (0,0)", + toggle.getText()); + + selectMenuPath("Component", "Columns", "Column 0", "Hidable"); + Assert.assertEquals("Sidebar should disappear without toggable column", + 0, countBySelector(".v-grid-sidebar")); + + } + + @Test + public void testAddingCustomSidebarItem() { + openTestURL(); + CustomGridElement gridElement = getGridElement(); + + selectMenuPath("Component", "Sidebar", "Add item to end"); + + gridElement.findElement(By.className("v-grid-sidebar-button")).click(); + + WebElement sidebarItem = gridElement.findElement(By + .cssSelector(".v-grid-sidebar-content .gwt-MenuItem")); + + sidebarItem.click(); + + Assert.assertEquals("Sidebar should be closed after clicking item 0", + 0, countBySelector(".v-grid-sidebar-content")); + } + + @Test + public void testProgrammaticSidebarToggle() { + openTestURL(); + + selectMenuPath("Component", "Columns", "Column 0", "Hidable"); + + selectMenuPath("Component", "Sidebar", "Toggle sidebar visibility"); + + Assert.assertEquals("Sidebar be open", 1, + countBySelector(".v-grid-sidebar-content")); + + selectMenuPath("Component", "Sidebar", "Toggle sidebar visibility"); + + Assert.assertEquals("Sidebar be closed", 0, + countBySelector(".v-grid-sidebar-content")); + } + + @Test + public void testBasicSidebarOrder() { + openTestURL(); + CustomGridElement gridElement = getGridElement(); + + // First add custom content + selectMenuPath("Component", "Sidebar", "Add separator to end"); + selectMenuPath("Component", "Sidebar", "Add item to end"); + + // Then make one column togglable + selectMenuPath("Component", "Columns", "Column 0", "Hidable"); + + selectMenuPath("Component", "Sidebar", "Toggle sidebar visibility"); + + assertSidebarMenuItems("Header (0,0)", null, "Custom menu item 0"); + } + + @Test + public void testSidebarOrderAbuse() { + openTestURL(); + CustomGridElement gridElement = getGridElement(); + + selectMenuPath("Component", "Columns", "Column 0", "Hidable"); + selectMenuPath("Component", "Columns", "Column 1", "Hidable"); + + // Inserts a menu item between the two visibility toggles + selectMenuPath("Component", "Sidebar", "Add item before index 1"); + + selectMenuPath("Component", "Sidebar", "Toggle sidebar visibility"); + + // Total order enforcement not implemented at this point. Test can be + // updated when it is. + assertSidebarMenuItems("Header (0,0)", "Custom menu item 0", + "Header (0,1)"); + + selectMenuPath("Component", "Columns", "Column 2", "Hidable"); + + // Adding a new togglable column should have restored the expected order + assertSidebarMenuItems("Header (0,0)", "Header (0,1)", "Header (0,2)", + "Custom menu item 0"); + } + + private void assertSidebarMenuItems(String... items) { + List<WebElement> menuItems = getGridElement().findElements( + By.cssSelector(".v-grid-sidebar-content td")); + + Assert.assertEquals("Expected " + items.length + " menu items", + items.length, menuItems.size()); + + for (int i = 0; i < items.length; i++) { + String expectedItem = items[i]; + if (expectedItem == null) { + Assert.assertEquals("Item " + i + " should be a separator", + "gwt-MenuItemSeparator", + menuItems.get(i).getAttribute("class")); + } else { + Assert.assertEquals("Unexpected content for item " + i, + expectedItem, menuItems.get(i).getText()); + } + } + } + + private int countBySelector(String cssSelector) { + return getGridElement().findElements(By.cssSelector(cssSelector)) + .size(); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/element/CustomGridElement.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/element/CustomGridElement.java new file mode 100644 index 0000000000..e1934d4f2b --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/element/CustomGridElement.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures.element; + +import org.openqa.selenium.NoSuchElementException; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.elementsbase.ServerClass; + +@ServerClass("com.vaadin.ui.Grid") +public class CustomGridElement extends GridElement { + /** + * Gets the element that contains the details of a row. + * + * @since + * @param rowIndex + * the index of the row for the details + * @return the element that contains the details of a row. <code>null</code> + * if no widget is defined for the detials row + * @throws NoSuchElementException + * if the given details row is currently not open + */ + public TestBenchElement getDetails(int rowIndex) + throws NoSuchElementException { + return getSubPart("#details[" + rowIndex + "]"); + } + + private TestBenchElement getSubPart(String subPartSelector) { + return (TestBenchElement) findElement(By.vaadin(subPartSelector)); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/escalator/EscalatorBasicsTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/escalator/EscalatorBasicsTest.java index 4742236ac6..1d26477d34 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/escalator/EscalatorBasicsTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/escalator/EscalatorBasicsTest.java @@ -66,10 +66,8 @@ public class EscalatorBasicsTest extends EscalatorBasicClientFeaturesTest { selectMenuPath(GENERAL, DETACH_ESCALATOR); selectMenuPath(GENERAL, ATTACH_ESCALATOR); - assertEquals("Vertical scroll position", "50", getVerticalScrollbar() - .getAttribute("scrollTop")); - assertEquals("Horizontal scroll position", "50", - getHorizontalScrollbar().getAttribute("scrollLeft")); + assertEquals("Vertical scroll position", 50, getScrollTop()); + assertEquals("Horizontal scroll position", 50, getScrollLeft()); assertEquals("First cell of first visible row", "Row 2: 0,2", getBodyCell(0, 0).getText()); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/escalator/EscalatorSpacerTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/escalator/EscalatorSpacerTest.java new file mode 100644 index 0000000000..66c131255f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/escalator/EscalatorSpacerTest.java @@ -0,0 +1,583 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures.escalator; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Before; +import org.junit.ComparisonFailure; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; + +import com.vaadin.client.WidgetUtil; +import com.vaadin.shared.ui.grid.Range; +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.NotificationElement; +import com.vaadin.testbench.parallel.BrowserUtil; +import com.vaadin.tests.components.grid.basicfeatures.EscalatorBasicClientFeaturesTest; + +@SuppressWarnings("boxing") +public class EscalatorSpacerTest extends EscalatorBasicClientFeaturesTest { + + //@formatter:off + // separate strings made so that eclipse can show the concatenated string by hovering the mouse over the constant + + // translate3d(0px, 40px, 123px); + // translate3d(24px, 15.251px, 0); + // translate(0, 40px); + private final static String TRANSLATE_VALUE_REGEX = + "translate(?:3d|)" // "translate" or "translate3d" + + "\\(" // literal "(" + + "(" // start capturing the x argument + + "[0-9]+" // the integer part of the value + + "(?:" // start of the subpixel part of the value + + "\\.[0-9]" // if we have a period, there must be at least one number after it + + "[0-9]*" // any amount of accuracy afterwards is fine + + ")?" // the subpixel part is optional + + ")" + + "(?:px)?" // we don't care if the values are suffixed by "px" or not. + + ", " + + "(" // start capturing the y argument + + "[0-9]+" // the integer part of the value + + "(?:" // start of the subpixel part of the value + + "\\.[0-9]" // if we have a period, there must be at least one number after it + + "[0-9]*" // any amount of accuracy afterwards is fine + + ")?" // the subpixel part is optional + + ")" + + "(?:px)?" // we don't care if the values are suffixed by "px" or not. + + "(?:, .*?)?" // the possible z argument, uninteresting (translate doesn't have one, translate3d does) + + "\\)" // literal ")" + + ";?"; // optional ending semicolon + + // 40px; + // 12.34px + private final static String PIXEL_VALUE_REGEX = + "(" // capture the pixel value + + "[0-9]+" // the pixel argument + + "(?:" // start of the subpixel part of the value + + "\\.[0-9]" // if we have a period, there must be at least one number after it + + "[0-9]*" // any amount of accuracy afterwards is fine + + ")?" // the subpixel part is optional + + ")" + + "(?:px)?" // optional "px" string + + ";?"; // optional semicolon + //@formatter:on + + // also matches "-webkit-transform"; + private final static Pattern TRANSFORM_CSS_PATTERN = Pattern + .compile("transform: (.*?);"); + private final static Pattern TOP_CSS_PATTERN = Pattern.compile( + "top: ([0-9]+(?:\\.[0-9]+)?(?:px)?);?", Pattern.CASE_INSENSITIVE); + private final static Pattern LEFT_CSS_PATTERN = Pattern.compile( + "left: ([0-9]+(?:\\.[0-9]+)?(?:px)?);?", Pattern.CASE_INSENSITIVE); + + private final static Pattern TRANSLATE_VALUE_PATTERN = Pattern + .compile(TRANSLATE_VALUE_REGEX); + private final static Pattern PIXEL_VALUE_PATTERN = Pattern.compile( + PIXEL_VALUE_REGEX, Pattern.CASE_INSENSITIVE); + + @Before + public void before() { + setDebug(true); + openTestURL(); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, "Set 20px default height"); + populate(); + } + + @Test + public void openVisibleSpacer() { + assertFalse("No spacers should be shown at the start", + spacersAreFoundInDom()); + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + assertNotNull("Spacer should be shown after setting it", getSpacer(1)); + } + + @Test + public void closeVisibleSpacer() { + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + selectMenuPath(FEATURES, SPACERS, ROW_1, REMOVE); + assertNull("Spacer should not exist after removing it", getSpacer(1)); + } + + @Test + public void spacerPushesVisibleRowsDown() { + double oldTop = getElementTop(getBodyRow(2)); + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + double newTop = getElementTop(getBodyRow(2)); + + assertGreater("Row below a spacer was not pushed down", newTop, oldTop); + } + + @Test + public void addingRowAboveSpacerPushesItDown() { + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, REMOVE_ALL_ROWS); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING); + + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + double oldTop = getElementTop(getSpacer(1)); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING); + double newTop = getElementTop(getSpacer(2)); + + assertGreater("Spacer should've been pushed down (oldTop: " + oldTop + + ", newTop: " + newTop + ")", newTop, oldTop); + } + + @Test + public void addingRowBelowSpacerDoesNotPushItDown() { + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, REMOVE_ALL_ROWS); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING); + + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + double oldTop = getElementTop(getSpacer(1)); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_END); + double newTop = getElementTop(getSpacer(1)); + + assertEquals("Spacer should've not been pushed down", newTop, oldTop, + WidgetUtil.PIXEL_EPSILON); + } + + @Test + public void addingRowBelowSpacerIsActuallyRenderedBelowWhenEscalatorIsEmpty() { + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, REMOVE_ALL_ROWS); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING); + + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + double spacerTop = getElementTop(getSpacer(1)); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_END); + double rowTop = getElementTop(getBodyRow(2)); + + assertEquals("Next row should've been rendered below the spacer", + spacerTop + 100, rowTop, WidgetUtil.PIXEL_EPSILON); + } + + @Test + public void addSpacerAtBottomThenScrollThere() { + selectMenuPath(FEATURES, SPACERS, ROW_99, SET_100PX); + scrollVerticallyTo(999999); + + assertFalse("Did not expect a notification", + $(NotificationElement.class).exists()); + } + + @Test + public void scrollToBottomThenAddSpacerThere() { + scrollVerticallyTo(999999); + long oldBottomScrollTop = getScrollTop(); + selectMenuPath(FEATURES, SPACERS, ROW_99, SET_100PX); + + assertEquals("Adding a spacer underneath the current viewport should " + + "not scroll anywhere", oldBottomScrollTop, getScrollTop()); + assertFalse("Got an unexpected notification", + $(NotificationElement.class).exists()); + + scrollVerticallyTo(999999); + + assertFalse("Got an unexpected notification", + $(NotificationElement.class).exists()); + assertGreater("Adding a spacer should've made the scrollbar scroll " + + "further", getScrollTop(), oldBottomScrollTop); + } + + @Test + public void removingRowAboveSpacerMovesSpacerUp() { + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + WebElement spacer = getSpacer(1); + double originalElementTop = getElementTop(spacer); + + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, + REMOVE_ONE_ROW_FROM_BEGINNING); + assertLessThan("spacer should've moved up", getElementTop(spacer), + originalElementTop); + assertNull("No spacer for row 1 should be found after removing the " + + "top row", getSpacer(1)); + } + + @Test + public void removingSpacedRowRemovesSpacer() { + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + assertTrue("Spacer should've been found in the DOM", + spacersAreFoundInDom()); + + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, + REMOVE_ONE_ROW_FROM_BEGINNING); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, + REMOVE_ONE_ROW_FROM_BEGINNING); + + assertFalse("No spacers should be in the DOM after removing " + + "associated spacer", spacersAreFoundInDom()); + + } + + @Test + public void spacersAreFixedInViewport_firstFreezeThenScroll() { + selectMenuPath(FEATURES, FROZEN_COLUMNS, FREEZE_1_COLUMN); + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + assertEquals("Spacer's left position should've been 0 at the " + + "beginning", 0d, getElementLeft(getSpacer(1)), + WidgetUtil.PIXEL_EPSILON); + + int scrollTo = 10; + scrollHorizontallyTo(scrollTo); + assertEquals("Spacer's left position should've been " + scrollTo + + " after scrolling " + scrollTo + "px", scrollTo, + getElementLeft(getSpacer(1)), WidgetUtil.PIXEL_EPSILON); + } + + @Test + public void spacersAreFixedInViewport_firstScrollThenFreeze() { + selectMenuPath(FEATURES, FROZEN_COLUMNS, FREEZE_1_COLUMN); + int scrollTo = 10; + scrollHorizontallyTo(scrollTo); + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + assertEquals("Spacer's left position should've been " + scrollTo + + " after scrolling " + scrollTo + "px", scrollTo, + getElementLeft(getSpacer(1)), WidgetUtil.PIXEL_EPSILON); + } + + @Test + public void addingMinusOneSpacerDoesNotScrollWhenScrolledAtTop() { + scrollVerticallyTo(5); + selectMenuPath(FEATURES, SPACERS, ROW_MINUS1, SET_100PX); + assertEquals( + "No scroll adjustment should've happened when adding the -1 spacer", + 5, getScrollTop()); + } + + @Test + public void removingMinusOneSpacerScrolls() { + scrollVerticallyTo(5); + selectMenuPath(FEATURES, SPACERS, ROW_MINUS1, SET_100PX); + selectMenuPath(FEATURES, SPACERS, ROW_MINUS1, REMOVE); + assertEquals("Scroll adjustment should've happened when removing the " + + "-1 spacer", 0, getScrollTop()); + } + + @Test + public void scrollToRowWorksProperlyWithSpacers() throws Exception { + selectMenuPath(FEATURES, SPACERS, ROW_MINUS1, SET_100PX); + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + + /* + * we check for row -2 instead of -1, because escalator has the one row + * buffered underneath the footer + */ + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, SCROLL_TO, ROW_75); + Thread.sleep(500); + assertEquals("Row 75: 0,75", getBodyCell(-2, 0).getText()); + + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, SCROLL_TO, ROW_25); + Thread.sleep(500); + + try { + assertEquals("Row 25: 0,25", getBodyCell(0, 0).getText()); + } catch (ComparisonFailure retryForIE10andIE11) { + /* + * This seems to be some kind of subpixel/off-by-one-pixel error. + * Everything's scrolled correctly, but Escalator still loads one + * row above to the DOM, underneath the header. It's there, but it's + * not visible. We'll allow for that one pixel error. + */ + assertEquals("Row 24: 0,24", getBodyCell(0, 0).getText()); + } + } + + @Test + public void scrollToSpacerFromAbove() throws Exception { + selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX); + selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING); + + // Browsers might vary with a few pixels. + Range allowableScrollRange = Range.between(765, 780); + int scrollTop = (int) getScrollTop(); + assertTrue("Scroll position was not " + allowableScrollRange + ", but " + + scrollTop, allowableScrollRange.contains(scrollTop)); + } + + @Test + public void scrollToSpacerFromBelow() throws Exception { + selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX); + scrollVerticallyTo(999999); + selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING); + + // Browsers might vary with a few pixels. + Range allowableScrollRange = Range.between(1015, 1025); + int scrollTop = (int) getScrollTop(); + assertTrue("Scroll position was not " + allowableScrollRange + ", but " + + scrollTop, allowableScrollRange.contains(scrollTop)); + } + + @Test + public void scrollToSpacerAlreadyInViewport() throws Exception { + selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX); + scrollVerticallyTo(1000); + selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING); + + assertEquals(getScrollTop(), 1000); + } + + @Test + public void scrollToRowAndSpacerFromAbove() throws Exception { + selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX); + selectMenuPath(FEATURES, SPACERS, ROW_50, + SCROLL_HERE_SPACERBELOW_ANY_0PADDING); + + // Browsers might vary with a few pixels. + Range allowableScrollRange = Range.between(765, 780); + int scrollTop = (int) getScrollTop(); + assertTrue("Scroll position was not " + allowableScrollRange + ", but " + + scrollTop, allowableScrollRange.contains(scrollTop)); + } + + @Test + public void scrollToRowAndSpacerFromBelow() throws Exception { + selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX); + scrollVerticallyTo(999999); + selectMenuPath(FEATURES, SPACERS, ROW_50, + SCROLL_HERE_SPACERBELOW_ANY_0PADDING); + + // Browsers might vary with a few pixels. + Range allowableScrollRange = Range.between(995, 1005); + int scrollTop = (int) getScrollTop(); + assertTrue("Scroll position was not " + allowableScrollRange + ", but " + + scrollTop, allowableScrollRange.contains(scrollTop)); + } + + @Test + public void scrollToRowAndSpacerAlreadyInViewport() throws Exception { + selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX); + scrollVerticallyTo(950); + selectMenuPath(FEATURES, SPACERS, ROW_50, + SCROLL_HERE_SPACERBELOW_ANY_0PADDING); + + assertEquals(getScrollTop(), 950); + } + + @Test + public void domCanBeSortedWithFocusInSpacer() throws InterruptedException { + + // Firefox behaves badly with focus-related tests - skip it. + if (BrowserUtil.isFirefox(super.getDesiredCapabilities())) { + return; + } + + selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER); + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + + WebElement inputElement = getEscalator().findElement( + By.tagName("input")); + inputElement.click(); + scrollVerticallyTo(30); + + // Sleep needed because of all the JS we're doing, and to let + // the DOM reordering to take place. + Thread.sleep(500); + + assertFalse("Error message detected", $(NotificationElement.class) + .exists()); + } + + @Test + public void spacersAreInsertedInCorrectDomPosition() { + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + + WebElement tbody = getEscalator().findElement(By.tagName("tbody")); + WebElement spacer = getChild(tbody, 2); + String cssClass = spacer.getAttribute("class"); + assertTrue("element index 2 was not a spacer (class=\"" + cssClass + + "\")", cssClass.contains("-spacer")); + } + + @Test + public void spacersAreInCorrectDomPositionAfterScroll() { + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + + scrollVerticallyTo(32); // roughly one row's worth + + WebElement tbody = getEscalator().findElement(By.tagName("tbody")); + WebElement spacer = getChild(tbody, 1); + String cssClass = spacer.getAttribute("class"); + assertTrue("element index 1 was not a spacer (class=\"" + cssClass + + "\")", cssClass.contains("-spacer")); + } + + @Test + public void spacerScrolledIntoViewGetsFocus() { + selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER); + selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX); + selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING); + + tryToTabIntoFocusUpdaterElement(); + assertEquals("input", getFocusedElement().getTagName()); + } + + @Test + public void spacerScrolledOutOfViewDoesNotGetFocus() { + selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER); + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING); + + tryToTabIntoFocusUpdaterElement(); + assertNotEquals("input", getFocusedElement().getTagName()); + } + + @Test + public void spacerOpenedInViewGetsFocus() { + selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER); + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + tryToTabIntoFocusUpdaterElement(); + WebElement focusedElement = getFocusedElement(); + assertEquals("input", focusedElement.getTagName()); + } + + @Test + public void spacerOpenedOutOfViewDoesNotGetFocus() { + selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER); + selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX); + + tryToTabIntoFocusUpdaterElement(); + assertNotEquals("input", getFocusedElement().getTagName()); + } + + @Test + public void spacerOpenedInViewAndScrolledOutAndBackAgainGetsFocus() { + selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER); + selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, SCROLL_TO, ROW_50); + selectMenuPath(FEATURES, SPACERS, ROW_1, SCROLL_HERE_ANY_0PADDING); + + tryToTabIntoFocusUpdaterElement(); + assertEquals("input", getFocusedElement().getTagName()); + } + + @Test + public void spacerOpenedOutOfViewAndScrolledInAndBackAgainDoesNotGetFocus() { + selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER); + selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX); + selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING); + selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, SCROLL_TO, ROW_0); + + tryToTabIntoFocusUpdaterElement(); + assertNotEquals("input", getFocusedElement().getTagName()); + } + + private void tryToTabIntoFocusUpdaterElement() { + ((TestBenchElement) findElement(By.className("gwt-MenuBar"))).focus(); + WebElement focusedElement = getFocusedElement(); + focusedElement.sendKeys(Keys.TAB); + } + + private WebElement getChild(WebElement parent, int childIndex) { + return (WebElement) executeScript("return arguments[0].children[" + + childIndex + "];", parent); + } + + private static double[] getElementDimensions(WebElement element) { + /* + * we need to parse the style attribute, since using getCssValue gets a + * normalized value that is harder to parse. + */ + String style = element.getAttribute("style"); + + String transform = getTransformFromStyle(style); + if (transform != null) { + return getTranslateValues(transform); + } + + double[] result = new double[] { -1, -1 }; + String left = getLeftFromStyle(style); + if (left != null) { + result[0] = getPixelValue(left); + } + String top = getTopFromStyle(style); + if (top != null) { + result[1] = getPixelValue(top); + } + + if (result[0] != -1 && result[1] != -1) { + return result; + } else { + throw new IllegalArgumentException("Could not parse the position " + + "information from the CSS \"" + style + "\""); + } + } + + private static double getElementTop(WebElement element) { + return getElementDimensions(element)[1]; + } + + private static double getElementLeft(WebElement element) { + return getElementDimensions(element)[0]; + } + + private static String getTransformFromStyle(String style) { + return getFromStyle(TRANSFORM_CSS_PATTERN, style); + } + + private static String getTopFromStyle(String style) { + return getFromStyle(TOP_CSS_PATTERN, style); + } + + private static String getLeftFromStyle(String style) { + return getFromStyle(LEFT_CSS_PATTERN, style); + } + + private static String getFromStyle(Pattern pattern, String style) { + Matcher matcher = pattern.matcher(style); + if (matcher.find()) { + assertEquals("wrong amount of groups matched in " + style, 1, + matcher.groupCount()); + return matcher.group(1); + } else { + return null; + } + } + + /** + * @return {@code [0] == x}, {@code [1] == y} + */ + private static double[] getTranslateValues(String translate) { + Matcher matcher = TRANSLATE_VALUE_PATTERN.matcher(translate); + assertTrue("no matches for " + translate + " against " + + TRANSLATE_VALUE_PATTERN, matcher.find()); + assertEquals("wrong amout of groups matched in " + translate, 2, + matcher.groupCount()); + + return new double[] { Double.parseDouble(matcher.group(1)), + Double.parseDouble(matcher.group(2)) }; + } + + private static double getPixelValue(String top) { + Matcher matcher = PIXEL_VALUE_PATTERN.matcher(top); + assertTrue("no matches for \"" + top + "\" against " + + PIXEL_VALUE_PATTERN, matcher.find()); + assertEquals("wrong amount of groups matched in " + top, 1, + matcher.groupCount()); + return Double.parseDouble(matcher.group(1)); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnReorderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnReorderTest.java new file mode 100644 index 0000000000..0d62797ea4 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnReorderTest.java @@ -0,0 +1,347 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures.server; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; + +/** + * Tests that Grid columns can be reordered by user with drag and drop #16643. + * + * @author Vaadin Ltd + */ +public class GridColumnReorderTest extends GridBasicFeaturesTest { + + private static final String[] COLUMN_REORDERING_PATH = { "Component", + "State", "Column Reordering Allowed" }; + private static final String[] COLUMN_REORDER_LISTENER_PATH = { "Component", + "State", "ColumnReorderListener" }; + + @Before + public void setUp() { + setDebug(true); + } + + @Test + public void testColumnReordering_firstColumnDroppedOnThird_dropOnLeftSide() { + // given + openTestURL(); + assertColumnHeaderOrder(0, 1, 2); + toggleColumnReordering(); + + // when + dragAndDropDefaultColumnHeader(0, 2, CellSide.LEFT); + + // then + assertColumnHeaderOrder(1, 0, 2); + } + + @Test + public void testColumnReordering_firstColumnDroppedOnThird_dropOnRightSide() { + // given + openTestURL(); + assertColumnHeaderOrder(0, 1, 2); + toggleColumnReordering(); + + // when + dragAndDropDefaultColumnHeader(0, 2, CellSide.RIGHT); + + // then + assertColumnHeaderOrder(1, 2, 0); + } + + @Test + public void testColumnReordering_reorderingTwiceBackForth_reordered() { + // given + openTestURL(); + selectMenuPath("Component", "Size", "Width", "800px"); + assertColumnHeaderOrder(0, 1, 2, 3, 4); + toggleColumnReordering(); + + // when + dragAndDropDefaultColumnHeader(2, 0, CellSide.LEFT); + + // then + assertColumnHeaderOrder(2, 0, 1, 3, 4); + + // when + dragAndDropDefaultColumnHeader(1, 3, CellSide.RIGHT); + + // then + assertColumnHeaderOrder(2, 1, 3, 0); + } + + @Test + public void testColumnReordering_notEnabled_noReordering() { + // given + openTestURL(); + assertColumnHeaderOrder(0, 1, 2); + + // when + dragAndDropDefaultColumnHeader(0, 2, CellSide.RIGHT); + + // then + assertColumnHeaderOrder(0, 1, 2); + } + + @Test + public void testColumnReordering_userChangesRevertedByServer_columnsAreUpdated() { + // given + openTestURL(); + assertColumnHeaderOrder(0, 1, 2); + toggleColumnReordering(); + + // when + dragAndDropDefaultColumnHeader(0, 2, CellSide.LEFT); + assertColumnHeaderOrder(1, 0, 2); + moveColumnManuallyLeftByOne(0); + + // then + assertColumnHeaderOrder(0, 1, 2); + } + + @Test + public void testColumnReordering_concurrentUpdatesFromServer_columnOrderFromServerUsed() { + // given + openTestURL(); + assertColumnHeaderOrder(0, 1, 2); + toggleColumnReordering(); + + // when + selectMenuPath(new String[] { "Component", "Internals", + "Update column order without updating client" }); + dragAndDropDefaultColumnHeader(2, 0, CellSide.LEFT); + + // then + assertColumnHeaderOrder(1, 0, 2); + } + + @Test + public void testColumnReordering_triggersReorderEvent_isUserInitiated() { + // given + openTestURL(); + toggleColumnReordering(); + + // when + toggleColumnReorderListener(); + dragAndDropDefaultColumnHeader(0, 2, CellSide.LEFT); + + // then + assertColumnReorderEvent(true); + } + + @Test + public void testColumnReordering_addAndRemoveListener_registerUnRegisterWorks() { + // given + openTestURL(); + toggleColumnReordering(); + dragAndDropDefaultColumnHeader(0, 2, CellSide.LEFT); + assertNoColumnReorderEvent(); + + // when + toggleColumnReorderListener(); + dragAndDropDefaultColumnHeader(0, 2, CellSide.RIGHT); + + // then + assertColumnReorderEvent(true); + + // when + toggleColumnReorderListener(); + dragAndDropDefaultColumnHeader(0, 3, CellSide.LEFT); + + // then + assertNoColumnReorderEvent(); + } + + @Test + public void testColumnReorderingEvent_serverSideReorder_triggersReorderEvent() { + openTestURL(); + + // when + toggleColumnReorderListener(); + moveColumnManuallyLeftByOne(3); + + // then + assertColumnReorderEvent(false); + } + + @Test + public void testColumnReorder_draggingFrozenColumns_impossible() { + // given + openTestURL(); + toggleColumnReordering(); + setFrozenColumns(2); + assertColumnHeaderOrder(0, 1, 2, 3); + + // when + dragAndDropDefaultColumnHeader(0, 2, CellSide.LEFT); + + // then + assertColumnHeaderOrder(0, 1, 2, 3); + assertTrue(getGridElement().getHeaderCell(0, 0).isFrozen()); + assertTrue(getGridElement().getHeaderCell(0, 1).isFrozen()); + assertFalse(getGridElement().getHeaderCell(0, 2).isFrozen()); + } + + @Test + public void testColumnReorder_draggingColumnOnTopOfFrozenColumn_columnDroppedRightOfFrozenColumns() { + // given + openTestURL(); + toggleColumnReordering(); + setFrozenColumns(1); + assertColumnHeaderOrder(0, 1, 2, 3); + + // when + dragAndDropDefaultColumnHeader(2, 0, CellSide.LEFT); + + // then + assertColumnHeaderOrder(0, 2, 1, 3); + } + + @Test + public void testColumnReorder_draggingColumnLeftOfMultiSelectionColumn_columnDroppedRight() { + // given + openTestURL(); + toggleColumnReordering(); + selectMenuPath("Component", "State", "Selection mode", "multi"); + List<TestBenchElement> gridHeaderRowCells = getGridHeaderRowCells(); + assertTrue(gridHeaderRowCells.get(0).getText().equals("")); + assertColumnHeader("Column 0", gridHeaderRowCells.get(1)); + assertColumnHeader("Column 1", gridHeaderRowCells.get(2)); + assertColumnHeader("Column 2", gridHeaderRowCells.get(3)); + + // when + dragAndDropDefaultColumnHeader(2, 0, CellSide.LEFT); + + // then + gridHeaderRowCells = getGridHeaderRowCells(); + assertTrue(gridHeaderRowCells.get(0).getText().equals("")); + assertColumnHeader("Column 1", gridHeaderRowCells.get(1)); + assertColumnHeader("Column 0", gridHeaderRowCells.get(2)); + assertColumnHeader("Column 2", gridHeaderRowCells.get(3)); + } + + @Test + public void testColumnReorder_multiSelectionAndFrozenColumns_columnDroppedRight() { + // given + openTestURL(); + toggleColumnReordering(); + selectMenuPath("Component", "State", "Selection mode", "multi"); + setFrozenColumns(1); + List<TestBenchElement> gridHeaderRowCells = getGridHeaderRowCells(); + assertTrue(gridHeaderRowCells.get(0).getText().equals("")); + assertColumnHeader("Column 0", gridHeaderRowCells.get(1)); + assertColumnHeader("Column 1", gridHeaderRowCells.get(2)); + assertColumnHeader("Column 2", gridHeaderRowCells.get(3)); + + // when + dragAndDropDefaultColumnHeader(3, 0, CellSide.LEFT); + + // then + gridHeaderRowCells = getGridHeaderRowCells(); + assertTrue(gridHeaderRowCells.get(0).getText().equals("")); + assertColumnHeader("Column 0", gridHeaderRowCells.get(1)); + assertColumnHeader("Column 2", gridHeaderRowCells.get(2)); + assertColumnHeader("Column 1", gridHeaderRowCells.get(3)); + } + + @Test + public void testColumnReordering_multiSelectionColumnNotFrozen_stillCantDropLeftSide() { + // given + openTestURL(); + toggleColumnReordering(); + selectMenuPath("Component", "State", "Selection mode", "multi"); + setFrozenColumns(-1); + List<TestBenchElement> gridHeaderRowCells = getGridHeaderRowCells(); + assertTrue(gridHeaderRowCells.get(0).getText().equals("")); + assertColumnHeader("Column 0", gridHeaderRowCells.get(1)); + assertColumnHeader("Column 1", gridHeaderRowCells.get(2)); + assertColumnHeader("Column 2", gridHeaderRowCells.get(3)); + + // when + dragAndDropDefaultColumnHeader(2, 0, CellSide.LEFT); + + // then + gridHeaderRowCells = getGridHeaderRowCells(); + assertTrue(gridHeaderRowCells.get(0).getText().equals("")); + assertColumnHeader("Column 1", gridHeaderRowCells.get(1)); + assertColumnHeader("Column 0", gridHeaderRowCells.get(2)); + assertColumnHeader("Column 2", gridHeaderRowCells.get(3)); + } + + @Test + public void testColumnReordering_twoHeaderRows_dndReorderingPossibleFromFirstRow() { + // given + openTestURL(); + toggleColumnReordering(); + selectMenuPath("Component", "Header", "Append row"); + assertColumnHeaderOrder(0, 1, 2, 3); + + // when + dragAndDropColumnHeader(0, 0, 2, CellSide.RIGHT); + + // then + assertColumnHeaderOrder(1, 2, 0, 3); + } + + @Test + public void testColumnReordering_twoHeaderRows_dndReorderingPossibleFromSecondRow() { + // given + openTestURL(); + toggleColumnReordering(); + selectMenuPath("Component", "Header", "Append row"); + assertColumnHeaderOrder(0, 1, 2, 3); + + // when + dragAndDropColumnHeader(1, 0, 2, CellSide.RIGHT); + + // then + assertColumnHeaderOrder(1, 2, 0, 3); + } + + private void toggleColumnReordering() { + selectMenuPath(COLUMN_REORDERING_PATH); + } + + private void toggleColumnReorderListener() { + selectMenuPath(COLUMN_REORDER_LISTENER_PATH); + } + + private void moveColumnManuallyLeftByOne(int index) { + selectMenuPath(new String[] { "Component", "Columns", + "Column " + index, "Move left" }); + } + + private void assertColumnReorderEvent(boolean userOriginated) { + final String logRow = getLogRow(0); + assertTrue(logRow.contains("Columns reordered, userOriginated: " + + userOriginated)); + } + + private void assertNoColumnReorderEvent() { + final String logRow = getLogRow(0); + assertFalse(logRow.contains("Columns reordered")); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnVisibilityTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnVisibilityTest.java new file mode 100644 index 0000000000..d01e689b72 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnVisibilityTest.java @@ -0,0 +1,280 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; + +@TestCategory("grid") +public class GridColumnVisibilityTest extends GridBasicFeaturesTest { + + private static final String[] TOGGLE_LISTENER = new String[] { "Component", + "State", "ColumnVisibilityChangeListener" }; + private static final String[] TOGGLE_HIDE_COLUMN_0 = new String[] { + "Component", "Columns", "Column 0", "Hidden" }; + + private static final String COLUMN_0_BECAME_HIDDEN_MSG = "Visibility " + + "changed: propertyId: Column 0, isHidden: true"; + private static final String COLUMN_0_BECAME_UNHIDDEN_MSG = "Visibility " + + "changed: propertyId: Column 0, isHidden: false"; + private static final String USER_ORIGINATED_TRUE = "userOriginated: true"; + private static final String USER_ORIGINATED_FALSE = "userOriginated: false"; + + @Before + public void setUp() { + openTestURL(); + } + + @Test + public void columnIsNotShownWhenHidden() { + assertEquals("column 0", getGridElement().getHeaderCell(0, 0).getText() + .toLowerCase()); + + selectMenuPath(TOGGLE_HIDE_COLUMN_0); + assertEquals("column 1", getGridElement().getHeaderCell(0, 0).getText() + .toLowerCase()); + } + + @Test + public void columnIsShownWhenUnhidden() { + selectMenuPath(TOGGLE_HIDE_COLUMN_0); + selectMenuPath(TOGGLE_HIDE_COLUMN_0); + assertEquals("column 0", getGridElement().getHeaderCell(0, 0).getText() + .toLowerCase()); + } + + @Test + public void registeringListener() { + assertFalse(logContainsText(COLUMN_0_BECAME_HIDDEN_MSG)); + selectMenuPath(TOGGLE_LISTENER); + assertFalse(logContainsText(COLUMN_0_BECAME_HIDDEN_MSG)); + + selectMenuPath(TOGGLE_HIDE_COLUMN_0); + assertTrue(logContainsText(COLUMN_0_BECAME_HIDDEN_MSG)); + assertTrue(logContainsText(USER_ORIGINATED_FALSE)); + + selectMenuPath(TOGGLE_HIDE_COLUMN_0); + assertTrue(logContainsText(COLUMN_0_BECAME_UNHIDDEN_MSG)); + assertTrue(logContainsText(USER_ORIGINATED_FALSE)); + } + + @Test + public void deregisteringListener() { + selectMenuPath(TOGGLE_LISTENER); + selectMenuPath(TOGGLE_HIDE_COLUMN_0); + + selectMenuPath(TOGGLE_LISTENER); + selectMenuPath(TOGGLE_HIDE_COLUMN_0); + assertFalse(logContainsText(COLUMN_0_BECAME_UNHIDDEN_MSG)); + } + + @Test + public void testColumnHiding_userOriginated_correctParams() { + selectMenuPath(TOGGLE_LISTENER); + toggleColumnHidable(0); + assertColumnHeaderOrder(0, 1, 2, 3); + + getSidebarOpenButton().click(); + getColumnHidingToggle(0).click(); + getSidebarOpenButton().click(); + + assertColumnHeaderOrder(1, 2, 3); + assertTrue(logContainsText(COLUMN_0_BECAME_HIDDEN_MSG)); + assertTrue(logContainsText(USER_ORIGINATED_TRUE)); + + getSidebarOpenButton().click(); + getColumnHidingToggle(0).click(); + getSidebarOpenButton().click(); + + assertColumnHeaderOrder(0, 1, 2, 3); + assertTrue(logContainsText(COLUMN_0_BECAME_UNHIDDEN_MSG)); + assertTrue(logContainsText(USER_ORIGINATED_TRUE)); + + getSidebarOpenButton().click(); + getColumnHidingToggle(0).click(); + getSidebarOpenButton().click(); + + assertColumnHeaderOrder(1, 2, 3); + assertTrue(logContainsText(COLUMN_0_BECAME_HIDDEN_MSG)); + assertTrue(logContainsText(USER_ORIGINATED_TRUE)); + } + + @Test + public void testColumnHiding_whenHidableColumnRemoved_toggleRemoved() { + toggleColumnHidable(0); + toggleColumnHidable(1); + getSidebarOpenButton().click(); + assertNotNull(getColumnHidingToggle(0)); + + addRemoveColumn(0); + + assertNull(getColumnHidingToggle(0)); + } + + @Test + public void testColumnHiding_whenHidableColumnAdded_toggleWithCorrectCaptionAdded() { + selectMenuPath("Component", "Size", "Width", "100%"); + toggleColumnHidable(0); + toggleColumnHidable(1); + toggleColumnHidingToggleCaptionChange(0); + getSidebarOpenButton().click(); + assertEquals("Column 0 caption 0", getColumnHidingToggle(0).getText()); + getSidebarOpenButton().click(); + + addRemoveColumn(0); + addRemoveColumn(4); + addRemoveColumn(5); + addRemoveColumn(6); + addRemoveColumn(7); + addRemoveColumn(8); + addRemoveColumn(9); + addRemoveColumn(10); + assertColumnHeaderOrder(1, 2, 3, 11); + + getSidebarOpenButton().click(); + assertNull(getColumnHidingToggle(0)); + getSidebarOpenButton().click(); + + addRemoveColumn(0); + assertColumnHeaderOrder(1, 2, 3, 11, 0); + + getSidebarOpenButton().click(); + assertEquals("Column 0 caption 0", getColumnHidingToggle(0).getText()); + } + + @Test + public void testColumnHidingToggleCaption_settingToggleCaption_updatesToggle() { + toggleColumnHidable(1); + getSidebarOpenButton().click(); + assertEquals("column 1", getGridElement().getHeaderCell(0, 1).getText() + .toLowerCase()); + assertEquals("Column 1", getColumnHidingToggle(1).getText()); + + toggleColumnHidingToggleCaptionChange(1); + assertEquals("column 1", getGridElement().getHeaderCell(0, 1).getText() + .toLowerCase()); + assertEquals("Column 1 caption 0", getColumnHidingToggle(1).getText()); + + toggleColumnHidingToggleCaptionChange(1); + assertEquals("Column 1 caption 1", getColumnHidingToggle(1).getText()); + } + + @Test + public void testColumnHidingToggleCaption_settingWidgetToHeader_toggleCaptionStays() { + toggleColumnHidable(1); + getSidebarOpenButton().click(); + assertEquals("column 1", getGridElement().getHeaderCell(0, 1).getText() + .toLowerCase()); + assertEquals("Column 1", getColumnHidingToggle(1).getText()); + + selectMenuPath("Component", "Columns", "Column 1", "Header Type", + "Widget Header"); + + assertEquals("Column 1", getColumnHidingToggle(1).getText()); + } + + private void toggleColumnHidingToggleCaptionChange(int index) { + selectMenuPath("Component", "Columns", "Column " + index, + "Change hiding toggle caption"); + } + + @Test + public void testFrozenColumnHiding_hiddenColumnMadeFrozen_frozenWhenMadeVisible() { + selectMenuPath("Component", "Size", "Width", "100%"); + toggleColumnHidable(0); + toggleColumnHidable(1); + getSidebarOpenButton().click(); + getColumnHidingToggle(0).click(); + getColumnHidingToggle(1).click(); + + assertColumnHeaderOrder(2, 3, 4, 5); + + setFrozenColumns(2); + verifyColumnNotFrozen(0); + verifyColumnNotFrozen(1); + + getColumnHidingToggle(0).click(); + assertColumnHeaderOrder(0, 2, 3, 4, 5); + verifyColumnFrozen(0); + verifyColumnNotFrozen(1); + + getColumnHidingToggle(1).click(); + assertColumnHeaderOrder(0, 1, 2, 3, 4, 5); + verifyColumnFrozen(0); + verifyColumnFrozen(1); + verifyColumnNotFrozen(2); + } + + @Test + public void testFrozenColumnHiding_hiddenFrozenColumnUnfrozen_notFrozenWhenMadeVisible() { + selectMenuPath("Component", "Size", "Width", "100%"); + toggleColumnHidable(0); + toggleColumnHidable(1); + setFrozenColumns(2); + verifyColumnFrozen(0); + verifyColumnFrozen(1); + verifyColumnNotFrozen(2); + verifyColumnNotFrozen(3); + + getSidebarOpenButton().click(); + getColumnHidingToggle(0).click(); + getColumnHidingToggle(1).click(); + assertColumnHeaderOrder(2, 3, 4, 5); + verifyColumnNotFrozen(0); + verifyColumnNotFrozen(1); + + setFrozenColumns(0); + verifyColumnNotFrozen(0); + verifyColumnNotFrozen(1); + + getColumnHidingToggle(0).click(); + assertColumnHeaderOrder(0, 2, 3, 4, 5); + verifyColumnNotFrozen(0); + verifyColumnNotFrozen(1); + + getColumnHidingToggle(1).click(); + assertColumnHeaderOrder(0, 1, 2, 3, 4, 5); + verifyColumnNotFrozen(0); + verifyColumnNotFrozen(1); + verifyColumnNotFrozen(2); + } + + private void verifyColumnFrozen(int index) { + assertTrue(getGridElement().getHeaderCell(0, index).isFrozen()); + } + + private void verifyColumnNotFrozen(int index) { + assertFalse(getGridElement().getHeaderCell(0, index).isFrozen()); + } + + private void toggleColumnHidable(int index) { + selectMenuPath("Component", "Columns", "Column " + index, "Hidable"); + } + + private void addRemoveColumn(int index) { + selectMenuPath("Component", "Columns", "Column " + index, + "Add / Remove"); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java new file mode 100644 index 0000000000..4ea64073f3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java @@ -0,0 +1,306 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; + +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.NotificationElement; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; + +public class GridDetailsServerTest extends GridBasicFeaturesTest { + /** + * The reason to why last item details wasn't selected is that since it will + * exist only after the viewport has been scrolled into view, we wouldn't be + * able to scroll that particular details row into view, making tests + * awkward with two scroll commands back to back. + */ + private static final int ALMOST_LAST_INDEX = 995; + private static final String[] OPEN_ALMOST_LAST_ITEM_DETAILS = new String[] { + "Component", "Details", "Open " + ALMOST_LAST_INDEX }; + private static final String[] OPEN_FIRST_ITEM_DETAILS = new String[] { + "Component", "Details", "Open firstItemId" }; + private static final String[] TOGGLE_FIRST_ITEM_DETAILS = new String[] { + "Component", "Details", "Toggle firstItemId" }; + private static final String[] DETAILS_GENERATOR_NULL = new String[] { + "Component", "Details", "Generators", "NULL" }; + private static final String[] DETAILS_GENERATOR_WATCHING = new String[] { + "Component", "Details", "Generators", "\"Watching\"" }; + private static final String[] DETAILS_GENERATOR_HIERARCHICAL = new String[] { + "Component", "Details", "Generators", "Hierarchical" }; + private static final String[] CHANGE_HIERARCHY = new String[] { + "Component", "Details", "Generators", "- Change Component" }; + + @Before + public void setUp() { + openTestURL(); + } + + @Test + public void openVisibleDetails() { + try { + getGridElement().getDetails(0); + fail("Expected NoSuchElementException"); + } catch (NoSuchElementException ignore) { + // expected + } + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + assertNotNull("details should've opened", getGridElement() + .getDetails(0)); + } + + @Test(expected = NoSuchElementException.class) + public void closeVisibleDetails() { + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + + getGridElement().getDetails(0); + } + + @Test + public void openVisiblePopulatedDetails() { + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + assertNotNull("details should've populated", getGridElement() + .getDetails(0).findElement(By.className("v-widget"))); + } + + @Test(expected = NoSuchElementException.class) + public void closeVisiblePopulatedDetails() { + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + getGridElement().getDetails(0); + } + + @Test + public void openDetailsOutsideOfActiveRange() throws InterruptedException { + getGridElement().scroll(10000); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + getGridElement().scroll(0); + Thread.sleep(50); + assertNotNull("details should've been opened", getGridElement() + .getDetails(0)); + } + + @Test(expected = NoSuchElementException.class) + public void closeDetailsOutsideOfActiveRange() { + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + getGridElement().scroll(10000); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + getGridElement().scroll(0); + getGridElement().getDetails(0); + } + + @Test + public void componentIsVisibleClientSide() { + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + + TestBenchElement details = getGridElement().getDetails(0); + assertNotNull("No widget detected inside details", + details.findElement(By.className("v-widget"))); + } + + @Test + public void openingDetailsTwice() { + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); // open + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); // close + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); // open + + TestBenchElement details = getGridElement().getDetails(0); + assertNotNull("No widget detected inside details", + details.findElement(By.className("v-widget"))); + } + + @Test(expected = NoSuchElementException.class) + public void scrollingDoesNotCreateAFloodOfDetailsRows() { + selectMenuPath(DETAILS_GENERATOR_WATCHING); + + // scroll somewhere to hit uncached rows + getGridElement().scrollToRow(101); + + // this should throw + getGridElement().getDetails(100); + } + + @Test + public void openingDetailsOutOfView() { + getGridElement().scrollToRow(500); + + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + + getGridElement().scrollToRow(0); + + // if this fails, it'll fail before the assertNotNull + assertNotNull("unexpected null details row", getGridElement() + .getDetails(0)); + } + + @Test + public void togglingAVisibleDetailsRowWithOneRoundtrip() { + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); // open + + assertTrue("Unexpected generator content", + getGridElement().getDetails(0).getText().endsWith("(0)")); + selectMenuPath(TOGGLE_FIRST_ITEM_DETAILS); + assertTrue("New component was not displayed in the client", + getGridElement().getDetails(0).getText().endsWith("(1)")); + } + + @Test + public void almostLastItemIdIsRendered() { + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(OPEN_ALMOST_LAST_ITEM_DETAILS); + scrollGridVerticallyTo(100000); + + TestBenchElement details = getGridElement().getDetails( + ALMOST_LAST_INDEX); + assertNotNull(details); + assertTrue("Unexpected details content", + details.getText().endsWith(ALMOST_LAST_INDEX + " (0)")); + } + + @Test + public void hierarchyChangesWorkInDetails() { + selectMenuPath(DETAILS_GENERATOR_HIERARCHICAL); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + assertEquals("One", getGridElement().getDetails(0).getText()); + selectMenuPath(CHANGE_HIERARCHY); + assertEquals("Two", getGridElement().getDetails(0).getText()); + } + + @Ignore("This use case is not currently supported by Grid. If the detail " + + "is out of view, the component is detached from the UI and a " + + "new instance is generated when scrolled back. Support will " + + "maybe be incorporated at a later time") + @Test + public void hierarchyChangesWorkInDetailsWhileOutOfView() { + selectMenuPath(DETAILS_GENERATOR_HIERARCHICAL); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + scrollGridVerticallyTo(10000); + selectMenuPath(CHANGE_HIERARCHY); + scrollGridVerticallyTo(0); + assertEquals("Two", getGridElement().getDetails(0).getText()); + } + + @Test + public void swappingDetailsGenerators_noDetailsShown() { + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(DETAILS_GENERATOR_NULL); + assertFalse("Got some errors", $(NotificationElement.class).exists()); + } + + @Test + public void swappingDetailsGenerators_shownDetails() { + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + assertTrue("Details should be empty at the start", getGridElement() + .getDetails(0).getText().isEmpty()); + + selectMenuPath(DETAILS_GENERATOR_WATCHING); + assertFalse("Details should not be empty after swapping generator", + getGridElement().getDetails(0).getText().isEmpty()); + } + + @Test + public void swappingDetailsGenerators_whileDetailsScrolledOut_showNever() { + scrollGridVerticallyTo(1000); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + selectMenuPath(DETAILS_GENERATOR_WATCHING); + assertFalse("Got some errors", $(NotificationElement.class).exists()); + } + + @Test + public void swappingDetailsGenerators_whileDetailsScrolledOut_showAfter() { + scrollGridVerticallyTo(1000); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + selectMenuPath(DETAILS_GENERATOR_WATCHING); + scrollGridVerticallyTo(0); + + assertFalse("Got some errors", $(NotificationElement.class).exists()); + assertNotNull("Could not find a details", getGridElement() + .getDetails(0)); + } + + @Test + public void swappingDetailsGenerators_whileDetailsScrolledOut_showBefore() { + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + selectMenuPath(DETAILS_GENERATOR_WATCHING); + scrollGridVerticallyTo(1000); + + assertFalse("Got some errors", $(NotificationElement.class).exists()); + assertNotNull("Could not find a details", getGridElement() + .getDetails(0)); + } + + @Test + public void swappingDetailsGenerators_whileDetailsScrolledOut_showBeforeAndAfter() { + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + selectMenuPath(DETAILS_GENERATOR_WATCHING); + scrollGridVerticallyTo(1000); + scrollGridVerticallyTo(0); + + assertFalse("Got some errors", $(NotificationElement.class).exists()); + assertNotNull("Could not find a details", getGridElement() + .getDetails(0)); + } + + @Test + public void nullDetailComponentToggling() { + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(DETAILS_GENERATOR_NULL); + + try { + assertTrue("Details should be empty with null component", + getGridElement().getDetails(0).getText().isEmpty()); + } catch (NoSuchElementException e) { + fail("Expected to find a details row with empty content"); + } + + selectMenuPath(DETAILS_GENERATOR_WATCHING); + assertFalse("Details should be not empty with details component", + getGridElement().getDetails(0).getText().isEmpty()); + } + + @Test + public void noAssertErrorsOnEmptyDetailsAndScrollDown() { + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + scrollGridVerticallyTo(500); + assertFalse(logContainsText("AssertionError")); + } + + @Test + public void noAssertErrorsOnPopulatedDetailsAndScrollDown() { + selectMenuPath(DETAILS_GENERATOR_WATCHING); + selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + scrollGridVerticallyTo(500); + assertFalse(logContainsText("AssertionError")); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java new file mode 100644 index 0000000000..5262156b41 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2014 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.tests.components.grid.basicfeatures.server; + +import java.io.IOException; +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; +import com.vaadin.tests.components.grid.basicfeatures.GridSidebarFeatures; + +public class GridSidebarThemeTest extends GridBasicFeaturesTest { + + @Test + public void testValo() throws Exception { + runTestSequence("valo"); + } + + @Test + public void testValoDark() throws Exception { + runTestSequence("tests-valo-dark"); + } + + @Override + protected Class<?> getUIClass() { + return GridSidebarFeatures.class; + } + + private void runTestSequence(String theme) throws IOException { + openTestURL("theme=" + theme); + + compareScreen(theme + "|SidebarClosed"); + getSidebarOpenButton().click(); + + compareScreen(theme + "|SidebarOpen"); + + new Actions(getDriver()).moveToElement(getColumnHidingToggle(2), 5, 5) + .perform(); + + compareScreen(theme + "|OnMouseOverNotHiddenToggle"); + + getColumnHidingToggle(2).click(); + getColumnHidingToggle(3).click(); + getColumnHidingToggle(6).click(); + + new Actions(getDriver()).moveToElement(getSidebarOpenButton()) + .perform(); + ; + + compareScreen(theme + "|TogglesTriggered"); + + new Actions(getDriver()).moveToElement(getColumnHidingToggle(2)) + .perform(); + ; + + compareScreen(theme + "|OnMouseOverHiddenToggle"); + + getSidebarOpenButton().click(); + + compareScreen(theme + "|SidebarClosed2"); + } + + @Override + public List<DesiredCapabilities> getBrowsersToTest() { + // phantom JS looks wrong from the beginning, so not tested + return getBrowsersExcludingPhantomJS(); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/LoadingIndicatorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/LoadingIndicatorTest.java index f251313100..f4771b9067 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/LoadingIndicatorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/LoadingIndicatorTest.java @@ -19,7 +19,6 @@ import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.ExpectedConditions; @@ -83,10 +82,4 @@ public class LoadingIndicatorTest extends GridBasicFeaturesTest { }); } - private boolean isLoadingIndicatorVisible() { - WebElement loadingIndicator = findElement(By - .className("v-loading-indicator")); - - return loadingIndicator.isDisplayed(); - } } diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java index 2d032ecd9e..48f99e5057 100644 --- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java @@ -938,4 +938,24 @@ public abstract class AbstractTB3Test extends ParallelTest { protected void click(CheckBoxElement checkbox) { checkbox.findElement(By.xpath("input")).click(); } + + protected boolean isLoadingIndicatorVisible() { + WebElement loadingIndicator = findElement(By + .className("v-loading-indicator")); + + return loadingIndicator.isDisplayed(); + } + + protected void waitUntilLoadingIndicatorNotVisible() { + waitUntil(new ExpectedCondition<Boolean>() { + + @Override + public Boolean apply(WebDriver input) { + WebElement loadingIndicator = input.findElement(By + .className("v-loading-indicator")); + + return !loadingIndicator.isDisplayed(); + } + }); + } } diff --git a/uitest/src/com/vaadin/tests/util/PersonContainer.java b/uitest/src/com/vaadin/tests/util/PersonContainer.java index 611e5d3adb..709086be29 100644 --- a/uitest/src/com/vaadin/tests/util/PersonContainer.java +++ b/uitest/src/com/vaadin/tests/util/PersonContainer.java @@ -32,10 +32,14 @@ public class PersonContainer extends BeanItemContainer<Person> implements } public static PersonContainer createWithTestData() { + return createWithTestData(100); + } + + public static PersonContainer createWithTestData(int size) { PersonContainer c = null; Random r = new Random(0); c = new PersonContainer(); - for (int i = 0; i < 100; i++) { + for (int i = 0; i < size; i++) { Person p = new Person(); p.setFirstName(TestDataGenerator.getFirstName(r)); p.setLastName(TestDataGenerator.getLastName(r)); diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java index 761f32bc9a..c735797731 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java @@ -6,13 +6,18 @@ import java.util.List; import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.TableCellElement; +import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTML; import com.vaadin.client.widget.escalator.EscalatorUpdater; import com.vaadin.client.widget.escalator.FlyweightCell; import com.vaadin.client.widget.escalator.Row; import com.vaadin.client.widget.escalator.RowContainer; +import com.vaadin.client.widget.escalator.RowContainer.BodyRowContainer; +import com.vaadin.client.widget.escalator.Spacer; +import com.vaadin.client.widget.escalator.SpacerUpdater; import com.vaadin.client.widgets.Escalator; +import com.vaadin.shared.ui.grid.ScrollDestination; public class EscalatorBasicClientFeaturesWidget extends PureGWTTestApplication<Escalator> { @@ -303,6 +308,7 @@ public class EscalatorBasicClientFeaturesWidget extends createColumnsAndRowsMenu(); createFrozenMenu(); createColspanMenu(); + createSpacerMenu(); } private void createFrozenMenu() { @@ -567,6 +573,26 @@ public class EscalatorBasicClientFeaturesWidget extends escalator.setScrollTop(40); } }, menupath); + + String[] scrollToRowMenuPath = new String[menupath.length + 1]; + System.arraycopy(menupath, 0, scrollToRowMenuPath, 0, menupath.length); + scrollToRowMenuPath[scrollToRowMenuPath.length - 1] = "Scroll to..."; + for (int i = 0; i < 100; i += 25) { + final int rowIndex = i; + addMenuCommand("Row " + i, new ScheduledCommand() { + @Override + public void execute() { + escalator.scrollToRow(rowIndex, ScrollDestination.ANY, 0); + } + }, scrollToRowMenuPath); + } + + addMenuCommand("Set 20px default height", new ScheduledCommand() { + @Override + public void execute() { + escalator.getBody().setDefaultRowHeight(20); + } + }, menupath); } private void createRowsMenu(final RowContainer container, String[] menupath) { @@ -612,6 +638,94 @@ public class EscalatorBasicClientFeaturesWidget extends }, menupath); } + private void createSpacerMenu() { + String[] menupath = { "Features", "Spacers" }; + + addMenuCommand("Swap Spacer Updater", new ScheduledCommand() { + private final SpacerUpdater CUSTOM = new SpacerUpdater() { + @Override + public void destroy(Spacer spacer) { + spacer.getElement().setInnerText(""); + } + + @Override + public void init(Spacer spacer) { + spacer.getElement().setInnerText( + "Spacer for row " + spacer.getRow()); + } + }; + + @Override + public void execute() { + BodyRowContainer body = escalator.getBody(); + + if (SpacerUpdater.NULL.equals(body.getSpacerUpdater())) { + body.setSpacerUpdater(CUSTOM); + } else { + body.setSpacerUpdater(SpacerUpdater.NULL); + } + } + }, menupath); + + addMenuCommand("Focusable Updater", new ScheduledCommand() { + @Override + public void execute() { + escalator.getBody().setSpacerUpdater(new SpacerUpdater() { + @Override + public void init(Spacer spacer) { + spacer.getElement().appendChild(DOM.createInputText()); + } + + @Override + public void destroy(Spacer spacer) { + spacer.getElement().removeAllChildren(); + } + }); + } + }, menupath); + + createSpacersMenuForRow(-1, menupath); + createSpacersMenuForRow(1, menupath); + createSpacersMenuForRow(50, menupath); + createSpacersMenuForRow(99, menupath); + } + + private void createSpacersMenuForRow(final int rowIndex, String[] menupath) { + menupath = new String[] { menupath[0], menupath[1], "Row " + rowIndex }; + addMenuCommand("Set 100px", new ScheduledCommand() { + @Override + public void execute() { + escalator.getBody().setSpacer(rowIndex, 100); + } + }, menupath); + addMenuCommand("Set 50px", new ScheduledCommand() { + @Override + public void execute() { + escalator.getBody().setSpacer(rowIndex, 50); + } + }, menupath); + addMenuCommand("Remove", new ScheduledCommand() { + @Override + public void execute() { + escalator.getBody().setSpacer(rowIndex, -1); + } + }, menupath); + addMenuCommand("Scroll here (ANY, 0)", new ScheduledCommand() { + @Override + public void execute() { + escalator.scrollToSpacer(rowIndex, ScrollDestination.ANY, 0); + } + }, menupath); + addMenuCommand("Scroll here row+spacer below (ANY, 0)", + new ScheduledCommand() { + @Override + public void execute() { + escalator.scrollToRowAndSpacer(rowIndex, + ScrollDestination.ANY, 0); + } + }, menupath); + } + private void insertRows(final RowContainer container, int offset, int number) { if (container == escalator.getBody()) { data.insertRows(offset, number); diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java index 7f813b9d0f..e7ebcfeb51 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java @@ -24,6 +24,8 @@ import com.vaadin.client.widget.escalator.Cell; import com.vaadin.client.widget.escalator.ColumnConfiguration; import com.vaadin.client.widget.escalator.EscalatorUpdater; import com.vaadin.client.widget.escalator.RowContainer; +import com.vaadin.client.widget.escalator.RowContainer.BodyRowContainer; +import com.vaadin.client.widget.escalator.SpacerUpdater; import com.vaadin.client.widgets.Escalator; import com.vaadin.tests.widgetset.client.grid.EscalatorBasicClientFeaturesWidget.LogWidget; @@ -97,6 +99,33 @@ public class EscalatorProxy extends Escalator { } } + private class BodyRowContainerProxy extends RowContainerProxy implements + BodyRowContainer { + private BodyRowContainer rowContainer; + + public BodyRowContainerProxy(BodyRowContainer rowContainer) { + super(rowContainer); + this.rowContainer = rowContainer; + } + + @Override + public void setSpacer(int rowIndex, double height) + throws IllegalArgumentException { + rowContainer.setSpacer(rowIndex, height); + } + + @Override + public void setSpacerUpdater(SpacerUpdater spacerUpdater) + throws IllegalArgumentException { + rowContainer.setSpacerUpdater(spacerUpdater); + } + + @Override + public SpacerUpdater getSpacerUpdater() { + return rowContainer.getSpacerUpdater(); + } + } + private class RowContainerProxy implements RowContainer { private final RowContainer rowContainer; @@ -176,7 +205,7 @@ public class EscalatorProxy extends Escalator { } private RowContainer headerProxy = null; - private RowContainer bodyProxy = null; + private BodyRowContainer bodyProxy = null; private RowContainer footerProxy = null; private ColumnConfiguration columnProxy = null; private LogWidget logWidget; @@ -198,9 +227,9 @@ public class EscalatorProxy extends Escalator { } @Override - public RowContainer getBody() { + public BodyRowContainer getBody() { if (bodyProxy == null) { - bodyProxy = new RowContainerProxy(super.getBody()); + bodyProxy = new BodyRowContainerProxy(super.getBody()); } return bodyProxy; } diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 4dc0195f22..81f000c44e 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -33,9 +33,13 @@ import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.MenuItem; +import com.google.gwt.user.client.ui.MenuItemSeparator; import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.data.DataSource; import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.renderers.DateRenderer; @@ -46,6 +50,7 @@ import com.vaadin.client.renderers.TextRenderer; import com.vaadin.client.ui.VLabel; import com.vaadin.client.widget.grid.CellReference; import com.vaadin.client.widget.grid.CellStyleGenerator; +import com.vaadin.client.widget.grid.DetailsGenerator; import com.vaadin.client.widget.grid.EditorHandler; import com.vaadin.client.widget.grid.RendererCellReference; import com.vaadin.client.widget.grid.RowReference; @@ -55,6 +60,10 @@ import com.vaadin.client.widget.grid.datasources.ListSorter; import com.vaadin.client.widget.grid.events.BodyKeyDownHandler; import com.vaadin.client.widget.grid.events.BodyKeyPressHandler; import com.vaadin.client.widget.grid.events.BodyKeyUpHandler; +import com.vaadin.client.widget.grid.events.ColumnReorderEvent; +import com.vaadin.client.widget.grid.events.ColumnReorderHandler; +import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeEvent; +import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler; import com.vaadin.client.widget.grid.events.FooterKeyDownHandler; import com.vaadin.client.widget.grid.events.FooterKeyPressHandler; import com.vaadin.client.widget.grid.events.FooterKeyUpHandler; @@ -73,6 +82,7 @@ import com.vaadin.client.widgets.Grid.Column; import com.vaadin.client.widgets.Grid.FooterRow; import com.vaadin.client.widgets.Grid.HeaderRow; import com.vaadin.client.widgets.Grid.SelectionMode; +import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.tests.widgetset.client.grid.GridBasicClientFeaturesWidget.Data; /** @@ -400,6 +410,8 @@ public class GridBasicClientFeaturesWidget extends createEditorMenu(); createInternalsMenu(); createDataSourceMenu(); + createDetailsMenu(); + createSidebarMenu(); grid.getElement().getStyle().setZIndex(0); @@ -444,6 +456,71 @@ public class GridBasicClientFeaturesWidget extends }); } }, listenersPath); + addMenuCommand("Add ColumnReorder listener", new ScheduledCommand() { + private HandlerRegistration columnReorderHandler = null; + + @Override + public void execute() { + if (columnReorderHandler != null) { + return; + } + final Label columnOrderLabel = new Label(); + columnOrderLabel.getElement().setId("columnreorder"); + addLineEnd(columnOrderLabel, 300); + columnReorderHandler = grid + .addColumnReorderHandler(new ColumnReorderHandler<List<Data>>() { + + private int eventIndex = 0; + + @Override + public void onColumnReorder( + ColumnReorderEvent<List<Data>> event) { + columnOrderLabel.getElement().setAttribute( + "columns", "" + (++eventIndex)); + } + }); + } + }, listenersPath); + addMenuCommand("Add Column Visibility Change listener", + new ScheduledCommand() { + private HandlerRegistration columnVisibilityHandler = null; + + @Override + public void execute() { + if (columnVisibilityHandler != null) { + return; + } + final Label columnOrderLabel = new Label(); + columnOrderLabel.getElement().setId("columnvisibility"); + addLineEnd(columnOrderLabel, 250); + ColumnVisibilityChangeHandler handler = new ColumnVisibilityChangeHandler<List<Data>>() { + + private int eventIndex = 0; + + @Override + public void onVisibilityChange( + ColumnVisibilityChangeEvent<List<Data>> event) { + columnOrderLabel.getElement().setAttribute( + "counter", "" + (++eventIndex)); + columnOrderLabel.getElement().setAttribute( + "useroriginated", + (Boolean.toString(event + .isUserOriginated()))); + columnOrderLabel.getElement().setAttribute( + "ishidden", + (Boolean.toString(event.isHidden()))); + columnOrderLabel.getElement().setAttribute( + "columnindex", + "" + + grid.getColumns().indexOf( + event.getColumn())); + } + }; + + columnVisibilityHandler = grid + .addColumnVisibilityChangeHandler(handler); + } + }, listenersPath); } private void createStateMenu() { @@ -658,6 +735,79 @@ public class GridBasicClientFeaturesWidget extends grid.setColumnOrder(columns.toArray(new Column[columns.size()])); } }, "Component", "State"); + addMenuCommand("Column Reordering", new ScheduledCommand() { + + @Override + public void execute() { + grid.setColumnReorderingAllowed(!grid + .isColumnReorderingAllowed()); + } + }, "Component", "State"); + addMenuCommand("250px", new ScheduledCommand() { + + @Override + public void execute() { + grid.setWidth("250px"); + } + }, "Component", "State", "Width"); + addMenuCommand("500px", new ScheduledCommand() { + + @Override + public void execute() { + grid.setWidth("500px"); + } + }, "Component", "State", "Width"); + addMenuCommand("750px", new ScheduledCommand() { + + @Override + public void execute() { + grid.setWidth("750px"); + } + }, "Component", "State", "Width"); + addMenuCommand("1000px", new ScheduledCommand() { + + @Override + public void execute() { + grid.setWidth("1000px"); + } + }, "Component", "State", "Width"); + + createScrollToRowMenu(); + } + + private void createScrollToRowMenu() { + String[] menupath = new String[] { "Component", "State", + "Scroll to...", null }; + + for (int i = 0; i < ROWS; i += 100) { + menupath[3] = "Row " + i + "..."; + for (final ScrollDestination scrollDestination : ScrollDestination + .values()) { + final int row = i; + addMenuCommand("Destination " + scrollDestination, + new ScheduledCommand() { + @Override + public void execute() { + grid.scrollToRow(row, scrollDestination); + } + }, menupath); + } + } + + int i = ROWS - 1; + menupath[3] = "Row " + i + "..."; + for (final ScrollDestination scrollDestination : ScrollDestination + .values()) { + final int row = i; + addMenuCommand("Destination " + scrollDestination, + new ScheduledCommand() { + @Override + public void execute() { + grid.scrollToRow(row, scrollDestination); + } + }, menupath); + } + } private void createColumnsMenu() { @@ -671,7 +821,18 @@ public class GridBasicClientFeaturesWidget extends column.setSortable(!column.isSortable()); } }, "Component", "Columns", "Column " + i); - + addMenuCommand("Hidden", new ScheduledCommand() { + @Override + public void execute() { + column.setHidden(!column.isHidden()); + } + }, "Component", "Columns", "Column " + i); + addMenuCommand("Hidable", new ScheduledCommand() { + @Override + public void execute() { + column.setHidable(!column.isHidable()); + } + }, "Component", "Columns", "Column " + i); addMenuCommand("auto", new ScheduledCommand() { @Override public void execute() { @@ -768,6 +929,25 @@ public class GridBasicClientFeaturesWidget extends }); } }, "Component", "Columns", "Column " + i); + addMenuCommand("Move column left", new ScheduledCommand() { + + @SuppressWarnings("unchecked") + @Override + public void execute() { + List<Column<?, List<Data>>> cols = grid.getColumns(); + ArrayList<Column> reordered = new ArrayList<Column>(cols); + final int index = cols.indexOf(column); + if (index == 0) { + Column<?, List<Data>> col = reordered.remove(0); + reordered.add(col); + } else { + Column<?, List<Data>> col = reordered.remove(index); + reordered.add(index - 1, col); + } + grid.setColumnOrder(reordered.toArray(new Column[reordered + .size()])); + } + }, "Component", "Columns", "Column " + i); } } @@ -1223,4 +1403,166 @@ public class GridBasicClientFeaturesWidget extends String coords = "(" + object + ", " + column + ")"; label.setText(coords + " " + output); } + + private void createDetailsMenu() { + String[] menupath = new String[] { "Component", "Row details" }; + addMenuCommand("Set generator", new ScheduledCommand() { + @Override + public void execute() { + grid.setDetailsGenerator(new DetailsGenerator() { + @Override + public Widget getDetails(int rowIndex) { + FlowPanel panel = new FlowPanel(); + + final Label label = new Label("Row: " + rowIndex + "."); + Button button = new Button("Button", + new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + label.setText("clicked"); + } + }); + + panel.add(label); + panel.add(button); + return panel; + } + }); + } + }, menupath); + + addMenuCommand("Set faulty generator", new ScheduledCommand() { + @Override + public void execute() { + grid.setDetailsGenerator(new DetailsGenerator() { + @Override + public Widget getDetails(int rowIndex) { + throw new RuntimeException("This is by design."); + } + }); + } + }, menupath); + + addMenuCommand("Set empty generator", new ScheduledCommand() { + @Override + public void execute() { + grid.setDetailsGenerator(new DetailsGenerator() { + /* + * While this is functionally equivalent to the NULL + * generator, it's good to be explicit, since the behavior + * isn't strictly tied between them. NULL generator might be + * changed to render something different by default, and an + * empty generator might behave differently also in the + * future. + */ + + @Override + public Widget getDetails(int rowIndex) { + return null; + } + }); + } + }, menupath); + + String[] togglemenupath = new String[] { menupath[0], menupath[1], + "Toggle details for..." }; + for (int i : new int[] { 0, 1, 100, 200, 300, 400, 500, 600, 700, 800, + 900, 999 }) { + final int rowIndex = i; + addMenuCommand("Row " + rowIndex, new ScheduledCommand() { + boolean visible = false; + + @Override + public void execute() { + visible = !visible; + grid.setDetailsVisible(rowIndex, visible); + } + }, togglemenupath); + } + + } + + private static Logger getLogger() { + return Logger.getLogger(GridBasicClientFeaturesWidget.class.getName()); + } + + private void createSidebarMenu() { + String[] menupath = new String[] { "Component", "Sidebar" }; + + final List<MenuItem> customMenuItems = new ArrayList<MenuItem>(); + final List<MenuItemSeparator> separators = new ArrayList<MenuItemSeparator>(); + + addMenuCommand("Add item to end", new ScheduledCommand() { + @Override + public void execute() { + MenuItem item = createSidebarMenuItem(customMenuItems.size()); + customMenuItems.add(item); + grid.getSidebarMenu().addItem(item); + } + }, menupath); + + addMenuCommand("Add item before index 1", new ScheduledCommand() { + @Override + public void execute() { + MenuItem item = createSidebarMenuItem(customMenuItems.size()); + customMenuItems.add(item); + grid.getSidebarMenu().insertItem(item, 1); + } + }, menupath); + + addMenuCommand("Remove last added item", new ScheduledCommand() { + @Override + public void execute() { + grid.getSidebarMenu().removeItem( + customMenuItems.remove(customMenuItems.size() - 1)); + } + }, menupath); + + addMenuCommand("Add separator to end", new ScheduledCommand() { + @Override + public void execute() { + MenuItemSeparator separator = new MenuItemSeparator(); + separators.add(separator); + grid.getSidebarMenu().addSeparator(separator); + } + }, menupath); + + addMenuCommand("Add separator before index 1", new ScheduledCommand() { + @Override + public void execute() { + MenuItemSeparator separator = new MenuItemSeparator(); + separators.add(separator); + grid.getSidebarMenu().insertSeparator(separator, 1); + } + }, menupath); + + addMenuCommand("Remove last added separator", new ScheduledCommand() { + @Override + public void execute() { + grid.getSidebarMenu().removeSeparator( + separators.remove(separators.size() - 1)); + } + }, menupath); + + addMenuCommand("Toggle sidebar visibility", new ScheduledCommand() { + @Override + public void execute() { + grid.setSidebarOpen(!grid.isSidebarOpen()); + } + }, menupath); + } + + private MenuItem createSidebarMenuItem(final int index) { + final MenuItem menuItem = new MenuItem("Custom menu item " + index, + new ScheduledCommand() { + @Override + public void execute() { + if (index % 2 == 0) { + grid.setSidebarOpen(false); + } + getLogger().info("Menu item " + index + " selected"); + } + }); + return menuItem; + } } |