/*
* This is eMonocot, a global online biodiversity information resource.
*
* Copyright © 2011–2015 The Board of Trustees of the Royal Botanic Gardens, Kew and The University of Oxford
*
* eMonocot is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* eMonocot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* The complete text of the GNU Affero General Public License is in the source repository as the file
* ‘COPYING’. It is also available from <http://www.gnu.org/licenses/>.
*/
package org.emonocot.portal.driver;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.emonocot.portal.remoting.IdentificationKeyDaoImpl;
import org.emonocot.portal.remoting.ImageDaoImpl;
import org.emonocot.test.TestDataManager;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author ben
*/
public class PageObject {
private Pattern pattern = Pattern.compile("^(.*?);jsessionid=[A-Z0-9]+$");
/**
*
*/
@FindBy(how = How.TAG_NAME, using = "footer")
private WebElement foot;
/**
*
*/
@FindBy(how = How.ID_OR_NAME, using = "identify-box")
private WebElement identifyBox;
/**
*
*/
@FindBy(how = How.ID_OR_NAME, using = "classify-box")
private WebElement classifyBox;
/**
*
*/
@FindBy(how = How.CLASS_NAME, using = "navbar")
private WebElement nav;
/**
*
*/
private static final Integer AJAX_WAIT_STEP = 100;
/**
*
*/
private static Logger logger = LoggerFactory.getLogger(PageObject.class);
/**
* @return the identify link
*/
public final Identify selectIdentifyLink() {
return openAs(
identifyBox.findElement(By.linkText("identification features")).getAttribute("href"),
Identify.class);
}
/**
* @return the identify link
*/
public final Identify selectClassifyLink() {
return openAs(
classifyBox.findElement(By.linkText("classification features")).getAttribute("href"),
Identify.class);
}
/**
*
*/
@FindBy(how = How.TAG_NAME, using = "a")
private List<WebElement> links;
/**
*
*/
protected WebDriver webDriver;
/**
*
*/
protected ImageDaoImpl imageDao;
/**
*
*/
protected IdentificationKeyDaoImpl keyDao;
/**
*
*/
private String baseUri;
private String host;
private String basePath;
private int port;
/**
*
*/
protected TestDataManager testDataManager;
/**
* @param newBaseUri
* Set the base Uri
*/
public final void setBaseUri(final String newBaseUri) {
this.baseUri = newBaseUri;
}
/**
* @return the base uri
*/
public final String getBaseUri() {
return baseUri;
}
/**
* @param <T>
* The type of page
* @param address
* the url of the page
* @param pageClass
* the class of the page
* @return the page
*/
protected final <T extends PageObject> T openAs(final String address,
final Class<T> pageClass) {
open(address);
Pattern loginPattern = Pattern.compile(".*/login.*");
if (loginPattern.matcher(webDriver.getCurrentUrl()).matches()
&& !pageClass.equals(Login.class)) {
Login loginPage = pageObjectInstance(Login.class);
loginPage.setBaseUri(baseUri);
loginPage.testDataManager = this.testDataManager;
loginPage.webDriver = this.webDriver;
loginPage.imageDao = this.imageDao;
loginPage.keyDao = this.keyDao;
throw new RequiresLoginException(loginPage);
}
return getPage(pageClass);
}
/**
* @param <T>
* The type of page
* @param pageClass
* the class of the page
* @return the page
*/
protected final <T extends PageObject> T getPage(final Class<T> pageClass) {
T pageObject = pageObjectInstance(pageClass);
pageObject.setBaseUri(baseUri);
pageObject.setHost(host);
pageObject.setPort(port);
pageObject.setBasePath(basePath);
pageObject.testDataManager = this.testDataManager;
pageObject.webDriver = this.webDriver;
pageObject.imageDao = this.imageDao;
pageObject.keyDao = this.keyDao;
return pageObject;
}
/**
* @param initialPause
* Set the initial wait time
*/
public final void waitForAjax(final Integer initialPause) {
try {
Thread.sleep(initialPause);
while (true) {
Boolean ajaxIsComplete = (Boolean) ((JavascriptExecutor) webDriver)
.executeScript("return jQuery.active == 0");
if (ajaxIsComplete) {
break;
}
Thread.sleep(AJAX_WAIT_STEP);
}
} catch (InterruptedException ie) {
logger.error(ie.getMessage());
}
}
/**
* @param <T>
* The type of page
* @param pageClass
* Set the page class
* @return an instance of class T
*/
private <T extends PageObject> T pageObjectInstance(final Class<T> pageClass) {
return PageFactory.initElements(webDriver, pageClass);
}
/**
* @param address
* Set hte address
*/
private void open(final String address) {
webDriver.navigate().to(address);
}
/**
* @return the web driver
*/
public final WebDriver getWebDriver() {
return webDriver;
}
/**
* Assumption that we're handling authentication via tomcat and using
* Cookies.
*/
public final void disableAuthentication() {
Cookie cookie = webDriver.manage().getCookieNamed("jsessionid");
if (cookie != null) {
webDriver.manage().deleteCookie(cookie);
}
}
/**
* @return the current (baseURI-relative including preceding slash) uri or
* null if the URI is malformed
*/
public final String getUri() {
try {
java.net.URI uri = new java.net.URI(webDriver.getCurrentUrl());
String basePath = new java.net.URI(getBaseUri()).getPath();
String relPath = uri.getPath().replace(basePath, "");
relPath = relPath.startsWith("/") ? relPath.substring(1) : relPath;
Matcher matcher = pattern.matcher(relPath);
if(matcher.matches()) {
relPath = matcher.group(1);
}
return relPath;
} catch (java.net.URISyntaxException e) {
e.printStackTrace();
return null;
}
}
/**
* @return the login page
*/
public final Login selectLoginLink() {
return this.openAs(
nav.findElement(By.linkText("Sign in")).getAttribute("href"),
Login.class);
}
/**
* @return true, if the user is logged in
*/
public final Boolean loggedIn() {
WebElement userMenu = nav.findElement(By.cssSelector("#menuUser"));
return (userMenu != null);
}
/**
*
*/
public final void logOut() {
try {
openAs(getBaseUri() + "/logout", Index.class);
} catch (Exception e) {
logger.debug(e.getMessage());
}
}
/**
* @return the info message
*/
public final String getInfoMessage() {
WebElement webElement = webDriver.findElement(By
.cssSelector(".alert.info p"));
return webElement.getText();
}
/**
* @param text
* Set the link text
* @param clazz
* Set the expected page
* @return the page object
*/
public final PageObject selectLink(final String text,
final Class<? extends PageObject> clazz) {
return this.openAs(this.webDriver.findElement(By.linkText(text))
.getAttribute("href"), clazz);
}
/**
* @return the about page
*/
public final About selectAboutLink() {
return openAs(
foot.findElement(By.linkText("About us")).getAttribute("href"),
About.class);
}
public final TermsOfUse selectTermsOfUseLink() {
return openAs(
foot.findElement(By.linkText("Terms of Use")).getAttribute("href"),
TermsOfUse.class);
}
/**
* @return the contact page
*/
public final String getContactLink() {
return foot.findElement(By.xpath("div/div/div/ul/li/ul/li/a[@class='contactLinkOverlay']")).getAttribute("href");
}
/**
* @param text partial text of link to search for
* @return false if there is a NoSuchElementException is thrown
* true otherwise
*/
public final boolean isLinkPresent(String text) {
try {
webDriver.findElement(By.partialLinkText(text));
// if an element is found
return true;
} catch (NoSuchElementException e) {
return false;
}
}
/**
* @param text
* the text of the link
* @return the target of the link if it is found on this page
*/
public PageObject selectLink(String text) {
return selectLink(text, PageObject.class);
}
/**
* @param elementId
* @return Whether an element with this id is visible
*/
public boolean isElementVisible(String elementId) {
try {
WebElement element = webDriver.findElement(By.id(elementId));
return element.isDisplayed();
} catch (NoSuchElementException e) {
return false;
}
}
/**
* @return the footer icons arrangement
*/
public final List<List<String>> getFooterIconsArrangement() {
List<List<String>> returnRows = new ArrayList<List<String>>();
List<WebElement> footerRows = foot.findElement(By.id("footer-icons")).findElements(By.className("nav"));
for (WebElement we : footerRows) {
List<String> returnRow = new ArrayList<String>();
for (WebElement img : we.findElements(By.tagName("img"))) {
returnRow.add(img.getAttribute("alt"));
}
returnRows.add(returnRow);
}
return returnRows;
}
/**
* @param paragraphNameOrId
* @return
*/
public String paragraphText(String paragraphNameOrId) {
WebElement element = null;
try{
logger.info("Attempting to find element by id:" + paragraphNameOrId);
element = webDriver.findElement(By.id(paragraphNameOrId));
} catch (NoSuchElementException e0) {
logger.info("No element with id:" + paragraphNameOrId + ". Attempting to find element with this name");
try {
element = webDriver.findElement(By.name(paragraphNameOrId));
} catch (NoSuchElementException e1) {
logger.warn("Unable to find element with either id or name:" + paragraphNameOrId, e1);
element = null;
}
}
if(element == null) {
return null;
} else {
return element.getText();
}
}
/**
* @return The source of the page. Dependant on the implementing class, this
* can be the source when the page was retrieved, the page as modified by script
* or some other representation of the DOM
*/
public String getText() {
return webDriver.getPageSource();
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getBasePath() {
return basePath;
}
public void setBasePath(String basePath) {
this.basePath = basePath;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}