/**
* Constellio
* Copyright (C) 2010 DocuLibre inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.constellio.sdk.tests.selenium.adapters.base;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import com.constellio.sdk.tests.selenium.conditions.ActionWithTimeout;
import com.constellio.sdk.tests.selenium.conditions.ConditionWithTimeout;
@SuppressWarnings({ "unchecked" })
public abstract class WebDriverAdapter<WE extends WebElement> implements WebDriver, JavascriptExecutor {
protected WebDriver adapted;
public WebDriverAdapter(WebDriver driver) {
super();
this.adapted = driver;
}
protected abstract WE adapt(WebElementFinder<WebElement> factory);
@Override
public void close() {
adapted.close();
}
protected abstract void ensureNoApplicationException();
public List<WE> findAdaptElements(final By by) {
List<WE> adapters = new ArrayList<WE>();
int size = findElements(by).size();
for (int i = 0; i < size; i++) {
adapters.add(findElementAtIndex(by, i));
}
return Collections.unmodifiableList(adapters);
}
public WE find(String className) {
return findElement(By.className(className));
}
private WebElement nestedFindElement(By by) {
try {
return adapted.findElement(by);
} catch (Throwable t) {
String errorMessage = "Cannot find element " + by.toString().replace("By.", "by ");
throw new RuntimeException(errorMessage, t);
}
}
@Override
public WE findElement(final By by) {
ensureNoApplicationException();
WebElement element = nestedFindElement(by);
if (element == null) {
return null;
} else {
WebElementFinder<WebElement> factory = new WebElementFinder<WebElement>() {
@Override
public WebElement get() {
ensureNoApplicationException();
return WebDriverAdapter.this.getAdaptedDriver().findElement(by);
}
@Override
public String getOperationDescription() {
return "webDriver.find(" + by.toString() + ")";
}
};
factory.getUsingCache();
return adapt(factory);
}
}
public WE findElementAtIndex(final By by, final int index) {
WebElementFinder<WebElement> factory = new WebElementFinder<WebElement>() {
@Override
public WebElement get() {
ensureNoApplicationException();
return WebDriverAdapter.this.getAdaptedDriver().findElements(by).get(index);
}
@Override
public String getOperationDescription() {
return "webDriver.findElements(" + by.toString() + ")";
}
};
factory.getUsingCache();
return adapt(factory);
}
@Override
public List<WebElement> findElements(By by) {
return adapted.findElements(by);
}
public WE findRequiredElement(By by) {
WE element = findElement(by);
if (element == null) {
throw new RequiredElementNotFound(by);
}
return element;
}
public List<WE> findRequiredElements(By by) {
List<WE> adapters = findAdaptElements(by);
if (adapters.isEmpty()) {
throw new RequiredElementNotFound(by);
} else {
return adapters;
}
}
@Override
public void get(String url) {
adapted.get(url);
}
public WebDriver getAdaptedDriver() {
return adapted;
}
@Override
public String getCurrentUrl() {
return adapted.getCurrentUrl();
}
@Override
public String getPageSource() {
try {
return new ActionWithTimeout<String>() {
@Override
protected String execute()
throws Exception {
return adapted.getPageSource();
}
}.tryExecute(5000);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String getTitle() {
return adapted.getTitle();
}
@Override
public String getWindowHandle() {
return adapted.getWindowHandle();
}
@Override
public Set<String> getWindowHandles() {
return adapted.getWindowHandles();
}
@Override
public Options manage() {
return adapted.manage();
}
@Override
public Navigation navigate() {
return adapted.navigate();
}
@Override
public void quit() {
adapted.quit();
}
@Override
public TargetLocator switchTo() {
return adapted.switchTo();
}
@Override
public String toString() {
return adapted.toString();
}
public final void waitForCondition(ConditionWithTimeout condition) {
condition.waitForTrue(10000);
}
public final void waitForCondition(ConditionWithTimeout condition, long timeout) {
condition.waitForTrue(timeout);
}
public WE waitUntilElementExist(By by) {
return waitUntilElementExist(by, 10000);
}
public WE waitUntilElementExist(final By by, long timeout) {
final Object[] elementHolder = new Object[1];
new ConditionWithTimeout() {
@Override
protected boolean evaluate() {
WE element = findElement(by);
elementHolder[0] = element;
element.getLocation();
return element != null;
}
}.waitForTrue(timeout);
return (WE) elementHolder[0];
}
@Override
public Object executeScript(String script, Object... args) {
JavascriptExecutor executor = (JavascriptExecutor) adapted;
return executor.executeScript(script, convertScriptArguments(args));
}
@Override
public Object executeAsyncScript(String script, Object... args) {
JavascriptExecutor executor = (JavascriptExecutor) adapted;
return executor.executeAsyncScript(script, convertScriptArguments(args));
}
@SuppressWarnings("rawtypes")
private Object[] convertScriptArguments(Object[] arguments) {
Object[] convertedArguments = new Object[arguments.length];
for (int i = 0; i < arguments.length; i++) {
if (arguments[i] instanceof WebElementAdapter) {
convertedArguments[i] = ((WebElementAdapter) arguments[i]).getAdaptedElement();
} else {
convertedArguments[i] = arguments[i];
}
}
return convertedArguments;
}
public List<WE> getChildren() {
return findAdaptElements(By.xpath("*"));
}
public void scrollIntoView(WebElement webElement) {
executeScript("arguments[0].scrollIntoView();", webElement);
}
}