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