| Class | Line # | Actions | |||||
|---|---|---|---|---|---|---|---|
| LiveTableElement | 40 | 59 | 0% | 26 | 35 |
| 1 | /* | |
| 2 | * See the NOTICE file distributed with this work for additional | |
| 3 | * information regarding copyright ownership. | |
| 4 | * | |
| 5 | * This is free software; you can redistribute it and/or modify it | |
| 6 | * under the terms of the GNU Lesser General Public License as | |
| 7 | * published by the Free Software Foundation; either version 2.1 of | |
| 8 | * the License, or (at your option) any later version. | |
| 9 | * | |
| 10 | * This software is distributed in the hope that it will be useful, | |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 | * Lesser General Public License for more details. | |
| 14 | * | |
| 15 | * You should have received a copy of the GNU Lesser General Public | |
| 16 | * License along with this software; if not, write to the Free | |
| 17 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
| 18 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. | |
| 19 | */ | |
| 20 | package org.xwiki.test.ui.po; | |
| 21 | ||
| 22 | import java.util.List; | |
| 23 | ||
| 24 | import org.apache.commons.lang3.StringEscapeUtils; | |
| 25 | import org.openqa.selenium.By; | |
| 26 | import org.openqa.selenium.JavascriptExecutor; | |
| 27 | import org.openqa.selenium.TimeoutException; | |
| 28 | import org.openqa.selenium.WebDriver; | |
| 29 | import org.openqa.selenium.WebElement; | |
| 30 | import org.openqa.selenium.interactions.Actions; | |
| 31 | import org.openqa.selenium.support.ui.ExpectedCondition; | |
| 32 | import org.openqa.selenium.support.ui.Select; | |
| 33 | ||
| 34 | /** | |
| 35 | * Represents the actions possible on a livetable. | |
| 36 | * | |
| 37 | * @version $Id: 6ba9a98cb28200dadaa1bb0dfc4947cf04070032 $ | |
| 38 | * @since 3.2M3 | |
| 39 | */ | |
| 40 | public class LiveTableElement extends BaseElement | |
| 41 | { | |
| 42 | private String livetableId; | |
| 43 | ||
| 44 | 113 | public LiveTableElement(String livetableId) |
| 45 | { | |
| 46 | 113 | this.livetableId = livetableId; |
| 47 | } | |
| 48 | ||
| 49 | /** | |
| 50 | * @return if the livetable has finished displaying and is ready for service | |
| 51 | */ | |
| 52 | 341 | public boolean isReady() |
| 53 | { | |
| 54 | 341 | Object result = getDriver().executeJavascript("return Element.hasClassName('" |
| 55 | + StringEscapeUtils.escapeEcmaScript(livetableId) + "-ajax-loader','hidden')"); | |
| 56 | 341 | return result instanceof Boolean ? (Boolean) result : false; |
| 57 | } | |
| 58 | ||
| 59 | /** | |
| 60 | * Wait till the livetable has finished displaying all its rows (so that we can then assert the livetable content | |
| 61 | * without running the risk that the rows have not been updated yet). | |
| 62 | */ | |
| 63 | 119 | public void waitUntilReady() |
| 64 | { | |
| 65 | 119 | long t1 = System.currentTimeMillis(); |
| 66 | 341 | while ((System.currentTimeMillis() - t1 < getDriver().getTimeout() * 1000L)) { |
| 67 | 341 | if (isReady()) { |
| 68 | 119 | return; |
| 69 | } | |
| 70 | 222 | try { |
| 71 | 222 | Thread.sleep(50); |
| 72 | } catch (InterruptedException e) { | |
| 73 | // Do nothing just break out | |
| 74 | 0 | break; |
| 75 | } | |
| 76 | } | |
| 77 | 0 | throw new TimeoutException("Livetable isn't ready after the timeout has expired."); |
| 78 | } | |
| 79 | ||
| 80 | 14 | public boolean hasColumn(String columnTitle) |
| 81 | { | |
| 82 | 14 | List<WebElement> elements = getDriver().findElementsWithoutWaiting( |
| 83 | By.xpath("//th[contains(@class, 'xwiki-livetable-display-header-text') and normalize-space(.) = '" | |
| 84 | + columnTitle + "']")); | |
| 85 | 14 | return elements.size() > 0; |
| 86 | } | |
| 87 | ||
| 88 | 22 | public void filterColumn(String inputId, String filterValue) |
| 89 | { | |
| 90 | // Make extra sure Selenium can't go quicker than the live table status by forcing it before filtering. | |
| 91 | 22 | getDriver().executeJavascript("return $('" + StringEscapeUtils.escapeEcmaScript(livetableId) |
| 92 | + "-ajax-loader').removeClassName('hidden')"); | |
| 93 | ||
| 94 | 22 | WebElement element = getDriver().findElement(By.id(inputId)); |
| 95 | 22 | if ("select".equals(element.getTagName())) { |
| 96 | 3 | new Select(element).selectByVisibleText(filterValue); |
| 97 | } else { | |
| 98 | 19 | element.clear(); |
| 99 | 19 | element.sendKeys(filterValue); |
| 100 | } | |
| 101 | 22 | waitUntilReady(); |
| 102 | } | |
| 103 | ||
| 104 | /** | |
| 105 | * @param inputId the filter input identifier | |
| 106 | * @return the value of the filter input for the specified column | |
| 107 | * @see #filterColumn(String, String) | |
| 108 | */ | |
| 109 | 2 | public String getFilterValue(String inputId) |
| 110 | { | |
| 111 | 2 | return getDriver().findElement(By.id(inputId)).getAttribute("value"); |
| 112 | } | |
| 113 | ||
| 114 | /** | |
| 115 | * @param columnTitle the title of live table column | |
| 116 | * @return the 0-based index of the specified column | |
| 117 | */ | |
| 118 | 34 | public int getColumnIndex(String columnTitle) |
| 119 | { | |
| 120 | 34 | WebElement liveTable = getDriver().findElement(By.id(livetableId)); |
| 121 | ||
| 122 | 34 | String escapedColumnTitle = columnTitle.replace("\\", "\\\\").replace("'", "\\'"); |
| 123 | 34 | String columnXPath = "//thead[@class = 'xwiki-livetable-display-header']//th[normalize-space(.) = '%s']"; |
| 124 | 34 | WebElement column = liveTable.findElement(By.xpath(String.format(columnXPath, escapedColumnTitle))); |
| 125 | ||
| 126 | 34 | return ((Long) ((JavascriptExecutor) getDriver()).executeScript("return arguments[0].cellIndex;", column)) |
| 127 | .intValue(); | |
| 128 | } | |
| 129 | ||
| 130 | /** | |
| 131 | * Checks if there is a row that has the given value for the specified column. | |
| 132 | * | |
| 133 | * @param columnTitle the title of live table column | |
| 134 | * @param columnValue the value to match rows against | |
| 135 | * @return {@code true} if there is a row that matches the given value for the specified column, {@code false} | |
| 136 | * otherwise | |
| 137 | */ | |
| 138 | 31 | public boolean hasRow(String columnTitle, String columnValue) |
| 139 | { | |
| 140 | 31 | List<WebElement> elements = getRows(columnTitle); |
| 141 | ||
| 142 | 31 | boolean result = elements.size() > 0; |
| 143 | 31 | boolean match = false; |
| 144 | 31 | if (result) { |
| 145 | 30 | for (WebElement element : elements) { |
| 146 | 54 | match = element.getText().equals(columnValue); |
| 147 | 54 | if (match) { |
| 148 | 29 | break; |
| 149 | } | |
| 150 | } | |
| 151 | } | |
| 152 | ||
| 153 | 31 | return result && match; |
| 154 | } | |
| 155 | ||
| 156 | /** | |
| 157 | * Checks if there are as many rows as there are passed values and check that the values match. | |
| 158 | * | |
| 159 | * @since 7.2M2 | |
| 160 | */ | |
| 161 | 0 | public boolean hasExactRows(String columnTitle, List<String> columnValues) |
| 162 | { | |
| 163 | 0 | List<WebElement> elements = getRows(columnTitle); |
| 164 | ||
| 165 | 0 | boolean result = elements.size() == columnValues.size(); |
| 166 | 0 | if (result) { |
| 167 | 0 | for (int i = 0; i < elements.size(); i++) { |
| 168 | 0 | result = result && elements.get(i).getText().equals(columnValues.get(i)); |
| 169 | 0 | if (!result) { |
| 170 | 0 | break; |
| 171 | } | |
| 172 | } | |
| 173 | } | |
| 174 | ||
| 175 | 0 | return result; |
| 176 | } | |
| 177 | ||
| 178 | 31 | private List<WebElement> getRows(String columnTitle) |
| 179 | { | |
| 180 | 31 | String cellXPath = String.format(".//tr/td[position() = %s]", getColumnIndex(columnTitle) + 1); |
| 181 | 31 | WebElement liveTableBody = getDriver().findElement(By.id(this.livetableId + "-display")); |
| 182 | 31 | return liveTableBody.findElements(By.xpath(cellXPath)); |
| 183 | } | |
| 184 | ||
| 185 | /** | |
| 186 | * @return the number of rows in the live table | |
| 187 | */ | |
| 188 | 24 | public int getRowCount() |
| 189 | { | |
| 190 | 24 | WebElement liveTableBody = getDriver().findElementWithoutWaiting(By.id(this.livetableId + "-display")); |
| 191 | // We use XPath because we're interested only in the direct children. | |
| 192 | 24 | return getDriver().findElementsWithoutWaiting(liveTableBody, By.xpath("tr")).size(); |
| 193 | } | |
| 194 | ||
| 195 | /** | |
| 196 | * @since 5.3RC1 | |
| 197 | */ | |
| 198 | 0 | public WebElement getRow(int rowNumber) |
| 199 | { | |
| 200 | 0 | WebElement liveTableBody = getDriver().findElementWithoutWaiting(By.id(this.livetableId + "-display")); |
| 201 | 0 | return getDriver().findElementWithoutWaiting(liveTableBody, By.xpath("tr[" + rowNumber + "]")); |
| 202 | } | |
| 203 | ||
| 204 | /** | |
| 205 | * @since 5.3RC1 | |
| 206 | */ | |
| 207 | 0 | public WebElement getCell(WebElement rowElement, int columnNumber) |
| 208 | { | |
| 209 | 0 | return getDriver().findElementWithoutWaiting(rowElement, By.xpath("td[" + columnNumber + "]")); |
| 210 | } | |
| 211 | ||
| 212 | /** | |
| 213 | * @since 5.3RC1 | |
| 214 | */ | |
| 215 | 0 | public ViewPage clickCell(int rowNumber, int columnNumber) |
| 216 | { | |
| 217 | 0 | WebElement tdElement = getCell(getRow(rowNumber), columnNumber); |
| 218 | // First scroll the element into view, if needed, by moving the mouse to the top left corner of the element. | |
| 219 | 0 | new Actions(getDriver()).moveToElement(tdElement, 0, 0).perform(); |
| 220 | // Find the first A element and click it! | |
| 221 | 0 | tdElement.findElement(By.tagName("a")).click(); |
| 222 | 0 | return new ViewPage(); |
| 223 | } | |
| 224 | ||
| 225 | /** | |
| 226 | * @since 3.2M3 | |
| 227 | */ | |
| 228 | 0 | public void waitUntilRowCountGreaterThan(final int minimalExpectedRowCount) |
| 229 | { | |
| 230 | 0 | final By by = By.xpath("//tbody[@id = '" + this.livetableId + "-display']//tr"); |
| 231 | 0 |
getDriver().waitUntilCondition(new ExpectedCondition<Boolean>() |
| 232 | { | |
| 233 | 0 | @Override |
| 234 | public Boolean apply(WebDriver driver) | |
| 235 | { | |
| 236 | // Refresh the current page since we need the livetable to fetch the JSON again | |
| 237 | 0 | driver.navigate().refresh(); |
| 238 | 0 | return driver.findElements(by).size() >= minimalExpectedRowCount; |
| 239 | } | |
| 240 | }); | |
| 241 | } | |
| 242 | } |