/* * Copyright 2000-2016 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.v7.tests.components.grid.basicfeatures.server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.junit.Test; import org.openqa.selenium.Keys; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.testbench.By; import com.vaadin.testbench.elements.GridElement; import com.vaadin.testbench.elements.GridElement.GridCellElement; import com.vaadin.v7.tests.components.grid.basicfeatures.GridBasicFeatures; import com.vaadin.v7.tests.components.grid.basicfeatures.GridBasicFeaturesTest; public class GridSortingTest extends GridBasicFeaturesTest { private static class SortInfo { public final int sortOrder; public final SortDirection sortDirection; private SortInfo(int sortOrder, SortDirection sortDirection) { this.sortOrder = sortOrder; this.sortDirection = sortDirection; } } private static class SortInfoWithColumn extends SortInfo { public final int columnIndex; private SortInfoWithColumn(int columnIndex, int sortOrder, SortDirection sortDirection) { super(sortOrder, sortDirection); this.columnIndex = columnIndex; } } private static SortInfo getSortInfo(int sortOrder, SortDirection sortDirection) { return new SortInfo(sortOrder, sortDirection); } private static SortInfoWithColumn getSortInfo(int columnIndex, int sortOrder, SortDirection sortDirection) { return new SortInfoWithColumn(columnIndex, sortOrder, sortDirection); } @Test public void testProgrammaticSorting() throws Exception { openTestURL(); // Sorting by column 9 is sorting by row index that is represented as a // String. // First cells for first 3 rows are (9, 0), (99, 0) and (999, 0) sortBy("Column 9, DESC"); assertLastSortIsUserOriginated(false); // Verify that programmatic sorting calls are identified as originating // from API assertColumnsAreSortedAs(getSortInfo(9, 1, SortDirection.DESCENDING)); String row = ""; for (int i = 0; i < 3; ++i) { row += "9"; String expected = "(" + row + ", 0)"; String cellValue = getGridElement().getCell(i, 0).getText(); assertEquals( "Grid is not sorted by Column 9 " + "using descending direction.", expected, cellValue); } // Column 10 is random numbers from Random with seed 13334 sortBy("Column 10, ASC"); assertFalse("Column 9 should no longer have the sort-desc stylename", getGridElement().getHeaderCell(0, 9).getAttribute("class") .contains("sort-desc")); assertColumnsAreSortedAs(getSortInfo(10, 1, SortDirection.ASCENDING)); for (int i = 0; i < 5; ++i) { Integer firstRow = Integer .valueOf(getGridElement().getCell(i + 1, 10).getText()); Integer secondRow = Integer .valueOf(getGridElement().getCell(i, 10).getText()); assertGreater("Grid is not sorted by Column 10 using" + " ascending direction", firstRow, secondRow); } // Column 7 is row index as a number. Last three row are original rows // 2, 1 and 0. sortBy("Column 7, DESC"); for (int i = 0; i < 3; ++i) { String expected = "(" + i + ", 0)"; String cellContent = getGridElement() .getCell(GridBasicFeatures.ROWS - (i + 1), 0).getText(); assertEquals("Grid is not sorted by Column 7 using " + "descending direction", expected, cellContent); } assertFalse("Column 10 should no longer have the sort-asc stylename", getGridElement().getHeaderCell(0, 10).getAttribute("class") .contains("sort-asc")); assertColumnsAreSortedAs(getSortInfo(7, 1, SortDirection.DESCENDING)); } @Test public void testMouseSorting() throws Exception { setDebug(true); openTestURL(); GridElement grid = getGridElement(); selectMenuPath("Component", "Columns", "Column 9", "Column 9 Width", "Auto"); // Sorting by column 9 is sorting by row index that is represented as a // String. // Click header twice to sort descending clickHeader(grid.getHeaderCell(0, 9)); assertLastSortIsUserOriginated(true); assertColumnsAreSortedAs(getSortInfo(9, 1, SortDirection.ASCENDING)); clickHeader(grid.getHeaderCell(0, 9)); assertColumnsAreSortedAs(getSortInfo(9, 1, SortDirection.DESCENDING)); // First cells for first 3 rows are (9, 0), (99, 0) and (999, 0) String row = ""; for (int i = 0; i < 3; ++i) { row += "9"; String expected = "(" + row + ", 0)"; String actual = grid.getCell(i, 0).getText(); assertEquals("Grid is not sorted by Column 9" + " using descending direction.", expected, actual); } selectMenuPath("Component", "Columns", "Column 10", "Column 10 Width", "Auto"); // Column 10 is random numbers from Random with seed 13334 // Click header to sort ascending clickHeader(grid.getHeaderCell(0, 10)); assertColumnsAreSortedAs(getSortInfo(10, 1, SortDirection.ASCENDING)); for (int i = 0; i < 5; ++i) { Integer firstRow = Integer .valueOf(grid.getCell(i + 1, 10).getText()); Integer secondRow = Integer.valueOf(grid.getCell(i, 10).getText()); assertGreater( "Grid is not sorted by Column 10 using ascending direction", firstRow, secondRow); } selectMenuPath("Component", "Columns", "Column 7", "Column 7 Width", "Auto"); // Column 7 is row index as a number. Last three row are original rows // 2, 1 and 0. // Click header twice to sort descending clickHeader(grid.getHeaderCell(0, 7)); assertColumnsAreSortedAs(getSortInfo(7, 1, SortDirection.ASCENDING)); clickHeader(grid.getHeaderCell(0, 7)); assertColumnsAreSortedAs(getSortInfo(7, 1, SortDirection.DESCENDING)); for (int i = 0; i < 3; ++i) { assertEquals( "Grid is not sorted by Column 7 using descending direction", "(" + i + ", 0)", grid.getCell(GridBasicFeatures.ROWS - (i + 1), 0) .getText()); } } private void clickHeader(GridCellElement headerCell) { new Actions(getDriver()).moveToElement(headerCell, 20, 10).click() .perform(); } private void sendKey(Keys seq) { new Actions(getDriver()).sendKeys(seq).perform(); } private void holdKey(Keys key) { new Actions(getDriver()).keyDown(key).perform(); } private void releaseKey(Keys key) { new Actions(getDriver()).keyUp(key).perform(); } @Test public void testKeyboardSortingMultipleHeaders() { openTestURL(); selectMenuPath("Component", "Header", "Append row"); // Sort according to first column by clicking getGridElement().getHeaderCell(0, 0).click(); assertColumnIsSorted(0); // Try to sort according to second column by pressing enter on the new // header sendKey(Keys.ARROW_RIGHT); sendKey(Keys.ARROW_DOWN); sendKey(Keys.ENTER); // Should not have sorted assertColumnIsSorted(0); // Sort using default header sendKey(Keys.ARROW_UP); sendKey(Keys.ENTER); // Should have sorted assertColumnIsSorted(1); } @Test public void testKeyboardSorting() { openTestURL(); /* * We can't click on the header directly, since it will sort the header * immediately. We need to focus some other column first, and only then * navigate there. */ getGridElement().getCell(0, 0).click(); sendKey(Keys.ARROW_UP); // Sort ASCENDING on first column sendKey(Keys.ENTER); assertLastSortIsUserOriginated(true); assertColumnsAreSortedAs(getSortInfo(1, SortDirection.ASCENDING)); // Move to next column sendKey(Keys.RIGHT); // Add this column to the existing sorting group holdKey(Keys.SHIFT); sendKey(Keys.ENTER); releaseKey(Keys.SHIFT); assertColumnsAreSortedAs(getSortInfo(1, SortDirection.ASCENDING), getSortInfo(2, SortDirection.ASCENDING)); // Move to next column sendKey(Keys.RIGHT); // Add a third column to the sorting group holdKey(Keys.SHIFT); sendKey(Keys.ENTER); releaseKey(Keys.SHIFT); assertColumnsAreSortedAs(getSortInfo(1, SortDirection.ASCENDING), getSortInfo(2, SortDirection.ASCENDING), getSortInfo(3, SortDirection.ASCENDING)); // Move back to the second column sendKey(Keys.LEFT); // Change sort direction of the second column to DESCENDING holdKey(Keys.SHIFT); sendKey(Keys.ENTER); releaseKey(Keys.SHIFT); assertColumnsAreSortedAs(getSortInfo(1, SortDirection.ASCENDING), getSortInfo(2, SortDirection.DESCENDING), getSortInfo(3, SortDirection.ASCENDING)); // Move back to the third column sendKey(Keys.RIGHT); // Set sorting to third column, ASCENDING sendKey(Keys.ENTER); assertColumnsAreSortedAs(getSortInfo(2, 1, SortDirection.ASCENDING)); // Move to the fourth column sendKey(Keys.RIGHT); // Make sure that single-column sorting also works as expected sendKey(Keys.ENTER); assertColumnsAreSortedAs(getSortInfo(3, 1, SortDirection.ASCENDING)); } private void assertColumnsAreSortedAs(SortInfoWithColumn... sortInfos) { for (SortInfoWithColumn sortInfo : sortInfos) { assertSort(sortInfo, sortInfo.columnIndex, onlyOneColumnIsSorted(sortInfos)); } } /** * @param sortDirections * <code>null</code> if not interested in that index, otherwise a * direction that the column needs to be sorted as */ private void assertColumnsAreSortedAs(SortInfo... sortInfos) { for (int column = 0; column < sortInfos.length; column++) { SortInfo sortInfo = sortInfos[column]; assertSort(sortInfo, column, onlyOneColumnIsSorted(sortInfos)); } } private void assertSort(SortInfo sortInfo, int column, boolean onlyOneColumnIsSorted) { if (sortInfo == null) { return; } GridCellElement headerCell = getGridElement().getHeaderCell(0, column); String classValue = headerCell.getAttribute("class"); boolean isSortedAscending = sortInfo.sortDirection == SortDirection.ASCENDING && classValue.contains("sort-asc"); boolean isSortedDescending = sortInfo.sortDirection == SortDirection.DESCENDING && classValue.contains("sort-desc"); if (isSortedAscending || isSortedDescending) { String sortOrderAttribute = headerCell.getAttribute("sort-order"); if (sortOrderAttribute == null) { if (!(sortInfo.sortOrder == 1 && onlyOneColumnIsSorted)) { fail("missing sort-order element attribute from column " + column); } } else { assertEquals("sort order was not as expected", String.valueOf(sortInfo.sortOrder), sortOrderAttribute); } } else { fail("column index " + column + " was not sorted as " + sortInfo.sortDirection + " (class: " + classValue + ")"); } } private static boolean onlyOneColumnIsSorted(SortInfo[] sortInfos) { boolean foundSortedColumn = false; for (SortInfo sortInfo : sortInfos) { if (sortInfo == null) { continue; } if (!foundSortedColumn) { foundSortedColumn = true; } else { // two columns were sorted return false; } } return foundSortedColumn; } private void sortBy(String column) { selectMenuPath("Component", "State", "Sort by column", column); } private void assertLastSortIsUserOriginated(boolean isUserOriginated) { // Find a message in the log List<WebElement> userOriginatedMessages = getDriver().findElements(By .xpath("//div[@id='Log']//*[contains(text(),'SortEvent: isUserOriginated')]")); Collections.sort(userOriginatedMessages, new Comparator<WebElement>() { @Override public int compare(WebElement o1, WebElement o2) { return o1.getText().compareTo(o2.getText()); } }); String newestEntry = userOriginatedMessages .get(userOriginatedMessages.size() - 1).getText(); String[] parts = newestEntry.split(" "); boolean wasUserOriginated = Boolean .parseBoolean(parts[parts.length - 1]); if (isUserOriginated) { assertTrue("expected the sort to be user originated, but wasn't", wasUserOriginated); } else { assertFalse( "expected the sort not to be user originated, but it was", wasUserOriginated); } } }