001    /**
002     * Copyright 2005-2012 The Kuali Foundation
003     *
004     * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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    package edu.samplu.common;
017    
018    import com.thoughtworks.selenium.Selenium;
019    import org.apache.commons.lang.RandomStringUtils;
020    import org.junit.Assert;
021    import org.openqa.selenium.By;
022    import org.openqa.selenium.NoSuchFrameException;
023    import org.openqa.selenium.WebDriver;
024    import org.openqa.selenium.chrome.ChromeDriver;
025    import org.openqa.selenium.firefox.FirefoxDriver;
026    import org.openqa.selenium.firefox.FirefoxProfile;
027    import org.openqa.selenium.remote.DesiredCapabilities;
028    import org.openqa.selenium.remote.RemoteWebDriver;
029    
030    import java.io.PrintWriter;
031    import java.io.StringWriter;
032    import java.net.MalformedURLException;
033    import java.net.URL;
034    import java.net.URLEncoder;
035    import java.util.Calendar;
036    import java.util.HashMap;
037    import java.util.Iterator;
038    import java.util.Map;
039    
040    import static com.thoughtworks.selenium.SeleneseTestBase.fail;
041    import static org.junit.Assert.assertEquals;
042    
043    /**
044     * Common selenium test methods that should be reused rather than recreated for each test.
045     * @author Kuali Rice Team (rice.collab@kuali.org)
046     */
047    
048    public class ITUtil {
049    
050        public static final String KUALI_PORTAL_TITLE = "Kuali Portal Index";
051        public static final String DEFAULT_BASE_URL = "http://localhost:8080/kr-dev";
052        public final static String PORTAL = "/portal.do";
053        public final static String PORTAL_URL =  ITUtil.getBaseUrlString() + ITUtil.PORTAL;
054        public final static String PORTAL_URL_ENCODED = URLEncoder.encode(PORTAL_URL);
055        public static final String DTS = Calendar.getInstance().getTimeInMillis() + "";
056        public static final String DTS_TWO = Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase();
057        public static String WAIT_TO_END_TEST = "5000";
058        public static final String DIV_ERROR_LOCATOR = "//div[@class='error']";
059        public static final String DIV_EXCOL_LOCATOR = "//div[@class='msg-excol']";
060        public static final int WAIT_DEFAULT_SECONDS = 60;
061        public static final String DEFAULT_WAIT_FOR_PAGE_TO_LOAD_TIMEOUT = "30000";
062        static Map<String, String> jiraMatches;
063        public static final String REMOTE_PUBLIC_URL_PROPERTY = "remote.public.url";
064        public static final String REMOTE_AUTOLOGIN_PROPERTY = "remote.autologin";
065        public static final String HUB_PROPERTY = "remote.public.hub";
066        public static final String HUB_DRIVER_PROPERTY = "remote.public.driver";
067        public static final String HUB_URL_PROPERTY = "http://localhost:4444/wd/hub";
068        public static final String DONT_TEAR_DOWN_PROPERTY = "remote.driver.dontTearDown";
069    
070        static {
071            jiraMatches = new HashMap<String, String>();
072            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?",
073                    "KULRICE-8137 Agenda Rule edit Incident report Invalid property 'refreshWhenChanged'");
074    
075            jiraMatches.put("org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase.processAddCollectionLineBusinessRules(MaintenanceDocumentRuleBase.",
076                    "KULRICE-8142 NPE in MaintenanceDocumentRuleBase.processAddCollectionLineBusinessRules");
077    
078            jiraMatches.put("at org.kuali.rice.krad.rules.DocumentRuleBase.isDocumentOverviewValid(DocumentRuleBase.",
079                    "KULRICE-8134 NPE in DocumentRuleBase.isDocumentOverviewValid(DocumentRuleBase");
080    
081            jiraMatches.put("org.kuali.rice.krad.uif.layout.TableLayoutManager.buildLine(TableLayoutManager.",
082                    "KULRICE-8160 NPE at TableLayoutManager.buildLine(TableLayoutManager");
083    
084            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?",
085                    "KULRICE-8173 Bean property 'configFileLocations' is not writable or has an invalid setter method");
086    
087            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?",
088                    "KULRICE-8182 JDK7 Bean property 'componentSecurity' is not readable...");
089    
090            jiraMatches.put("java.sql.SQLSyntaxErrorException: ORA-00904: \"ROUTEHEADERID\": invalid identifier",
091                    "KULRICE-8277 Several ITs fail with OJB operation; bad SQL grammar []; nested exception is java.sql.SQLException: ORA-00904: \"ROUTEHEADERID\": invalid identifier");
092    //        jiraMatches.put("",
093    //                "");
094    
095        }
096    
097        /**
098         * "FINAL", selenium.getText("//table[@id='row']/tbody/tr[1]/td[4]"
099         * @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    }