001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nelson Silva 018 */ 019package org.nuxeo.functionaltests.contentView; 020 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.util.List; 025import java.util.function.Function; 026 027import org.nuxeo.functionaltests.AbstractTest; 028import org.nuxeo.functionaltests.AjaxRequestManager; 029import org.nuxeo.functionaltests.Assert; 030import org.nuxeo.functionaltests.Locator; 031import org.nuxeo.functionaltests.fragment.WebFragmentImpl; 032import org.nuxeo.functionaltests.pages.DocumentBasePage; 033import org.openqa.selenium.By; 034import org.openqa.selenium.NoSuchElementException; 035import org.openqa.selenium.WebDriver; 036import org.openqa.selenium.WebElement; 037 038/** 039 * Represents a content view element. 040 * 041 * @since 7.1 042 */ 043public class ContentViewElement extends WebFragmentImpl { 044 045 private static final String SELECT_ALL_BUTTON_XPATH = "//input[@type=\"checkbox\" and @title=\"Select all / deselect all\"]"; 046 047 private static final String CHECK_BOX_XPATH = "td/input[@type=\"checkbox\"]"; 048 049 public enum ResultLayout { 050 THUMBNAIL("Thumbnail view"), LISTING("List view"); 051 052 private final String title; 053 054 ResultLayout(String title) { 055 this.title = title; 056 } 057 } 058 059 public ContentViewElement(WebDriver driver, WebElement element) { 060 super(driver, element); 061 } 062 063 protected ContentViewElement reload(String id) { 064 return getWebFragment(By.id(id), ContentViewElement.class); 065 } 066 067 /** 068 * @since 9.1 069 */ 070 public ContentViewUpperActions getUpperActions() { 071 return AbstractTest.getWebFragment(By.className("contentViewUpperActions"), ContentViewUpperActions.class); 072 } 073 074 /** 075 * @since 9.1 076 */ 077 public ContentViewSelectionActions getSelectionActions() { 078 By buttonsId = By.id(String.format("%s_buttons:ajax_selection_buttons", getContentViewType())); 079 Locator.waitUntilElementPresent(buttonsId); 080 return AbstractTest.getWebFragment(buttonsId, ContentViewSelectionActions.class); 081 } 082 083 public PageNavigationControls getPaginationControls() { 084 return AbstractTest.getWebFragment(findElement(By.className("pageNavigationControls")), 085 PageNavigationControls.class); 086 } 087 088 /** 089 * @since 9.1 090 */ 091 protected WebElement getFilterInput() { 092 String id = getContentViewId() + "_quickFilterForm:nxl_document_content_filter:nxw_search_title"; 093 return findElement(By.id(id)); 094 } 095 096 /** 097 * @since 9.1 098 */ 099 protected WebElement getFilterButton() { 100 String id = getContentViewId() + "_quickFilterForm:submitFilter"; 101 return findElement(By.id(id)); 102 } 103 104 /** 105 * @since 9.1 106 */ 107 protected WebElement getClearFilterButton() { 108 String id = getContentViewId() + "_resetFilterForm:resetFilter"; 109 return findElement(By.id(id)); 110 } 111 112 protected String getContentViewId() { 113 String id = getId(); 114 if (id.endsWith("_panel")) { 115 return id.substring(0, id.length() - "_panel".length()); 116 } 117 return id; 118 } 119 120 /** 121 * @return the content view id with cv_* and _\d* removed. This is useful to get the selection actions. 122 */ 123 protected String getContentViewType() { 124 return getContentViewId().replaceFirst("^cv_", "").replaceFirst("_\\d*$", ""); 125 } 126 127 protected WebElement getResultsPanel() { 128 String id = getContentViewId() + "_resultsPanel"; 129 return getElement().findElement(By.id(id)); 130 } 131 132 public WebElement getActionByTitle(String title) { 133 return getUpperActions().getActionByTitle(title); 134 } 135 136 public ContentViewElement switchToResultLayout(ResultLayout layout) { 137 // get id before element is detached from DOM (during next ajax calls) 138 String id = getId(); 139 getUpperActions().clickOnActionByTitle(layout.title); 140 return reload(id); 141 } 142 143 /** 144 * Use this method to do navigation actions with reloading of this {@link ContentViewElement}. 145 * 146 * @return the new content view element 147 * @since 9.1 148 */ 149 public <T extends DocumentBasePage> ContentViewElement navigation(Function<PageNavigationControls, T> nav) { 150 // get id before element is detached from DOM (during next ajax calls) 151 String id = getId(); 152 nav.apply(getPaginationControls()); 153 return reload(id); 154 } 155 156 /** 157 * @since 8.3 158 */ 159 public List<WebElement> getItems() { 160 ResultLayout layout = getResultLayout(); 161 switch (layout) { 162 case THUMBNAIL: 163 return getResultsPanel().findElements(By.xpath(".//div[contains(@class,'bubbleBox')]")); 164 case LISTING: 165 default: 166 return getResultsPanel().findElements(By.xpath("(.//form)[1]//tbody//tr")); 167 } 168 } 169 170 /** 171 * @since 9.1 172 */ 173 public WebElement getItemWithTitleAndVersion(String title, String version) { 174 for (WebElement item : getItems()) { 175 String t = item.findElement(By.xpath("td[3]")).getText(); // title 176 String v = item.findElement(By.xpath("td[7]")).getText(); // version 177 if (t.equals(title) && v.equals(version)) { 178 return item; 179 } 180 } 181 throw new NoSuchElementException("No item with title \"" + title + "\" and version " + version); 182 } 183 184 /** 185 * @since 8.3 186 */ 187 public void clickOnItemTitle(String title) { 188 Locator.findElementWaitUntilEnabledAndClick(getResultsPanel(), By.linkText(title)); 189 } 190 191 /** 192 * @since 9.1 193 */ 194 public void clickOnItemTitleAndVersion(String title, String version) { 195 if (getResultLayout() == ResultLayout.THUMBNAIL) { 196 throw new NoSuchElementException("Click on title and version doesn\"t work with thumbnails."); 197 } 198 WebElement item = getItemWithTitleAndVersion(title, version); 199 Locator.findElementWaitUntilEnabledAndClick(item, By.linkText(title)); 200 } 201 202 /** 203 * @since 9.1 204 */ 205 public void clickOnItemIndex(int index) { 206 if (getResultLayout() == ResultLayout.THUMBNAIL) { 207 throw new NoSuchElementException("Click on index doesn\"t work with thumbnails."); 208 } 209 Locator.waitUntilEnabledAndClick(getItems().get(index).findElement(By.xpath("td[3]/div/a[1]"))); 210 } 211 212 /** 213 * @since 8.3 214 */ 215 public boolean hasItem(String title) { 216 try { 217 WebElement element = getResultsPanel().findElement(By.linkText(title)); 218 return element != null; 219 } catch (NoSuchElementException e) { 220 return false; 221 } 222 } 223 224 /** 225 * Perform filter on the given string. 226 * 227 * @param filter the string to filter 228 * @since 9.1 229 */ 230 public ContentViewElement filterDocument(String filter) { 231 WebElement filterInput = getFilterInput(); 232 // get id before element is detached from DOM (during next ajax calls) 233 String id = getId(); 234 filterInput.clear(); 235 filterInput.sendKeys(filter); 236 AjaxRequestManager arm = new AjaxRequestManager(driver); 237 arm.begin(); 238 getFilterButton().click(); 239 arm.end(); 240 Locator.waitUntilElementPresent(By.id(getClearFilterButton().getAttribute("id"))); 241 return reload(id); 242 } 243 244 /** 245 * Clear the current filter and refresh content view. 246 * 247 * @since 9.1 248 */ 249 public ContentViewElement clearFilter() { 250 WebElement clearFilterButton = getClearFilterButton(); 251 // get id before element is detached from DOM (during next ajax calls) 252 String id = getId(); 253 String clearFilterButtonId = clearFilterButton.getAttribute("id"); 254 AjaxRequestManager arm = new AjaxRequestManager(driver); 255 arm.begin(); 256 Locator.waitUntilEnabledAndClick(clearFilterButton); 257 arm.end(); 258 Locator.waitUntilElementNotPresent(By.id(clearFilterButtonId)); 259 return reload(id); 260 } 261 262 /** 263 * @since 8.3 264 * @deprecated since 9.1 use {@link #selectByTitle(String...)} instead. 265 */ 266 @Deprecated 267 public ContentViewElement checkByTitle(String... titles) { 268 // get id before element is detached from DOM (during next ajax calls) 269 String id = getId(); 270 List<WebElement> items = getItems(); 271 for (WebElement item : items) { 272 for (String title : titles) { 273 try { 274 item.findElement(By.linkText(title)); 275 AjaxRequestManager arm = new AjaxRequestManager(driver); 276 arm.begin(); 277 Locator.findElementWaitUntilEnabledAndClick(item, By.xpath(CHECK_BOX_XPATH)); 278 arm.end(); 279 break; 280 } catch (NoSuchElementException e) { 281 // next 282 } 283 } 284 } 285 return reload(id); 286 } 287 288 /** 289 * @since 9.1 290 */ 291 public ContentViewSelectionActions selectByTitle(String... titles) { 292 // get id before element is detached from DOM (during next ajax calls) 293 String id = getId(); 294 List<WebElement> items = getItems(); 295 for (WebElement item : items) { 296 for (String title : titles) { 297 try { 298 item.findElement(By.linkText(title)); 299 AjaxRequestManager arm = new AjaxRequestManager(driver); 300 arm.begin(); 301 WebElement element = item.findElement(By.xpath(CHECK_BOX_XPATH)); 302 assertFalse("Element with title=" + title + " is already selected", element.isSelected()); 303 Locator.scrollAndForceClick(element); 304 arm.end(); 305 break; 306 } catch (NoSuchElementException e) { 307 // next 308 } 309 } 310 } 311 return reload(id).getSelectionActions(); 312 } 313 314 /** 315 * @since 9.1 316 */ 317 public ContentViewElement unselectByTitle(String... titles) { 318 // get id before element is detached from DOM (during next ajax calls) 319 String id = getId(); 320 List<WebElement> items = getItems(); 321 for (WebElement item : items) { 322 for (String title : titles) { 323 try { 324 item.findElement(By.linkText(title)); 325 AjaxRequestManager arm = new AjaxRequestManager(driver); 326 arm.begin(); 327 WebElement element = item.findElement(By.xpath(CHECK_BOX_XPATH)); 328 assertTrue("Element with title=" + title + " is not selected", element.isSelected()); 329 Locator.scrollAndForceClick(element); 330 arm.end(); 331 break; 332 } catch (NoSuchElementException e) { 333 // next 334 } 335 } 336 } 337 return reload(id); 338 } 339 340 /** 341 * @since 8.3 342 * @deprecated since 9.1 use {@link #selectByIndex(int...)}/{@link #unselectByIndex(int...)} instead. 343 */ 344 @Deprecated 345 public ContentViewElement checkByIndex(int... indexes) { 346 // get id before element is detached from DOM (during next ajax calls) 347 String id = getId(); 348 AjaxRequestManager arm = new AjaxRequestManager(driver); 349 for (int i : indexes) { 350 arm.watchAjaxRequests(); 351 getItems().get(i).findElement(By.xpath(CHECK_BOX_XPATH)).click(); 352 arm.waitForAjaxRequests(); 353 } 354 return reload(id); 355 } 356 357 /** 358 * @since 9.1 359 */ 360 public ContentViewSelectionActions selectByIndex(int... indexes) { 361 // get id before element is detached from DOM (during next ajax calls) 362 String id = getId(); 363 AjaxRequestManager arm = new AjaxRequestManager(driver); 364 for (int i : indexes) { 365 arm.watchAjaxRequests(); 366 WebElement element = getItems().get(i).findElement(By.xpath(CHECK_BOX_XPATH)); 367 assertFalse("Element with id=" + i + " is already selected", element.isSelected()); 368 Locator.scrollAndForceClick(element); 369 arm.waitForAjaxRequests(); 370 } 371 return reload(id).getSelectionActions(); 372 } 373 374 /** 375 * @since 9.1 376 */ 377 public ContentViewElement unselectByIndex(int... indexes) { 378 // get id before element is detached from DOM (during next ajax calls) 379 String id = getId(); 380 AjaxRequestManager arm = new AjaxRequestManager(driver); 381 for (int i : indexes) { 382 arm.watchAjaxRequests(); 383 WebElement element = getItems().get(i).findElement(By.xpath(CHECK_BOX_XPATH)); 384 assertTrue("Element with id=" + i + " is not selected", element.isSelected()); 385 Locator.scrollAndForceClick(element); 386 arm.waitForAjaxRequests(); 387 } 388 return reload(id); 389 } 390 391 /** 392 * @since 8.3 393 * @deprecated since 9.1 use {@link #selectAll()}/{@link #unselectAll()} instead. 394 */ 395 @Deprecated 396 public ContentViewElement checkAllItems() { 397 WebElement selectAll = null; 398 try { 399 selectAll = getResultsPanel().findElement(By.xpath(SELECT_ALL_BUTTON_XPATH)); 400 } catch (NoSuchElementException e) { 401 // no item 402 } 403 if (selectAll != null) { 404 // get id before element is detached from DOM (during next ajax call) 405 String id = getId(); 406 AjaxRequestManager arm = new AjaxRequestManager(driver); 407 arm.begin(); 408 Locator.scrollAndForceClick(selectAll); 409 arm.end(); 410 return reload(id); 411 } 412 return this; 413 } 414 415 /** 416 * @since 9.1 417 */ 418 public ContentViewSelectionActions selectAll() { 419 WebElement selectAll = getResultsPanel().findElement(By.xpath(SELECT_ALL_BUTTON_XPATH)); 420 assertFalse("Select all Element is already selected", selectAll.isSelected()); 421 // get id before element is detached from DOM (during next ajax call) 422 String id = getId(); 423 AjaxRequestManager arm = new AjaxRequestManager(driver); 424 arm.begin(); 425 Locator.scrollAndForceClick(selectAll); 426 arm.end(); 427 return reload(id).getSelectionActions(); 428 } 429 430 /** 431 * CAUTION You can call this method only after a {@link #selectAll()}. 432 * 433 * @since 9.1 434 */ 435 public ContentViewElement unselectAll() { 436 WebElement selectAll = getResultsPanel().findElement(By.xpath(SELECT_ALL_BUTTON_XPATH)); 437 assertTrue("Select all Element is not selected", selectAll.isSelected()); 438 // get id before element is detached from DOM (during next ajax call) 439 String id = getId(); 440 AjaxRequestManager arm = new AjaxRequestManager(driver); 441 arm.begin(); 442 Locator.scrollAndForceClick(selectAll); 443 arm.end(); 444 return reload(id); 445 } 446 447 /** 448 * @since 8.3 449 * @deprecated since 9.1 use {@link #getUpperActions()} then 450 * {@link ContentViewUpperActions#getActionByTitle(String)} instead. Or use select methods directly. 451 */ 452 @Deprecated 453 public WebElement getSelectionActionByTitle(String title) { 454 return getUpperActions().getActionByTitle(title); 455 } 456 457 /** 458 * @since 8.4 459 */ 460 public ResultLayout getResultLayout() { 461 WebElement element = getElement(); 462 WebElement resultsPanel = getResultsPanel(); 463 String resultLayoutSelected = ".//span[@class=\"resultLayoutSelection selected\"]/*/img[@alt=\"%s\"]"; 464 if (Assert.hasChild(element, By.xpath(String.format(resultLayoutSelected, ResultLayout.THUMBNAIL.title))) 465 || Assert.hasChild(resultsPanel, By.xpath(".//div[contains(@class,'bubbleBox')]"))) { 466 return ResultLayout.THUMBNAIL; 467 } else if (Assert.hasChild(element, By.xpath(String.format(resultLayoutSelected, ResultLayout.LISTING.title))) 468 || Assert.hasChild(resultsPanel, By.xpath(".//table[@class='dataOutput']"))) { 469 return ResultLayout.LISTING; 470 } 471 throw new IllegalStateException("Content view is not listing nor thumbnail."); 472 } 473 474}