View Javadoc

1   /*
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package edu.samplu.common;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.openqa.selenium.By;
21  import org.openqa.selenium.NoSuchFrameException;
22  import org.openqa.selenium.Proxy;
23  import org.openqa.selenium.WebDriver;
24  import org.openqa.selenium.chrome.ChromeDriver;
25  import org.openqa.selenium.chrome.ChromeDriverService;
26  import org.openqa.selenium.firefox.FirefoxDriver;
27  import org.openqa.selenium.firefox.FirefoxProfile;
28  import org.openqa.selenium.remote.CapabilityType;
29  import org.openqa.selenium.remote.DesiredCapabilities;
30  import org.openqa.selenium.remote.RemoteWebDriver;
31  import org.openqa.selenium.safari.SafariDriver;
32  
33  import com.thoughtworks.selenium.SeleneseTestBase;
34  
35  import java.io.File;
36  import java.net.MalformedURLException;
37  import java.net.URL;
38  import java.util.concurrent.TimeUnit;
39  
40  
41  /**
42   * The goal of the WebDriverUtil class is to invert the dependencies on WebDriver from WebDriverLegacyITBase for reuse
43   * without having to extend WebDriverLegacyITBase.  For the first example see waitFor
44   *
45   * @see WebDriverLegacyITBase
46   * @author Kuali Rice Team (rice.collab@kuali.org)
47   */
48  public class WebDriverUtil {
49  
50      /**
51       * TODO apparent dup WebDriverITBase.DEFAULT_WAIT_SEC
52       * TODO parametrize for JVM Arg
53       * 30 Seconds
54       */
55      public static int DEFAULT_IMPLICIT_WAIT_TIME = 30;
56  
57      /**
58       * TODO introduce SHORT_IMPLICIT_WAIT_TIME with param in WebDriverITBase
59       * TODO parametrize for JVM Arg
60       * 1 Second
61       */
62      public static int SHORT_IMPLICIT_WAIT_TIME = 1;
63  
64      /**
65       * Set -Dremote.driver.saucelabs for running on saucelabs
66       * @link https://wiki.kuali.org/display/KULRICE/How+To+Run+a+Selenium+Test for patch required
67       */
68      public static final String REMOTE_DRIVER_SAUCELABS_PROPERTY = "remote.driver.saucelabs";
69  
70      /**
71       * Selenium's webdriver.chrome.driver parameter, you can set -Dwebdriver.chrome.driver= or Rice's REMOTE_PUBLIC_CHROME
72       */
73      public static final String WEBDRIVER_CHROME_DRIVER = "webdriver.chrome.driver";
74  
75      /**
76       * Set -Dremote.public.chrome= or WEBDRIVER_CHROME_DRIVER
77       */
78      public static final String REMOTE_PUBLIC_CHROME = "remote.public.chrome";
79  
80      /**
81       * Time to wait for the URL used in setup to load.  Sometimes this is the first hit on the app and it needs a bit
82       * longer than any other.  120 Seconds.
83       * TODO parametrize for JVM Arg
84       */
85      public static final int SETUP_URL_LOAD_WAIT_SECONDS = 120;
86  
87      /**
88       * local proxy used for running tests thru jmeter.
89       * Include host name and port number. Example: localhost:7777
90       */
91      public static final String PROXY_HOST_PROPERTY = "remote.public.proxy";
92  
93      /**
94       * Setup the WebDriver test, login, and load the given web page
95       *
96       * @param username
97       * @param url
98       * @return driver
99       * @throws Exception
100      */
101     public static WebDriver setUp(String username, String url) throws Exception {
102         return setUp(username, url, null, null);
103     }
104 
105     /**
106      * Setup the WebDriver test, login, and load the given web page
107      *
108      * @param username
109      * @param url
110      * @param className
111      * @param testName
112      * @return driver
113      * @throws Exception
114      */
115     public static WebDriver setUp(String username, String url, String className, String testName) throws Exception {
116         WebDriver driver = null;
117         if (System.getProperty(REMOTE_DRIVER_SAUCELABS_PROPERTY) == null) {
118             driver = getWebDriver();
119 //        } else {
120 //            SauceLabsWebDriverHelper saucelabs = new SauceLabsWebDriverHelper();
121 //            saucelabs.setUp(className, testName);
122 //            driver = saucelabs.getDriver();
123         }
124         driver.manage().timeouts().implicitlyWait(SETUP_URL_LOAD_WAIT_SECONDS, TimeUnit.SECONDS);
125 
126         // TODO Got into the situation where the first url doesn't expect server, but all others do.  Readdress once
127         // the NavIT WDIT conversion has been completed.
128         if (!url.startsWith("http")) {
129             url = ITUtil.getBaseUrlString() + url;
130         }
131 
132         driver.get(url);
133         driver.manage().timeouts().implicitlyWait(DEFAULT_IMPLICIT_WAIT_TIME, TimeUnit.SECONDS);
134         return driver;
135     }
136 
137     /**
138      *
139      * @param passed
140      * @param sessionId
141      * @param testParam
142      * @param userParam
143      * @throws Exception
144      */
145     public static void tearDown(boolean passed, String sessionId, String testParam, String userParam) throws Exception {
146 
147 //        if (System.getProperty(SauceLabsWebDriverHelper.SAUCE_PROPERTY) != null) {
148 //            SauceLabsWebDriverHelper.tearDown(passed, sessionId, System.getProperty(SauceLabsWebDriverHelper.SAUCE_USER_PROPERTY),
149 //                    System.getProperty(SauceLabsWebDriverHelper.SAUCE_KEY_PROPERTY));
150 //        }
151 
152         if (System.getProperty(WebDriverLegacyITBase.REMOTE_PUBLIC_USERPOOL_PROPERTY) != null) {
153             ITUtil.getHTML(ITUtil.prettyHttp(System.getProperty(WebDriverLegacyITBase.REMOTE_PUBLIC_USERPOOL_PROPERTY) + "?test="
154                     + testParam + "&user=" + userParam));
155         }
156     }
157 
158     /**
159      *
160      * @param testParam
161      * @return
162      */
163     public static String determineUser(String testParam) {
164         String user = null;
165 
166         if (System.getProperty(WebDriverLegacyITBase.REMOTE_PUBLIC_USER_PROPERTY) != null) {
167             return System.getProperty(WebDriverLegacyITBase.REMOTE_PUBLIC_USER_PROPERTY);
168         } else if (System.getProperty(WebDriverLegacyITBase.REMOTE_PUBLIC_USERPOOL_PROPERTY) != null) { // deprecated
169             String userResponse = ITUtil.getHTML(ITUtil.prettyHttp(System.getProperty(
170                     WebDriverLegacyITBase.REMOTE_PUBLIC_USERPOOL_PROPERTY) + "?test=" + testParam.trim()));
171             return userResponse.substring(userResponse.lastIndexOf(":") + 2, userResponse.lastIndexOf("\""));
172         }
173 
174         return user;
175     }
176 
177     /***
178      * @link ITUtil#checkForIncidentReport
179      * @param driver
180      * @param locator
181      * @param message
182      */
183     public static void checkForIncidentReport(WebDriver driver, String locator, Failable failable,
184             String message) {
185         ITUtil.checkForIncidentReport(driver.getPageSource(), locator, failable, message);
186     }
187 
188     /**
189      * @link http://code.google.com/p/chromedriver/downloads/list
190      * @link #REMOTE_PUBLIC_CHROME
191      * @link #WEBDRIVER_CHROME_DRIVER
192      * @link ITUtil#HUB_DRIVER_PROPERTY
193      * @return chromeDriverService
194      */
195     public static ChromeDriverService chromeDriverCreateCheck() {
196         String driverParam = System.getProperty(ITUtil.HUB_DRIVER_PROPERTY);
197         // TODO can the saucelabs driver stuff be leveraged here?
198         if (driverParam != null && "chrome".equals(driverParam.toLowerCase())) {
199             if (System.getProperty(WEBDRIVER_CHROME_DRIVER) == null) {
200                 if (System.getProperty(REMOTE_PUBLIC_CHROME) != null) {
201                     System.setProperty(WEBDRIVER_CHROME_DRIVER, System.getProperty(REMOTE_PUBLIC_CHROME));
202                 }
203             }
204             try {
205                 ChromeDriverService chromeDriverService = new ChromeDriverService.Builder()
206                         .usingDriverExecutable(new File(System.getProperty(WEBDRIVER_CHROME_DRIVER)))
207                         .usingAnyFreePort()
208                         .build();
209                 return chromeDriverService;
210             } catch (Throwable t) {
211                 throw new RuntimeException("Exception starting chrome driver service, is chromedriver ( http://code.google.com/p/chromedriver/downloads/list ) installed? You can include the path to it using -Dremote.public.chrome", t)   ;
212             }
213         }
214         return null;
215     }
216 
217     /**
218      * remote.public.driver set to chrome or firefox (null assumes firefox)
219      * if remote.public.hub is set a RemoteWebDriver is created (Selenium Grid)
220      * if proxy.host is set, the web driver is setup to use a proxy
221      * @return WebDriver or null if unable to create
222      */
223     public static WebDriver getWebDriver() {
224         String driverParam = System.getProperty(ITUtil.HUB_DRIVER_PROPERTY);
225         String hubParam = System.getProperty(ITUtil.HUB_PROPERTY);
226         String proxyParam = System.getProperty(PROXY_HOST_PROPERTY);
227 
228         // setup proxy if specified as VM Arg
229         DesiredCapabilities capabilities = new DesiredCapabilities();
230         WebDriver webDriver = null;
231         if (StringUtils.isNotEmpty(proxyParam)) {
232             capabilities.setCapability(CapabilityType.PROXY, new Proxy().setHttpProxy(proxyParam));
233         }
234 
235         if (hubParam == null) {
236             if (driverParam == null || "firefox".equalsIgnoreCase(driverParam)) {
237                 FirefoxProfile profile = new FirefoxProfile();
238                 profile.setEnableNativeEvents(false);
239                 capabilities.setCapability(FirefoxDriver.PROFILE, profile);
240                 return new FirefoxDriver(capabilities);
241             } else if ("chrome".equalsIgnoreCase(driverParam)) {
242                 return new ChromeDriver(capabilities);
243             } else if ("safari".equals(driverParam)) {
244                 System.out.println("SafariDriver probably won't work, if it does please contact Erik M.");
245                 return new SafariDriver(capabilities);
246             }
247         } else {
248             try {
249                 if (driverParam == null || "firefox".equalsIgnoreCase(driverParam)) {
250                     return new RemoteWebDriver(new URL(ITUtil.getHubUrlString()), DesiredCapabilities.firefox());
251                 } else if ("chrome".equalsIgnoreCase(driverParam)) {
252                     return new RemoteWebDriver(new URL(ITUtil.getHubUrlString()), DesiredCapabilities.chrome());
253                 }
254             } catch (MalformedURLException mue) {
255                 System.out.println(ITUtil.getHubUrlString() + " " + mue.getMessage());
256                 mue.printStackTrace();
257             }
258         }
259         return null;
260     }
261 
262     /**
263      * If the JVM arg remote.autologin is set, auto login as admin will not be done.
264      * @param driver
265      * @param userName
266      * @param failable
267      * @throws InterruptedException
268      */
269     public static void login(WebDriver driver, String userName, Failable failable) throws InterruptedException {
270         if (System.getProperty(ITUtil.REMOTE_AUTOLOGIN_PROPERTY) == null) {
271             driver.findElement(By.name("__login_user")).clear();
272             driver.findElement(By.name("__login_user")).sendKeys(userName);
273             driver.findElement(By.cssSelector("input[type=\"submit\"]")).click();
274             Thread.sleep(1000);
275             String contents = driver.getPageSource();
276             ITUtil.failOnInvalidUserName(userName, contents, failable);
277         }
278     }
279 
280     protected static void selectFrameSafe(WebDriver driver, String locator) {
281         try {
282             driver.switchTo().frame(locator);
283         } catch (NoSuchFrameException nsfe) {
284             // don't fail
285         }
286     }
287 
288     /**
289      * Wait for the given amount of seconds, for the given by, using the given driver.  The message is displayed if the
290      * by cannot be found.  No action is performed on the by, so it is possible that the by found is not visible or enabled.
291      *
292      * @param driver WebDriver
293      * @param waitSeconds int
294      * @param by By
295      * @param message String
296      * @throws InterruptedException
297      */
298     public static void waitFor(WebDriver driver, int waitSeconds, By by, String message) throws InterruptedException {
299         driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
300         Thread.sleep(1000);
301         driver.findElement(by);  // NOTICE just the find, no action, so by is found, but might not be visible or enabled.
302         driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
303     }
304     
305     public static void failOnMatchedJira(String contents, Failable failable) {
306         JiraAwareFailureUtil.failOnMatchedJira(contents, failable);
307     }
308     
309     private static void failWithReportInfoForKim(String contents, String linkLocator, String message) {
310         final String kimIncidentReport = extractIncidentReportKim(contents, linkLocator, message);
311         SeleneseTestBase.fail(kimIncidentReport);
312     }
313     
314     private static String extractIncidentReportKim(String contents, String linkLocator, String message) {
315         String chunk =  contents.substring(contents.indexOf("id=\"headerarea\""), contents.lastIndexOf("</div>") );
316         String docIdPre = "type=\"hidden\" value=\"";
317         String docId = chunk.substring(chunk.indexOf(docIdPre) + docIdPre.length(), chunk.indexOf("\" name=\"documentId\""));
318 
319         String stackTrace = chunk.substring(chunk.lastIndexOf("name=\"displayMessage\""), chunk.length());
320         String stackTracePre = "value=\"";
321         stackTrace = stackTrace.substring(stackTrace.indexOf(stackTracePre) + stackTracePre.length(), stackTrace.indexOf("name=\"stackTrace\"") - 2);
322 
323         return "\nIncident report "+ message+ " navigating to "+ linkLocator + " Doc Id: "+ docId.trim()+ "\nStackTrace: "+ stackTrace.trim();
324     }
325     
326     private static void processIncidentReport(String contents, String linkLocator, Failable failable, String message) {
327         failOnMatchedJira(contents, failable);
328 
329         if (contents.indexOf("Incident Feedback") > -1) {
330             failWithReportInfo(contents, linkLocator, message);
331         }
332 
333         if (contents.indexOf("Incident Report") > -1) { // KIM incident report
334             failWithReportInfoForKim(contents, linkLocator, message);
335         }
336 
337         SeleneseTestBase.fail("\nIncident report detected " + message + "\n Unable to parse out details for the contents that triggered exception: " + deLinespace(
338                 contents));
339     }
340 
341     private static void failWithReportInfo(String contents, String linkLocator, String message) {
342         final String incidentReportInformation = extractIncidentReportInfo(contents, linkLocator, message);
343         SeleneseTestBase.fail(incidentReportInformation);
344     }
345     
346     private static String extractIncidentReportInfo(String contents, String linkLocator, String message) {
347         String chunk =  contents.substring(contents.indexOf("Incident Feedback"), contents.lastIndexOf("</div>") );
348         String docId = chunk.substring(chunk.lastIndexOf("Document Id"), chunk.indexOf("View Id"));
349         docId = docId.substring(0, docId.indexOf("</span>"));
350         docId = docId.substring(docId.lastIndexOf(">") + 2, docId.length());
351 
352         String viewId = chunk.substring(chunk.lastIndexOf("View Id"), chunk.indexOf("Error Message"));
353         viewId = viewId.substring(0, viewId.indexOf("</span>"));
354         viewId = viewId.substring(viewId.lastIndexOf(">") + 2, viewId.length());
355 
356         String stackTrace = chunk.substring(chunk.lastIndexOf("(only in dev mode)"), chunk.length());
357         stackTrace = stackTrace.substring(stackTrace.indexOf("<span id=\"") + 3, stackTrace.length());
358         stackTrace = stackTrace.substring(stackTrace.indexOf("\">") + 2, stackTrace.indexOf("</span>"));
359     
360         return "\nIncident report "+ message+ " navigating to "+ linkLocator+ " : View Id: "+ viewId.trim()+ " Doc Id: "+ docId.trim()+ "\nStackTrace: "+ stackTrace.trim();
361     }
362     
363     public static String deLinespace(String contents) {
364         while (contents.contains("\n\n")) {
365             contents = contents.replaceAll("\n\n", "\n");
366         }
367         
368         return contents;
369     }
370 }