View Javadoc

1   /**
2    * Copyright 2005-2012 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  package edu.samplu.common;
17  
18  import com.thoughtworks.selenium.Selenium;
19  import org.apache.commons.lang.RandomStringUtils;
20  import org.junit.Assert;
21  import org.openqa.selenium.By;
22  import org.openqa.selenium.NoSuchFrameException;
23  import org.openqa.selenium.WebDriver;
24  import org.openqa.selenium.chrome.ChromeDriver;
25  import org.openqa.selenium.firefox.FirefoxDriver;
26  import org.openqa.selenium.firefox.FirefoxProfile;
27  import org.openqa.selenium.remote.DesiredCapabilities;
28  import org.openqa.selenium.remote.RemoteWebDriver;
29  
30  import java.io.PrintWriter;
31  import java.io.StringWriter;
32  import java.net.MalformedURLException;
33  import java.net.URL;
34  import java.net.URLEncoder;
35  import java.util.Calendar;
36  import java.util.HashMap;
37  import java.util.Iterator;
38  import java.util.Map;
39  
40  import static com.thoughtworks.selenium.SeleneseTestBase.fail;
41  import static org.junit.Assert.assertEquals;
42  
43  /**
44   * Common selenium test methods that should be reused rather than recreated for each test.
45   * @author Kuali Rice Team (rice.collab@kuali.org)
46   */
47  
48  public class ITUtil {
49  
50      public static final String KUALI_PORTAL_TITLE = "Kuali Portal Index";
51      public static final String DEFAULT_BASE_URL = "http://localhost:8080/kr-dev";
52      public final static String PORTAL = "/portal.do";
53      public final static String PORTAL_URL =  ITUtil.getBaseUrlString() + ITUtil.PORTAL;
54      public final static String PORTAL_URL_ENCODED = URLEncoder.encode(PORTAL_URL);
55      public static final String DTS = Calendar.getInstance().getTimeInMillis() + "";
56      public static final String DTS_TWO = Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase();
57      public static String WAIT_TO_END_TEST = "5000";
58      public static final String DIV_ERROR_LOCATOR = "//div[@class='error']";
59      public static final String DIV_EXCOL_LOCATOR = "//div[@class='msg-excol']";
60      public static final int WAIT_DEFAULT_SECONDS = 60;
61      public static final String DEFAULT_WAIT_FOR_PAGE_TO_LOAD_TIMEOUT = "30000";
62      static Map<String, String> jiraMatches;
63      public static final String REMOTE_PUBLIC_URL_PROPERTY = "remote.public.url";
64      public static final String REMOTE_AUTOLOGIN_PROPERTY = "remote.autologin";
65      public static final String HUB_PROPERTY = "remote.public.hub";
66      public static final String HUB_DRIVER_PROPERTY = "remote.public.driver";
67      public static final String HUB_URL_PROPERTY = "http://localhost:4444/wd/hub";
68      public static final String DONT_TEAR_DOWN_PROPERTY = "remote.driver.dontTearDown";
69  
70      static {
71          jiraMatches = new HashMap<String, String>();
72          jiraMatches.put("Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'refreshWhenChanged' of bean class [org.kuali.rice.krad.uif.element.Action]: Bean property 'refreshWhenChanged' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?",
73                  "KULRICE-8137 Agenda Rule edit Incident report Invalid property 'refreshWhenChanged'");
74  
75          jiraMatches.put("org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase.processAddCollectionLineBusinessRules(MaintenanceDocumentRuleBase.",
76                  "KULRICE-8142 NPE in MaintenanceDocumentRuleBase.processAddCollectionLineBusinessRules");
77  
78          jiraMatches.put("at org.kuali.rice.krad.rules.DocumentRuleBase.isDocumentOverviewValid(DocumentRuleBase.",
79                  "KULRICE-8134 NPE in DocumentRuleBase.isDocumentOverviewValid(DocumentRuleBase");
80  
81          jiraMatches.put("org.kuali.rice.krad.uif.layout.TableLayoutManager.buildLine(TableLayoutManager.",
82                  "KULRICE-8160 NPE at TableLayoutManager.buildLine(TableLayoutManager");
83  
84          jiraMatches.put("Bean property 'configFileLocations' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?",
85                  "KULRICE-8173 Bean property 'configFileLocations' is not writable or has an invalid setter method");
86  
87          jiraMatches.put("Bean property 'componentSecurity' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?",
88                  "KULRICE-8182 JDK7 Bean property 'componentSecurity' is not readable...");
89  
90          jiraMatches.put("java.sql.SQLSyntaxErrorException: ORA-00904: \"ROUTEHEADERID\": invalid identifier",
91                  "KULRICE-8277 Several ITs fail with OJB operation; bad SQL grammar []; nested exception is java.sql.SQLException: ORA-00904: \"ROUTEHEADERID\": invalid identifier");
92  //        jiraMatches.put("",
93  //                "");
94  
95      }
96  
97      /**
98       * "FINAL", selenium.getText("//table[@id='row']/tbody/tr[1]/td[4]"
99       * @param selenium
100      * @param docId
101      */
102     public static void assertDocFinal(Selenium selenium, String docId) {
103         docId= "link=" + docId;
104         if(selenium.isElementPresent(docId)){
105             assertEquals("FINAL", selenium.getText("//table[@id='row']/tbody/tr[1]/td[4]"));
106         }else{
107             assertEquals(docId, selenium.getText("//table[@id='row']/tbody/tr[1]/td[1]"));
108             assertEquals("FINAL", selenium.getText("//table[@id='row']/tbody/tr[1]/td[4]"));
109         }
110     }
111 
112     protected static String blanketApprovalCleanUpErrorText(String errorText) {
113         errorText = errorText.replace("* required field", "").replace("\n", " ").trim(); // bit of extra ui text we don't care about
114         return errorText;
115     }
116 
117     /**
118      * Generic blanket approve behavior
119      * @param selenium
120      * @throws InterruptedException
121      */
122     public static void blanketApprove(Selenium selenium) throws InterruptedException {
123         ITUtil.checkForIncidentReport(selenium, "methodToCall.blanketApprove");
124         ITUtil.waitAndClick(selenium, "methodToCall.blanketApprove");
125         selenium.waitForPageToLoad(DEFAULT_WAIT_FOR_PAGE_TO_LOAD_TIMEOUT);
126         Thread.sleep(2000);
127 
128         if (selenium.isElementPresent(DIV_ERROR_LOCATOR)) {
129             String errorText = selenium.getText(DIV_ERROR_LOCATOR);
130             if (errorText != null && errorText.contains("error(s) found on page.")) {
131                 errorText = blanketApprovalCleanUpErrorText(errorText);
132                 if (selenium.isElementPresent(DIV_EXCOL_LOCATOR)) { // not present if errors are at the bottom of the page (see left-errmsg below)
133                     errorText = blanketApprovalCleanUpErrorText(selenium.getText(DIV_EXCOL_LOCATOR));// + "\n" + selenium.getHtmlSource()); // replacing errorText as DIV_EXCOL_LOCATOR includes the error count
134                 }
135                 if (selenium.isElementPresent("//div[@class='left-errmsg-tab']/div/div")) {
136                     errorText = errorText + blanketApprovalCleanUpErrorText(selenium.getText("//div[@class='left-errmsg-tab']/div/div"));
137                 }
138 
139                 //                if (selenium.isElementPresent("//div[@class='left-errmsg']/div")) {
140                 //                    errorText = errorText + " " + selenium.getText("//div[@class='left-errmsg']/div/div[1]");
141                 //                }
142                 Assert.fail(errorText);
143             }
144         }
145         ITUtil.checkForIncidentReport(selenium, "//img[@alt='doc search']");
146         waitAndClick(selenium, "//img[@alt='doc search']");
147         selenium.waitForPageToLoad(DEFAULT_WAIT_FOR_PAGE_TO_LOAD_TIMEOUT);
148         assertEquals("Kuali Portal Index", selenium.getTitle());
149         try {
150             selenium.selectFrame("iframeportlet");
151         } catch (NoSuchFrameException nsfe) {
152             // do nothing don't fail on missing frames
153         }
154         selenium.click("//input[@name='methodToCall.search' and @value='search']");
155         selenium.waitForPageToLoad(DEFAULT_WAIT_FOR_PAGE_TO_LOAD_TIMEOUT);
156     }
157 
158     /**
159      * "//li[@class='uif-errorMessageItem']"
160      * @param selenium
161      * @param message
162      */
163     public static void checkErrorMessageItem(Selenium selenium, String message) {
164         final String error_locator = "//li[@class='uif-errorMessageItem']";
165         if (selenium.isElementPresent(error_locator)) {
166             String errorText = selenium.getText(error_locator);
167             if (errorText != null && errorText.contains("errors")) {
168                 Assert.fail(errorText + message);
169             }
170         }
171     }
172 
173 
174     /**
175      * In order to run as a smoke test the ability to set the baseUrl via the JVM arg remote.public.url is required.
176      * Trailing slashes are trimmed.  If the remote.public.url does not start with http:// it will be added.
177      * @return http://localhost:8080/kr-dev by default else the value of remote.public.url
178      */
179     public static String getBaseUrlString() {
180         String baseUrl = System.getProperty(REMOTE_PUBLIC_URL_PROPERTY);
181         if (baseUrl == null) {
182             baseUrl = DEFAULT_BASE_URL;
183         }
184         baseUrl = prettyHttp(baseUrl);
185         return baseUrl;
186     }
187 
188     /**
189      * Append http:// if not present.  Remove trailing /
190      * @param baseUrl
191      * @return
192      */
193     public static String prettyHttp(String baseUrl) {
194         if (baseUrl.endsWith("/")) {
195             baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
196         }
197         if (!baseUrl.startsWith("http")) {
198             baseUrl = "http://" + baseUrl;
199         }
200         return baseUrl;
201     }
202 
203     /**
204      * In order to run as a smoke test under selenium grid the ability to set the hubUrl via the JVM arg remote.public.hub is required.
205      * Trailing slashes are trimmed.  If the remote.public.hub does not start with http:// it will be added.
206      * @return http://localhost:4444/wd/hub by default else the value of remote.public.hub
207      */
208     public static String getHubUrlString() {
209         String hubUrl = System.getProperty(HUB_PROPERTY);
210         if (hubUrl == null) {
211             hubUrl = HUB_URL_PROPERTY;
212         }
213         hubUrl = prettyHttp(hubUrl);
214         if (!hubUrl.endsWith("/wd/hub")) {
215             hubUrl = hubUrl + "/wd/hub";
216         }
217         return hubUrl;
218     }
219 
220     /**
221      * remote.public.driver set to chrome or firefox (null assumes firefox)
222      * if remote.public.hub is set a RemoteWebDriver is created (Selenium Grid)
223      * @return WebDriver or null if unable to create
224      */
225     public static WebDriver getWebDriver() {
226         String driverParam = System.getProperty(HUB_DRIVER_PROPERTY);
227         String hubParam = System.getProperty(HUB_PROPERTY);
228         if (hubParam == null) {
229             if (driverParam == null || "firefox".equalsIgnoreCase(driverParam)) {
230                 FirefoxProfile profile = new FirefoxProfile();
231                 profile.setEnableNativeEvents(false);
232                 return new FirefoxDriver(profile);
233             } else if ("chrome".equalsIgnoreCase(driverParam)) {
234                 return new ChromeDriver();
235             }
236         } else {
237             try {
238                 if (driverParam == null || "firefox".equalsIgnoreCase(driverParam)) {
239                     return new RemoteWebDriver(new URL(ITUtil.getHubUrlString()), DesiredCapabilities.firefox());
240                 } else if ("chrome".equalsIgnoreCase(driverParam)) {
241                     return new RemoteWebDriver(new URL(ITUtil.getHubUrlString()), DesiredCapabilities.chrome());
242                 }
243             } catch (MalformedURLException mue) {
244                 System.out.println(ITUtil.getHubUrlString() + " " + mue.getMessage());
245                 mue.printStackTrace();
246             }
247         }
248         return null;
249     }
250 
251     /**
252      * If the JVM arg remote.autologin is set, auto login as admin will not be done.
253      * @param selenium to login with
254      */
255     public static void loginSe(Selenium selenium) {
256         loginSe(selenium, "admin");
257     }
258 
259     /**
260      * If the JVM arg remote.autologin is set, auto login as admin will not be done.
261      * @param driver
262      * @param userName
263      * @throws InterruptedException
264      */
265     public static void login(WebDriver driver, String userName) throws InterruptedException {
266         if (System.getProperty(REMOTE_AUTOLOGIN_PROPERTY) == null) {
267             driver.findElement(By.name("__login_user")).clear();
268             driver.findElement(By.name("__login_user")).sendKeys(userName);
269             driver.findElement(By.cssSelector("input[type=\"submit\"]")).click();
270             Thread.sleep(1000);
271             String contents = driver.getPageSource();
272             checkForInvalidUserName(userName, contents);
273         }
274     }
275 
276     private static void checkForInvalidUserName(String userName, String contents) {
277         if (contents.indexOf("Invalid username") > -1) {
278             Assert.fail("Invalid username " + userName);
279         }
280     }
281 
282     /**
283      * If the JVM arg remote.autologin is set, auto login as admin will not be done.
284      * @param selenium to login with
285      */
286     public static void loginSe(Selenium selenium, String user) {
287         if (System.getProperty(REMOTE_AUTOLOGIN_PROPERTY) == null) {
288             try {
289                 selenium.waitForPageToLoad(DEFAULT_WAIT_FOR_PAGE_TO_LOAD_TIMEOUT);
290             } catch (Exception e) {
291                 Assert.fail("Login page not loaded app started?");
292             }
293             if (!"Login".equals(selenium.getTitle())) {
294                 fail("Title is not Login as expected, but " + selenium.getTitle());
295             }
296             selenium.type("__login_user", user);
297             selenium.click("//input[@type='submit']"); //using css selector fails
298             selenium.waitForPageToLoad(DEFAULT_WAIT_FOR_PAGE_TO_LOAD_TIMEOUT);
299             String contents = selenium.getHtmlSource();
300             checkForInvalidUserName(user, contents);
301         }
302     }
303 
304     /**
305      * Write the given stack trace into a String
306      * @param throwable whose stack trace to return
307      * @return String of the given throwable's stack trace.
308      */
309     public static String stackTrace(Throwable throwable) {
310         StringWriter wrt=new StringWriter();
311         PrintWriter pw=new PrintWriter(wrt);
312         throwable.printStackTrace(pw);
313         pw.flush();
314         return wrt.toString();
315     }
316 
317     /**
318      * Setting the JVM arg remote.driver.dontTearDown to y or t leaves the browser window open when the test has completed.  Valuable when debugging, updating, or creating new tests.
319      * When implementing your own tearDown method rather than an inherited one, it is a common courtesy to include this check and not stop and shutdown the browser window to make it easy debug or update your test.
320      * {@code }
321      * @return true if the dontTearDownProperty is not set.
322      */
323     public static boolean dontTearDownPropertyNotSet() {
324         return System.getProperty(DONT_TEAR_DOWN_PROPERTY) == null ||
325                 "f".startsWith(System.getProperty(DONT_TEAR_DOWN_PROPERTY).toLowerCase()) ||
326                 "n".startsWith(System.getProperty(DONT_TEAR_DOWN_PROPERTY).toLowerCase());
327     }
328 
329     /**
330      * Wait 60 seconds for the elementLocator to be present or fail.  Click if present
331      * @param selenium
332      * @param elementLocator
333      * @throws InterruptedException
334      */
335     public static void waitAndClick(Selenium selenium, String elementLocator) throws InterruptedException {
336         waitAndClick(selenium, elementLocator, WAIT_DEFAULT_SECONDS);
337     }
338 
339     /**
340      * Wait 60 seconds for the elementLocator to be present or fail.  Click if present
341      * @param selenium
342      * @param elementLocator
343      * @param message
344      * @throws InterruptedException
345      */
346     public static void waitAndClick(Selenium selenium, String elementLocator, String message) throws InterruptedException {
347         waitAndClick(selenium, elementLocator, WAIT_DEFAULT_SECONDS, message);
348     }
349 
350     /**
351      * Wait the given seconds for the elementLocator to be present or fail
352      * @param selenium
353      * @param elementLocator
354      * @param seconds
355      * @throws InterruptedException
356      */
357     public static void waitAndClick(Selenium selenium, String elementLocator, int seconds) throws InterruptedException {
358         waitAndClick(selenium, elementLocator, seconds, "");
359     }
360 
361     /**
362      * Wait the given seconds for the elementLocator to be present or fail
363      * @param selenium
364      * @param elementLocator
365      * @param seconds
366      * @param message
367      * @throws InterruptedException
368      */
369     public static void waitAndClick(Selenium selenium, String elementLocator, int seconds, String message) throws InterruptedException {
370         waitForElement(selenium, elementLocator, seconds, message);
371         selenium.click(elementLocator);
372         Thread.sleep(1000);
373         ITUtil.checkForIncidentReport(selenium, elementLocator, message);
374     }
375 
376     /**
377      * Wait the 60 seconds for the elementLocator to be present or fail, when present type the text.
378      * @param selenium
379      * @param elementLocator
380      * @param text
381      * @throws InterruptedException
382      */
383     public static void waitAndType(Selenium selenium, String elementLocator, String text) throws InterruptedException {
384         waitAndType(selenium, elementLocator, text, "");
385     }
386 
387     /**
388      * Wait the 60 seconds for the elementLocator to be present or fail, when present type the text.  Include failure message on fail.
389      * @param selenium
390      * @param elementLocator
391      * @param text
392      * @param message
393      * @throws InterruptedException
394      */
395     public static void waitAndType(Selenium selenium, String elementLocator, String text, String message) throws InterruptedException {
396         waitAndType(selenium, elementLocator, WAIT_DEFAULT_SECONDS, text, message);
397     }
398 
399     /**
400      * Wait the given seconds for the elementLocator to be present or fail, when present type the text.
401      * @param selenium
402      * @param elementLocator
403      * @param seconds
404      * @param text
405      * @param message
406      * @throws InterruptedException
407      */
408     public static void waitAndType(Selenium selenium, String elementLocator, int seconds, String text, String message) throws InterruptedException {
409         waitForElement(selenium, elementLocator, seconds, message);
410         selenium.type(elementLocator, text);
411         Thread.sleep(1000);
412     }
413 
414     /**
415      * Wait 60 seconds for the elementLocator to be present or fail
416      * @param selenium
417      * @param elementLocator
418      * @throws InterruptedException
419      */
420     public static void waitForElement(Selenium selenium, String elementLocator) throws InterruptedException {
421         waitForElement(selenium, elementLocator, WAIT_DEFAULT_SECONDS);
422     }
423 
424     /**
425      * Wait 60 seconds for the elementLocator to be present or fail
426      * @param selenium
427      * @param elementLocator
428      * @param message
429      * @throws InterruptedException
430      */
431     public static void waitForElement(Selenium selenium, String elementLocator, String message) throws InterruptedException {
432         waitForElement(selenium, elementLocator, WAIT_DEFAULT_SECONDS, message);
433     }
434 
435     /**
436      * Wait the given seconds for the elementLocator to be present or fail
437      * @param selenium
438      * @param elementLocator
439      * @param seconds
440      * @throws InterruptedException
441      */
442     public static void waitForElement(Selenium selenium, String elementLocator, int seconds) throws InterruptedException {
443         waitForElement(selenium, elementLocator, WAIT_DEFAULT_SECONDS, "");
444     }
445 
446     /**
447      * Wait the given seconds for the elementLocator to be present or fail
448      * @param selenium
449      * @param elementLocator
450      * @param seconds
451      * @param message
452      * @throws InterruptedException
453      */
454     public static void waitForElement(Selenium selenium, String elementLocator, int seconds, String message) throws InterruptedException {
455         boolean failed = false;
456         for (int second = 0;; second++) {
457             if (second >= seconds) failed = true;
458             try { if (failed || selenium.isElementPresent(elementLocator)) break; } catch (Exception e) {}
459             Thread.sleep(1000);
460         }
461         ITUtil.checkForIncidentReport(selenium, elementLocator); // after timeout to be sure page is loaded
462         if (failed) fail("timeout of " + seconds + " seconds waiting for " + elementLocator + " " + message);
463     }
464 
465     /**
466      * Wait the given seconds for the elementLocator to be present or fail
467      * @param selenium
468      * @param elementLocator
469      * @throws InterruptedException
470      */
471     public static void waitForElementVisible(Selenium selenium, String elementLocator) throws InterruptedException {
472         waitForElementVisible(selenium, elementLocator, WAIT_DEFAULT_SECONDS, "");
473     }
474 
475     /**
476      * Wait 60 seconds for the elementLocator to be present or fail including the given message
477      * @param selenium
478      * @param elementLocator
479      * @param message
480      * @throws InterruptedException
481      */
482     public static void waitForElementVisible(Selenium selenium, String elementLocator, String message) throws InterruptedException {
483         waitForElementVisible(selenium, elementLocator, WAIT_DEFAULT_SECONDS, message);
484     }
485 
486     /**
487      * Wait the given seconds for the elementLocator to be present or fail
488      * @param selenium
489      * @param elementLocator
490      * @param seconds
491      * @throws InterruptedException
492      */
493     public static void waitForElementVisible(Selenium selenium, String elementLocator, int seconds, String message) throws InterruptedException {
494         for (int second = 0;; second++) {
495             if (second >= seconds) fail("timeout of " + seconds + " seconds waiting for " + elementLocator + " " + message);
496             try { if (selenium.isVisible(elementLocator)) break; } catch (Exception e) {}
497             Thread.sleep(1000);
498         }
499     }
500 
501     /**
502      * Wait for 60 seconds for the selenium.getTitle to match the given title then fail.
503      * @param selenium
504      * @param title
505      * @throws InterruptedException
506      */
507     public static void waitForTitleToEqual(Selenium selenium, String title) throws InterruptedException {
508         waitForTitleToEqual(selenium, title, "");
509     }
510 
511     /**
512      * Wait for 60 seconds for the selenium.getTitle to match the given title then fail including the given message.
513      * @param selenium
514      * @param title
515      * @param message
516      * @throws InterruptedException
517      */
518     public static void waitForTitleToEqual(Selenium selenium, String title, String message) throws InterruptedException {
519         Thread.sleep(2000);
520 //        for (int second = 0;; second++) {
521 //            if (second >= WAIT_DEFAULT_SECONDS) fail(("timeout of " + WAIT_DEFAULT_SECONDS + " seconds waiting for title to equal " + title + " " + message).trim());
522 //            try { if (title.equals(selenium.getTitle())) break; } catch (Exception e) {}
523 //            Thread.sleep(1000);
524 //        }
525     }
526 
527     /**
528      * Check the selenium contents for an Incident Report failure with Incident Report Details
529      * @param selenium
530      * @param linkLocator
531      */
532     public static void checkForIncidentReport(Selenium selenium, String linkLocator) {
533         checkForIncidentReport(selenium, linkLocator, "");
534     }
535 
536     /**
537      * Fails if a Incident Report is detected, extracting and reporting the View Id, Document Id, and StackTrace
538      * @param selenium
539      * @param linkLocator used only in the failure message
540      */
541     public static void checkForIncidentReport(Selenium selenium, String linkLocator, String message) {
542         selenium.waitForPageToLoad(DEFAULT_WAIT_FOR_PAGE_TO_LOAD_TIMEOUT);
543         String contents = selenium.getHtmlSource();
544         checkForIncidentReport(contents, linkLocator, message);
545     }
546 
547     protected static void checkForIncidentReport(String contents, String linkLocator, String message) {
548         if (contents != null &&
549                 contents.contains("Incident Report") &&
550                 !contents.contains("portal.do?channelTitle=Incident%20Report") && // Incident Report link on sampleapp KRAD tab
551                 !contents.contains("portal.do?channelTitle=Incident Report") && // Incident Report link on sampleapp KRAD tab IE8
552                 !contents.contains("uitest?viewId=Travel-testView2") && 
553                 !contents.contains("SeleniumException")) { // selenium timeouts have Incident Report in them
554             try {
555                 if (contents.indexOf("Incident Feedback") > -1) {
556                     Iterator<String> iter = jiraMatches.keySet().iterator();
557                     String key = null;
558                     while (iter.hasNext()) {
559                         key = iter.next();
560                         if (contents.contains(key)) {
561                             Assert.fail("https://jira.kuali.org/browse/" + jiraMatches.get(key));
562                         }
563                     }
564 
565                     String chunk =  contents.substring(contents.indexOf("Incident Feedback"), contents.lastIndexOf("</div>") );
566                     String docId = chunk.substring(chunk.lastIndexOf("Document Id"), chunk.indexOf("View Id"));
567                     docId = docId.substring(0, docId.indexOf("</span>"));
568                     docId = docId.substring(docId.lastIndexOf(">") + 2, docId.length());
569 
570                     String viewId = chunk.substring(chunk.lastIndexOf("View Id"), chunk.indexOf("Error Message"));
571                     viewId = viewId.substring(0, viewId.indexOf("</span>"));
572                     viewId = viewId.substring(viewId.lastIndexOf(">") + 2, viewId.length());
573 
574                     String stackTrace = chunk.substring(chunk.lastIndexOf("(only in dev mode)"), chunk.length());
575                     stackTrace = stackTrace.substring(stackTrace.indexOf("<span id=\"") + 3, stackTrace.length());
576                     stackTrace = stackTrace.substring(stackTrace.indexOf("\">") + 2, stackTrace.indexOf("</span>"));
577 
578                     //            System.out.println(docId);
579                     //            System.out.println(viewId);
580                     //            System.out.println(stackTrace);
581                     Assert.fail("\nIncident report " + message + " navigating to "
582                             + linkLocator
583                             + " : View Id: "
584                             + viewId.trim()
585                             + " Doc Id: "
586                             + docId.trim()
587                             + "\nStackTrace: "
588                             + stackTrace.trim());
589                 } else {
590                     Assert.fail("\nIncident report detected " + message + "\nContents that triggered exception: " + deLinespace(contents));
591                 }
592             } catch (IndexOutOfBoundsException e) {
593                 Assert.fail("\nIncident report detected " + message + " but there was an exception during processing: " + e.getMessage() + "\nStack Trace from processing exception" + stackTrace(e) + "\nContents that triggered exception: " + deLinespace(
594                         contents));
595             }
596         } else {
597             if (contents.contains("HTTP Status 404")) {
598                 Assert.fail("\nHTTP Status 404 " + linkLocator + " " + message + " " + "\ncontents:" + contents);
599             }
600         }
601     }
602 
603     protected static String deLinespace(String contents) {
604         while (contents.contains("\n\n")) {
605             contents = contents.replaceAll("\n\n", "\n");
606         }
607         return contents;
608     }
609 }