001/* 002 * (C) Copyright 2006-2011 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 * bstefanescu 018 */ 019package org.nuxeo.runtime.test.runner.web; 020 021import java.net.MalformedURLException; 022import java.net.URL; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027import javax.inject.Inject; 028 029import org.assertj.core.api.Assertions; 030import org.nuxeo.runtime.test.runner.FeaturesRunner; 031import org.openqa.selenium.By; 032import org.openqa.selenium.NotFoundException; 033import org.openqa.selenium.WebDriver; 034import org.openqa.selenium.WebDriverException; 035import org.openqa.selenium.WebElement; 036import org.openqa.selenium.support.PageFactory; 037import org.openqa.selenium.support.ui.ExpectedCondition; 038import org.openqa.selenium.support.ui.WebDriverWait; 039 040/** 041 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 042 */ 043public abstract class WebPage { 044 045 /** 046 * Can be used by tests as default timeouts. This way you can change these 047 * values to change all the timeout in the tests. DEFAULT_TIMEOUT is used 048 * for regular timeouts (loading an ajax page an ajax dialog etc.) while 049 * BIG_TIMEOUT should be used for pages that are slower (like the home of a 050 * GWT application) 051 */ 052 public static int DEFAULT_TIMEOUT = 5; 053 054 public static int BIG_TIMEOUT = 15; 055 056 private static final Map<Class<?>, WebPage> pages = new HashMap<>(); 057 058 @Inject 059 protected Configuration config; 060 061 @Inject 062 protected WebDriver driver; 063 064 @Inject 065 protected FeaturesRunner runner; 066 067 /** 068 * Should be overridden by dynamic page (using ajax) to wait until the page 069 * is completely loaded By default nothing is done (page is assumed to be 070 * loaded) 071 * 072 * @return the page itself 073 */ 074 public WebPage ensureLoaded() { 075 config.getBrowserFamily().getDriverFactory().waitForAjax(driver); 076 return this; 077 078 } 079 080 public Configuration getConfiguration() { 081 return config; 082 } 083 084 public WebDriver getDriver() { 085 return driver; 086 } 087 088 public FeaturesRunner getRunner() { 089 return runner; 090 } 091 092 public void home() { 093 driver.get(config.home); 094 } 095 096 public void to(String path) { 097 if (path.contains("://")) { 098 driver.get(path); 099 } else { 100 try { 101 URL url = new URL(new URL(config.home), path); 102 driver.navigate().to(url); 103 } catch (MalformedURLException e) { 104 throw new WebDriverException(e); 105 } 106 } 107 } 108 109 public boolean hasElement(final By by) { 110 try { 111 driver.findElement(by); 112 return true; 113 } catch (WebDriverException e) { 114 return false; 115 } 116 } 117 118 public boolean hasElement(final By by, int timeoutInSeconds) { 119 try { 120 findElement(by, timeoutInSeconds); 121 return true; 122 } catch (WebDriverException e) { 123 return false; 124 } 125 } 126 127 public WebElement findElement(final By by) { 128 return driver.findElement(by); 129 } 130 131 public List<WebElement> findElements(final By by) { 132 return driver.findElements(by); 133 } 134 135 public WebElement findElement(final By by, int timeOutInSeconds) { 136 return waitUntilElementFound(by, timeOutInSeconds); 137 } 138 139 public WebElement waitUntilElementFound(final By by, int timeOutInSeconds) { 140 try { 141 return findElement(by); // try once first 142 } catch (NotFoundException e) { 143 return new WebDriverWait(driver, timeOutInSeconds).until(new ExpectedCondition<WebElement>() { 144 @Override 145 public WebElement apply(WebDriver arg0) { 146 return driver.findElement(by); 147 } 148 }); 149 } 150 } 151 152 public void waitUntilElementNotFound(final By by, int timeOutInSeconds) { 153 try { 154 findElement(by); // try once first 155 new WebDriverWait(driver, timeOutInSeconds).until(new ExpectedCondition<Boolean>() { 156 @Override 157 public Boolean apply(WebDriver arg0) { 158 try { 159 driver.findElement(by); 160 return Boolean.FALSE; 161 } catch (NotFoundException e) { 162 return Boolean.TRUE; 163 } 164 } 165 }); 166 } catch (NotFoundException e) { 167 } 168 } 169 170 public <T extends WebPage> T getPage(Class<T> type) { 171 return getPage(runner, config, type); 172 } 173 174 @SuppressWarnings("unchecked") 175 public static <T extends WebPage> T getPage(FeaturesRunner runner, Configuration config, Class<T> type) { 176 T page = (T) pages.get(type); 177 if (page == null) { 178 synchronized (pages) { 179 page = (T) pages.get(type); 180 if (page != null) { 181 return page; 182 } 183 page = PageFactory.initElements(config.driver, type); 184 runner.getInjector().injectMembers(page); 185 pages.put(type, page); 186 } 187 } 188 return (T) page.ensureLoaded(); // this will block until page is loaded 189 // (if implementation needs this) 190 } 191 192 /** 193 * Gives access to an attachment retrieved from this web page. 194 * 195 */ 196 public Attachment getAttachment() { 197 Attachment attachment = ((TakesAttachment) driver).getAttachment(); 198 Assertions.assertThat(attachment).isNotNull(); 199 return attachment; 200 } 201 202 public static void flushPageCache() { 203 synchronized (pages) { 204 pages.clear(); 205 } 206 } 207 208}