/*
* (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* bstefanescu
*/
package org.nuxeo.runtime.test.runner.web;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.assertj.core.api.Assertions;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.openqa.selenium.By;
import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
/**
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*/
public abstract class WebPage {
/**
* Can be used by tests as default timeouts. This way you can change these
* values to change all the timeout in the tests. DEFAULT_TIMEOUT is used
* for regular timeouts (loading an ajax page an ajax dialog etc.) while
* BIG_TIMEOUT should be used for pages that are slower (like the home of a
* GWT application)
*/
public static int DEFAULT_TIMEOUT = 5;
public static int BIG_TIMEOUT = 15;
private static final Map<Class<?>, WebPage> pages = new HashMap<>();
@Inject
protected Configuration config;
@Inject
protected WebDriver driver;
@Inject
protected FeaturesRunner runner;
/**
* Should be overridden by dynamic page (using ajax) to wait until the page
* is completely loaded By default nothing is done (page is assumed to be
* loaded)
*
* @return the page itself
*/
public WebPage ensureLoaded() {
config.getBrowserFamily().getDriverFactory().waitForAjax(driver);
return this;
}
public Configuration getConfiguration() {
return config;
}
public WebDriver getDriver() {
return driver;
}
public FeaturesRunner getRunner() {
return runner;
}
public void home() {
driver.get(config.home);
}
public void to(String path) {
if (path.contains("://")) {
driver.get(path);
} else {
try {
URL url = new URL(new URL(config.home), path);
driver.navigate().to(url);
} catch (MalformedURLException e) {
throw new WebDriverException(e);
}
}
}
public boolean hasElement(final By by) {
try {
driver.findElement(by);
return true;
} catch (WebDriverException e) {
return false;
}
}
public boolean hasElement(final By by, int timeoutInSeconds) {
try {
findElement(by, timeoutInSeconds);
return true;
} catch (WebDriverException e) {
return false;
}
}
public WebElement findElement(final By by) {
return driver.findElement(by);
}
public List<WebElement> findElements(final By by) {
return driver.findElements(by);
}
public WebElement findElement(final By by, int timeOutInSeconds) {
return waitUntilElementFound(by, timeOutInSeconds);
}
public WebElement waitUntilElementFound(final By by, int timeOutInSeconds) {
try {
return findElement(by); // try once first
} catch (NotFoundException e) {
return new WebDriverWait(driver, timeOutInSeconds).until(new ExpectedCondition<WebElement>() {
@Override
public WebElement apply(WebDriver arg0) {
return driver.findElement(by);
}
});
}
}
public void waitUntilElementNotFound(final By by, int timeOutInSeconds) {
try {
findElement(by); // try once first
new WebDriverWait(driver, timeOutInSeconds).until(new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver arg0) {
try {
driver.findElement(by);
return Boolean.FALSE;
} catch (NotFoundException e) {
return Boolean.TRUE;
}
}
});
} catch (NotFoundException e) {
}
}
public <T extends WebPage> T getPage(Class<T> type) {
return getPage(runner, config, type);
}
@SuppressWarnings("unchecked")
public static <T extends WebPage> T getPage(FeaturesRunner runner, Configuration config, Class<T> type) {
T page = (T) pages.get(type);
if (page == null) {
synchronized (pages) {
page = (T) pages.get(type);
if (page != null) {
return page;
}
page = PageFactory.initElements(config.driver, type);
runner.getInjector().injectMembers(page);
pages.put(type, page);
}
}
return (T) page.ensureLoaded(); // this will block until page is loaded
// (if implementation needs this)
}
/**
* Gives access to an attachment retrieved from this web page.
*
*/
public Attachment getAttachment() {
Attachment attachment = ((TakesAttachment) driver).getAttachment();
Assertions.assertThat(attachment).isNotNull();
return attachment;
}
public static void flushPageCache() {
synchronized (pages) {
pages.clear();
}
}
}