001/**
002 * Copyright 2005-2017 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 */
016package org.kuali.rice.testtools.selenium;
017
018import org.junit.After;
019import org.junit.AfterClass;
020import org.junit.Before;
021import org.junit.BeforeClass;
022import org.junit.Rule;
023import org.junit.rules.TestName;
024import org.kuali.rice.testtools.common.JiraAwareFailable;
025import org.kuali.rice.testtools.common.JiraAwareFailureUtils;
026import org.openqa.selenium.By;
027import org.openqa.selenium.JavascriptExecutor;
028import org.openqa.selenium.Keys;
029import org.openqa.selenium.NoSuchElementException;
030import org.openqa.selenium.NoSuchWindowException;
031import org.openqa.selenium.WebDriver;
032import org.openqa.selenium.WebElement;
033import org.openqa.selenium.chrome.ChromeDriverService;
034import org.openqa.selenium.interactions.Actions;
035import org.openqa.selenium.remote.RemoteWebDriver;
036
037import java.lang.reflect.Method;
038import java.text.SimpleDateFormat;
039import java.util.ArrayList;
040import java.util.Calendar;
041import java.util.Date;
042import java.util.Iterator;
043import java.util.LinkedList;
044import java.util.List;
045import java.util.Set;
046import java.util.concurrent.TimeUnit;
047
048/**
049 * Ideally the AFT code here should be generic for KRAD AFT testing and not specific to KRAD sampleapp testing.  The idea
050 * being that code in this class should be generic enough to be useful to other projects using and testing KRAD without having
051 * to pull in code to specific to the KRAD sampleapp.  KRAD sampleapp specific code should go in WebDriverLegacyITBase.
052 *
053 * @author Kuali Rice Team (rice.collab@kuali.org)
054 */
055public abstract class WebDriverAftBase extends JiraAwareAftBase {
056
057    protected static ChromeDriverService chromeDriverService;
058
059    /**
060     * div.dataTables_wrapper thead th
061     */
062    public static final String DATA_TABLE_TH_CSS = "div.dataTables_wrapper thead th";
063
064    // make WebDriver static for one browser
065    protected WebDriver driver;
066
067    protected String jGrowlHeader;
068
069    /**
070     *  lookupCriteria[number]
071     */
072    public static final String LOOKUP_CRITERIA_NUMBER_NAME="lookupCriteria[number]";
073
074    /**
075     * ^[\s\S]*error[\s\S]*$"
076     */
077    public static final String REGEX_ERROR = "^[\\s\\S]*error[\\s\\S]*$";
078
079    /**
080     * ^[\s\S]*valid[\s\S]*$
081     */
082    public static final String REGEX_VALID = "^[\\s\\S]*valid[\\s\\S]*$";
083
084    /**
085     * return selected
086     */
087    public static final String RETURN_SELECTED_BUTTON_TEXT = "return selected";
088
089    /**
090     * return value
091     */
092    public static final String RETURN_VALUE_LINK_TEXT = "return value";
093
094    /**
095     * //button[contains(text(),'earch')]
096     */
097    public static final String SEARCH_XPATH_3 = "//button[contains(text(),'earch')]";
098
099    /**
100     * show inactive
101     */
102    public static final String SHOW_INACTIVE = "show inactive";
103
104    /**
105     * div.uif-group.uif-collectionGroup.uif-tableCollectionGroup.uif-tableSubCollection.uif-disclosure span.uif-headerText-span
106     */
107    public static final String SUB_COLLECTION_UIF_DISCLOSURE_SPAN_UIF_HEADER_TEXT_SPAN_XPATH =
108            "div.uif-group.uif-collectionGroup.uif-tableCollectionGroup.uif-tableSubCollection.uif-disclosure span.uif-headerText-span";
109
110    // one browser
111//    protected String oneBrowserHandle = null;
112
113    protected String sessionId = null;
114
115    protected String testMethodName;
116
117    public @Rule TestName testName = new TestName();
118
119    /**
120     * timeout
121     */
122    public static final String TIMEOUT_MESSAGE = "timeout";
123
124    protected String uniqueString;
125
126    protected String user = "admin";
127
128    protected int waitSeconds;
129
130    protected WebDriverScreenshotHelper webDriverScreenshotHelper = new WebDriverScreenshotHelper();
131
132    protected void acceptAlertIfPresent() {
133        WebDriverUtils.acceptAlertIfPresent(driver);
134    }
135
136    /**
137     * Accept the javascript alert (clicking OK)
138     */
139    protected void alertAccept() {
140        WebDriverUtils.alertAccept(driver);
141    }
142
143    /**
144     * Dismiss the javascript alert (clicking Cancel)
145     */
146    protected void alertDismiss() {
147        WebDriverUtils.alertDismiss(driver);
148    }
149
150    @AfterClass
151    public static void afterClass() {
152        // one browser
153//        if (driver != null) {
154//            try {
155//                driver.close();
156//            } catch (NoSuchWindowException nswe) {
157//                System.out.println("NoSuchWindowException closing WebDriver " + nswe.getMessage());
158//            } finally {
159//                if (driver != null) {
160//                    driver.quit();
161//                }
162//            }
163//        }
164
165        if (chromeDriverService != null) {
166            chromeDriverService.stop();
167        }
168    }
169
170    protected boolean areAllMultiValueSelectsChecked() throws InterruptedException {
171        acceptAlertIfPresent();
172        WebElement tbody = waitAndGetElementByAttributeValue("role", "alert"); // results table body
173        List<WebElement> checkboxes = findElements(By.className("uif-checkboxControl"),tbody);
174        for (WebElement checkbox: checkboxes) {
175            if (!"true".equals(checkbox.getAttribute("checked"))) {
176                return false;
177            }
178        }
179        return true;
180    }
181
182    protected boolean areNoMultiValueSelectsChecked() throws InterruptedException {
183        WebElement tbody = waitAndGetElementByAttributeValue("role", "alert"); // results table body
184        List<WebElement> checkboxes = findElements(By.className("uif-checkboxControl"),tbody);
185        for (WebElement checkbox: checkboxes) {
186            if (null != checkbox.getAttribute("checked")) {
187                return false;
188            }
189        }
190        return true;
191    }
192
193    protected void assertAttributeClassRegexDoesntMatch(String field, String regex) throws InterruptedException {
194        Thread.sleep(1000);
195        String attribute = waitAndGetAttributeByName(field, "class");
196        assertTrue("waitAndGetAttributeByName(" + field + ", \"class\") should not be null", attribute != null);
197        assertFalse("attribute " + attribute + " matches regex " + regex + " and it should not", attribute.matches(
198                regex));
199    }
200
201    protected void assertAttributeClassRegexMatches(String field, String regex) throws InterruptedException {
202        Thread.sleep(1000);
203        String attribute = waitAndGetAttributeByName(field, "class");
204        assertTrue("waitAndGetAttributeByName(" + field + ", \"class\") should not be null", attribute != null);
205        assertTrue("attribute " + attribute + " doesn't match regex " + regex, attribute.matches(regex));
206    }
207
208    protected void assertElementPresentInResultPages(By searchBy) throws Exception {
209        while(!isElementPresent(searchBy)) {
210            assertTrue("Didn't find expected results in result pages", isNextLinkEnabled());
211            waitAndClickByLinkText("Next");
212        }
213    }
214
215    protected void assertElementsPresentInResultPages(By[] searchBys) throws Exception {
216        boolean[] founds = new boolean[searchBys.length];
217        boolean allFound = false;
218
219        waitForElementPresentById("uLookupResults_layout_next");
220
221        while (!allFound) {
222
223            for (int i = 0; i < founds.length; i++) {
224                if (!founds[i]) {
225                    founds[i] = isElementPresent(searchBys[i]);
226                }
227            }
228
229            allFound = true; // assume we found them all, verify that assumption in the for loop
230            for (int i = 0; i < founds.length; i++) {
231                if (!founds[i]) {
232                    allFound = false;
233                }
234            }
235
236            if (!allFound) {
237                assertTrue("Didn't find expected results in result pages for " + this.getClass().getSimpleName(), isNextLinkEnabled());
238                waitAndClickByLinkText("Next");
239            }
240
241        }
242    }
243
244    protected void assertTextPresentInResultPages(String[][] texts) throws Exception {
245        boolean[] founds = new boolean[texts.length];
246        boolean allFound = false;
247
248        waitForElementPresentById("uLookupResults_layout_next");
249
250        while (!allFound) {
251
252            for (int i = 0; i < founds.length; i++) {
253                if (!founds[i]) {
254                    for (int j = 0; j < texts.length; j++) {
255                        founds[i] = isTextPresent(texts[i]);
256                    }
257                }
258            }
259
260            allFound = true; // assume we found them all, verify that assumption in the for loop
261            for (int i = 0; i < founds.length; i++) {
262                if (!founds[i]) {
263                    allFound = false;
264                }
265            }
266
267            if (!allFound) {
268                assertTrue("Didn't find expected results in result pages for " + this.getClass().getSimpleName(), isNextLinkEnabled());
269                waitAndClickByLinkText("Next");
270            }
271        }
272    }
273
274
275    protected void assertEmptyInputByName(String name) throws InterruptedException {
276        assertTrue(name + " not empty for " + this.getClass().getSimpleName(), waitForElementPresentByName(name)
277                .getAttribute("value").equals(""));
278    }
279
280    protected void assertFocusTypeBlurError(String field, String textToType) throws InterruptedException {
281        fireEvent(field, "focus");
282        waitAndTypeByName(field, textToType);
283        fireEvent(field, "blur");
284        Thread.sleep(500);
285        assertAttributeClassRegexMatches(field, REGEX_ERROR);
286        clearTextByName(field);
287    }
288
289    protected void assertFocusTypeBlurError(String field, String[] errorInputs) throws InterruptedException {
290        for (String errorInput: errorInputs) {
291            assertFocusTypeBlurError(field, errorInput);
292            clearTextByName(field);
293        }
294    }
295
296    protected void assertFocusTypeBlurValid(final String field, String textToType) throws InterruptedException {
297        clearTextByName(field);
298        fireEvent(field, "focus");
299        waitAndTypeByName(field, textToType);
300        fireEvent(field, "blur");
301        Thread.sleep(200);
302        assertAttributeClassRegexMatches(field, REGEX_VALID);
303        assertAttributeClassRegexDoesntMatch(field, REGEX_ERROR);
304        clearTextByName(field);
305    }
306
307    protected void assertFocusTypeBlurValid(String field, String[] validInputs) throws InterruptedException {
308        for (String validInput: validInputs) {
309            assertFocusTypeBlurValid(field, validInput);
310            clearTextByName(field);
311        }
312    }
313
314    protected void assertFocusTypeBlurValidation(String field, String[] errorInputs, String[] validInputs) throws InterruptedException {
315        assertFocusTypeBlurError(field, errorInputs);
316        clearTextByName(field);
317        assertFocusTypeBlurValid(field, validInputs);
318    }
319
320    protected void assertFocusTypeTabError(String field, String textToType) throws InterruptedException {
321        fireEvent(field, "focus");
322        waitAndTypeByName(field, textToType);
323        driver.switchTo().activeElement().sendKeys(Keys.TAB);
324        Thread.sleep(500);
325        assertAttributeClassRegexMatches(field, REGEX_ERROR);
326        clearTextByName(field);
327    }
328
329    protected void assertJgrowlText(String jGrowlText) throws InterruptedException {
330        waitForElementPresentByClassName("jGrowl-message");
331
332        // wait for any flash not present errors to fade out
333        while (jGrowlTextContains("Unable to load SWF file")) {
334            try {
335                driver.findElement(By.className("jGrowl-close")).click(); // no wait, click quick
336            } catch (Throwable t) {
337                // don't fail because the swf jgrowl has gone away
338            }
339        }
340
341        // get growl texts
342        StringBuilder sb = new StringBuilder("");
343        List<WebElement> jGrowls = findElements(By.className("jGrowl-message"));
344        for (WebElement jGrowl : jGrowls) {
345            if (jGrowl.getText() != null) {
346                sb.append(jGrowl.getText()).append("\n");
347            }
348        }
349        String growlText = sb.toString();
350
351        WebDriverUtils.stepMessage("Do jGrowls contain text '" + jGrowlText + "'? " + growlText.contains(jGrowlText));
352
353        //check growl text is present
354        assertTrue(growlText + " does not contain " + jGrowlText, growlText.contains(jGrowlText));
355    }
356
357    private boolean jGrowlTextContains(String text) {
358        boolean contains = false;
359        try {
360            contains = findElement(By.className("jGrowl-message")).getText().contains(text);
361        } catch (Throwable t) {
362            return false;
363        }
364        return contains;
365    }
366
367    protected void assertLabelWithTextPresent(String labelText) throws InterruptedException {
368        jGrowl("Assert Label containing the text " + labelText + " is present");
369        waitForElementPresentByXpath("//label[contains(text(), '" + labelText + "')]");
370    }
371
372    protected void assertLabelFor(String forElementId, String labelText) {
373        assertEquals(labelText, getForLabelText(forElementId));
374    }
375
376    protected void assertMultiValueDeselectAllThisPage() throws InterruptedException {
377        waitAndClickDropDown("deselect all items on this page");
378        if (!areNoMultiValueSelectsChecked()) {
379            jiraAwareFail("deselect all items on this page failure");
380        }
381        assertButtonDisabledByText(RETURN_SELECTED_BUTTON_TEXT);
382    }
383
384    protected void assertMultiValueSelectAllThisPage() throws InterruptedException {
385        waitAndClickDropDown("select all items on this page");
386        if (!areAllMultiValueSelectsChecked()) {
387            JiraAwareFailureUtils.fail("select all items on this page failure", this);
388        }
389        assertButtonEnabledByText(RETURN_SELECTED_BUTTON_TEXT);
390    }
391
392    protected void assertTextPresent(String[] text) throws InterruptedException {
393        assertTextPresent("", text);
394    }
395
396    protected void assertTextPresent( String message, String[] text) throws InterruptedException {
397        StringBuilder missingText = new StringBuilder("");
398        boolean present = true;
399        for (int i = 0, s = text.length; i < s; i++) {
400            if (i == 0) {
401                present = waitForIsTextPresent(text[0]); // wait for the first check
402                if (!present) {
403                    missingText.append(text[0]);
404                }
405            } else {
406                if (!isTextPresent(text[i])) {
407                    present = false;
408                    missingText.append(" " + text[i]);
409                }
410            }
411        }
412        if (!present) {
413            jiraAwareFail(message + " " + missingText + " not present for " + this.getClass().toString());
414        }
415    }
416
417    protected void assertTextPresent(String[][] text) throws InterruptedException {
418        StringBuilder missingText = new StringBuilder("");
419        boolean present = true;
420        for (int i = 0, s = text.length; i < s; i++) {
421            for (int j = 0, t = text[i].length; j < t; j++) {
422                if (i == 0 && j == 0) {
423                    present = waitForIsTextPresent(text[0][0]); // wait for the first check
424                    if (!present) {
425                        missingText.append(text[0][0]);
426                    }
427                } else {
428                    if (!isTextPresent(text[i][j])) {
429                        present = false;
430                        missingText.append(" " + text[i][j]);
431                    }
432                }
433            }
434        }
435        if (!present) {
436            jiraAwareFail(missingText + " not present for " + this.getClass().toString());
437        }
438    }
439
440    /**
441     * Assert that clicking an element causes a popup window with a specific URL
442     * Uses Selenium's findElements method which does not throw a test exception if not found.
443     * @param by The locating mechanism of the element to be clicked
444     * @param windowName The name of the popup window
445     * @param url The URL of the popup window
446     */
447    protected void assertPopUpWindowUrl(By by, String windowName, String url) {
448        findElement(by).click();
449        String parentWindowHandle = driver.getWindowHandle();
450        // wait page to be loaded
451        driver.switchTo().window(windowName).findElements(By.tagName("head"));
452        assertEquals(url, driver.getCurrentUrl());
453        driver.switchTo().window(parentWindowHandle);
454    }
455
456    protected void back() {
457        jGrowl("Click browser back button");
458        driver.navigate().back();
459    }
460
461    protected void check(By by) throws InterruptedException {
462        WebElement element = findElement(by);
463
464        if (!element.isSelected()) {
465            element.click();
466        }
467    }
468
469    protected void checkById(String id) throws InterruptedException {
470        check(By.id(id));
471    }
472
473    protected void checkByName(String name) throws InterruptedException {
474        check(By.name(name));
475    }
476
477    protected void checkByXpath(String locator) throws InterruptedException {
478        check(By.xpath(locator));
479    }
480
481    protected void checkForIncidentReport() {
482        checkForIncidentReport("", this.getClass().toString());
483    }
484
485    protected String incidentReportMessage() {
486        return AutomatedFunctionalTestUtils.incidentReportMessage(driver.getPageSource(), "", this.getClass().toString());
487    }
488
489    protected void checkForIncidentReport(String locator) {
490        checkForIncidentReport(locator, this.getClass().toString());
491    }
492
493    protected void checkForIncidentReport(String locator, String message) {
494        AutomatedFunctionalTestUtils.checkForIncidentReport(driver.getPageSource(), locator, message, this);
495    }
496
497    /**
498     * @deprecated {@see #checkForIncidentReport(String, String)}
499     */
500    protected void checkForIncidentReport(String locator, JiraAwareFailable failable, String message) {
501        AutomatedFunctionalTestUtils.checkForIncidentReport(driver.getPageSource(), locator, message, failable);
502    }
503
504    protected void clearText(By by) throws InterruptedException {
505        findElement(by).clear();
506    }
507
508    protected void clearText(String selector) throws InterruptedException {
509        clearText(By.cssSelector(selector));
510    }
511
512    protected void clearTextByName(String name) throws InterruptedException {
513        clearText(By.name(name));
514    }
515
516    protected void clearTextByXpath(String locator) throws InterruptedException {
517        clearText(By.xpath(locator));
518    }
519
520    protected void close() {
521        driver.close();
522    }
523
524    protected void closeAllOtherWindows(String handleToKeep) {
525        Set<String> set = driver.getWindowHandles();
526
527        set.remove(handleToKeep);
528
529        Iterator iter = set.iterator();
530        String handle = "";
531        while (iter.hasNext()) {
532            handle = (String)iter.next();
533            driver.switchTo().window(handle);
534            driver.close();
535        }
536
537        driver.switchTo().window(handleToKeep);
538    }
539
540
541    protected void colapseExpandByXpath(String clickLocator, String visibleLocator) throws InterruptedException {
542        waitAndClickByXpath(clickLocator);
543        waitNotVisibleByXpath(visibleLocator);
544        waitAndClickByXpath(clickLocator);
545        waitIsVisibleByXpath(visibleLocator);
546    }
547
548    /**
549     * If WebDriverUtils.chromeDriverCreateCheck() returns a ChromeDriverService, start it.
550     * {@link org.kuali.rice.testtools.selenium.WebDriverUtils#chromeDriverCreateCheck()}
551     * @throws Exception
552     */
553    @BeforeClass
554    public static void chromeDriverService() throws Exception {
555        chromeDriverService = WebDriverUtils.chromeDriverCreateCheck();
556        if (chromeDriverService != null) {
557            chromeDriverService.start();
558        }
559
560// one browser
561//        driver = WebDriverUtils.setUp("getClass().getSimpleName()", "testMethodName");
562
563    }
564
565    protected void closeAndQuitWebDriver() {
566        if (driver != null) {
567            if (WebDriverUtils.dontTearDownPropertyNotSet() && WebDriverUtils.dontTearDownOnFailure(isPassed())) {
568                try {
569                    acceptAlertIfPresent();
570                    driver.close();
571                } catch (NoSuchWindowException nswe) {
572                    System.out.println("NoSuchWindowException closing WebDriver " + nswe.getMessage());
573                } finally {
574                    if (driver != null) {
575                        driver.quit();
576                    }
577                }
578            }
579        } else {
580            System.out.println("WebDriver is null for " + this.getClass().toString() + " if using a remote hub did you include the port?");
581        }
582    }
583
584    protected void determineImplicitWait() {
585        waitSeconds = WebDriverUtils.configuredImplicityWait();
586    }
587
588    protected void determineJgrowlHeader() {
589        jGrowlHeader = getClass().getSimpleName() + "." + testMethodName;
590    }
591
592    protected String determinePage() {
593        String url = driver.getCurrentUrl();
594
595        String viewId = "";
596        if (url.contains("viewId=")) {
597            viewId = url.substring(url.indexOf("viewId=") + 7, url.length());
598            if (viewId.indexOf("&") > -1) {
599                viewId = viewId.substring(0, viewId.indexOf("&"));
600            } else {
601                viewId = viewId.substring(0, viewId.length());
602            }
603        }
604
605        String pageId = "";
606        if (url.contains("pageId=")) {
607            pageId = url.substring(url.indexOf("pageId=") + 7, url.length());
608            if (pageId.indexOf("&") > -1) {
609                pageId = "-" + pageId.substring(0, pageId.indexOf("&"));
610            } else {
611                pageId = "-" + pageId.substring(0, pageId.length());
612            }
613        }
614
615        return viewId + pageId;
616    }
617
618    protected void determineTestMethodName() {
619        if (testName != null && testName.getMethodName() != null) { // JUnit
620            setTestMethodName(testName.getMethodName());
621        }
622    }
623
624    public void setTestMethodName(String testMethodName) {
625        this.testMethodName = testMethodName;
626    }
627
628    protected void determineUser() {
629        String givenUser = WebDriverUtils.determineUser(this.toString());
630        if (givenUser != null) {
631            user = givenUser;
632        }
633    }
634
635    protected String getDescriptionBase() {
636        return this.getClass().toString().substring(this.getClass().toString().lastIndexOf(".") + 1,
637                this.getClass().toString().length()) +
638                "." + testMethodName + " description";
639    }
640
641    protected String getDescriptionUnique() {
642        if (uniqueString == null) {
643            uniqueString = AutomatedFunctionalTestUtils.createUniqueDtsPlusTwoRandomCharsNot9Digits();
644        }
645        return getDescriptionBase() + " " + uniqueString;
646    }
647
648    protected WebElement findButtonByText(String buttonText) {
649        return WebDriverUtils.findButtonByText(driver, buttonText);
650    }
651
652    protected List<WebElement> findVisibleElements(By by) {
653        List<WebElement> webElements = driver.findElements(by);
654        List<WebElement> visibleWebElements = new LinkedList<WebElement>();
655        for (WebElement webElement: webElements) {
656            if (webElement.isDisplayed()) {
657                visibleWebElements.add(webElement);
658            }
659        }
660
661        return visibleWebElements;
662    }
663
664    protected List<WebElement> findElements(By by) {
665        List<WebElement> found = driver.findElements(by);
666        return found;
667    }
668
669    protected List<WebElement> findElements(By by, WebElement element) {
670        if (element == null) {
671            checkForIncidentReport();
672            throw new AssertionError("element to findElements on for " + by.toString() + " is null in class " + this.getClass().toString());
673        }
674        List<WebElement> found = element.findElements(by);
675        return found;
676    }
677
678    protected void fireEvent(String name, String event) {
679        ((JavascriptExecutor) driver).executeScript("var elements=document.getElementsByName(\"" + name + "\");" +
680                "for (var i = 0; i < elements.length; i++){" +
681                "elements[i]." + event + "();}");
682    }
683
684    protected void fireEvent(String name, String value, String event) {
685        ((JavascriptExecutor) driver).executeScript("var elements=document.getElementsByName(\"" + name + "\");" +
686                "for (var i = 0; i < elements.length; i++){" +
687                "if(elements[i].value=='" + value + "')" +
688                "elements[i]." + event + "();}");
689    }
690
691    /**
692     * {@link org.openqa.selenium.interactions.Actions#moveToElement(org.openqa.selenium.WebElement)}
693     * @param name
694     */
695    public void fireMouseOverEventByName(String name) {
696        this.fireMouseOverEvent(By.name(name));
697    }
698
699    /**
700     * {@link org.openqa.selenium.interactions.Actions#moveToElement(org.openqa.selenium.WebElement)}
701     * @param id
702     */
703    public void fireMouseOverEventById(String id) {
704        this.fireMouseOverEvent(By.id(id));
705    }
706
707    /**
708     * {@link org.openqa.selenium.interactions.Actions#moveToElement(org.openqa.selenium.WebElement)}
709     * @param locator
710     */
711    public void fireMouseOverEventByXpath(String locator) {
712        this.fireMouseOverEvent(By.xpath(locator));
713    }
714
715    /**
716     * {@link org.openqa.selenium.interactions.Actions#moveToElement(org.openqa.selenium.WebElement)}
717     * @param by
718     */
719    public void fireMouseOverEvent(By by) {
720        Actions builder = new Actions(driver);
721        Actions hover = builder.moveToElement(findElement(by));
722        hover.perform();
723    }
724
725    /**
726     * {@link org.openqa.selenium.WebDriver#getWindowHandles()}
727     * @return
728     */
729    public String[] getAllWindowTitles() {
730        return (String[]) driver.getWindowHandles().toArray();
731    }
732
733    protected String getBaseUrlString() {
734        return WebDriverUtils.getBaseUrlString();
735    }
736
737    protected int getCssCount(String selector) {
738        return getCssCount(By.cssSelector(selector));
739    }
740
741    /**
742     * Uses Selenium's findElements method which does not throw a test exception if not found.
743     * @param by
744     * @return
745     */
746    protected int getCssCount(By by) {
747        return (findElements(by)).size();
748    }
749
750    protected String getDateTimeStampFormatted() {
751        return WebDriverUtils.getDateTimeStampFormatted();
752    }
753
754    protected String getDateToday() {
755        Date now = Calendar.getInstance().getTime();
756        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
757        return sdf.format(now);
758    }
759
760    protected String getDateTomorrow() {
761        Calendar now = Calendar.getInstance();
762        now.add(Calendar.DATE, 1);
763        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
764        return sdf.format(now.getTime());
765    }
766
767    /**
768     * {@inheritDoc}
769     *
770     * @return WebDriver
771     */
772    @Override
773    protected WebDriver getDriver() {
774        return driver;
775    }
776
777    public void setDriver(WebDriver driver) {
778        this.driver = driver;
779    }
780
781    protected WebElement getElementByAttribute(String attributeName){
782        return findElement(By.cssSelector("[" + attributeName + "]"));
783    }
784
785    protected WebElement getElementByDataAttribute(String dataAttributeName){
786        return findElement(By.cssSelector("[data-" + dataAttributeName + "]"));
787    }
788
789    protected WebElement getElementByDataAttributeValue(String dataAttributeName, String value){
790        return findElement(By.cssSelector("[data-" + dataAttributeName + "='" + value + "']"));
791    }
792
793    protected WebElement getElementByAttributeValue(String attributeName, String value){
794        return findElement(By.cssSelector("[" + attributeName + "='" + value +"']"));
795    }
796
797    protected List<WebElement> getElementsByAttributeValue(String attributeName, String value){
798        return findElements(By.cssSelector("[" + attributeName + "='" + value + "']"));
799    }
800
801    @Override
802    protected String getNavigationUrl() {
803        String classString = this.getClass().toString();
804        if (classString.contains("krad.demo")) {
805            return AutomatedFunctionalTestUtils.KRAD_PORTAL;
806        } else if (classString.contains("krad.labs")) {
807            return AutomatedFunctionalTestUtils.LABS;
808        } else {
809            return AutomatedFunctionalTestUtils.PORTAL;
810        }
811    }
812
813    /**
814     * Uses Selenium's findElements for getting the options (findElement for the select) method which does not throw a test exception if not found.
815     * @param by
816     * @return
817     * @throws InterruptedException
818     */
819    protected String[] getSelectOptions(By by) throws InterruptedException {
820        WebElement select1 = driver.findElement(by); // don't highlight
821        List<WebElement> options = select1.findElements(By.tagName("option"));
822        String[] optionValues = new String[options.size()];
823        int counter = 0;
824
825        for (WebElement option : options) {
826            optionValues[counter] = option.getAttribute("value");
827            counter++;
828        }
829
830        return optionValues;
831    }
832
833    protected String[] getSelectOptionsByName(String name) throws InterruptedException {
834        return getSelectOptions(By.name(name));
835    }
836
837    protected String[] getSelectOptionsByXpath(String locator) throws InterruptedException {
838        return getSelectOptions(By.xpath(locator));
839    }
840
841    /**
842     *
843     * @return sessionId
844     */
845    public String getSessionId() {
846        return sessionId;
847    }
848
849    protected String getText(By by) throws InterruptedException {
850        WebElement element = findElement(by);
851        return element.getText();
852    }
853
854    protected String getTextByClassName(String className) throws InterruptedException {
855        return getText(By.className(className));
856    }
857
858    protected String getTextById(String id) throws InterruptedException {
859        return getText(By.id(id));
860    }
861
862    protected String getTextByName(String name) throws InterruptedException {
863        return getText(By.name(name));
864    }
865
866    protected String getText(String locator) throws InterruptedException {
867        return getText(By.cssSelector(locator));
868    }
869
870    protected String getTextByXpath(String locator) throws InterruptedException {
871        return getText(By.xpath(locator));
872    }
873
874    protected String getTitle() {
875        return driver.getTitle();
876    }
877
878    /**
879     * "admin" by default.  Can be overridden using {@see WebDriverUtils#REMOTE_PUBLIC_USER_PROPERTY}
880     * @return string
881     */
882    public String getUserName() {
883        return user;
884    }
885
886    /**
887     * Returns the label text of a label-for element
888     * <p>
889     * For usage with elements like this: <label for="some-element-id">The text of the Label</label>
890     * </p>
891     *
892     * @param forElementId the id of the element for which to find the label text
893     * @return label text
894     */
895    protected String getForLabelText(String forElementId) {
896        return findElement(By.cssSelector("label[for=" + forElementId + "]")).getText();
897    }
898
899    protected void gotoIframeById(final String iframeId) {
900        if (driver.findElements(By.id(iframeId)).size() > 0) { // find elements so an exception isn't thrown if not found
901            WebElement contentFrame = driver.findElement(By.id(iframeId)); // don't highlight
902            driver.switchTo().frame(contentFrame);
903        } else {
904            System.out.println("Unable to find " + iframeId);
905        }
906    }
907    protected WebElement gotoIframeByXpath(final String iframeXpath) {
908        if (driver.findElements(By.xpath(iframeXpath)).size() > 0) {  // find elements so an exception isn't thrown if not found
909            WebElement contentFrame = driver.findElement(By.xpath(iframeXpath)); // don't highlight
910            driver.switchTo().frame(contentFrame);
911            return contentFrame;
912        } else {
913            System.out.println("Unable to find " + iframeXpath);
914        }
915        return null;
916    }
917
918    protected void gotoLightBox() throws InterruptedException {
919        waitForElementVisibleBy(By.cssSelector(".uif-lookupDialog-iframe"));
920        driver.switchTo().frame(driver.findElement(By.cssSelector(".uif-lookupDialog-iframe")));
921    }
922
923    protected WebElement gotoLightBoxIframe() {
924        selectTopFrame();
925        return gotoIframeByXpath("//iframe[@class='uif-iFrame uif-lookupDialog-iframe']");
926    }
927
928    protected int howManyAreVisible(By by) throws InterruptedException {
929        int count = 0;
930        if (by == null) {
931
932            return count;
933        }
934
935        List<WebElement> webElementsFound = driver.findElements(by);
936        for (WebElement webElement: webElementsFound) {
937            if (webElement.isDisplayed()) {
938                count++;
939            }
940        }
941
942        return count;
943    }
944
945    protected boolean isNextLinkEnabled() {
946        return findElements(By.xpath("//a[@id='uLookupResults_layout_next' and @class='next paginate_button paginate_button_disabled']")).size() != 1;
947    }
948
949    protected boolean isChecked(By by) {
950        return findElement(by).isSelected();
951    }
952
953    protected boolean isCheckedById(String id) {
954        return isChecked(By.id(id));
955    }
956
957    protected boolean isCheckedByName(String name) {
958        return isChecked(By.name(name));
959    }
960
961    protected boolean isCheckedByXpath(String locator) {
962        return isChecked(By.xpath(locator));
963    }
964
965    protected boolean isEnabled(By by) {
966        return findElement(by).isEnabled();
967    }
968
969    protected boolean isEnabledById(String id) {
970        return isEnabled(By.id(id));
971    }
972
973    protected boolean isEnabledByName(String name) {
974        return isEnabled(By.name(name));
975    }
976
977    protected boolean isEnabledByXpath(String locator) {
978        return isEnabled(By.xpath(locator));
979    }
980
981    protected boolean isVisible(By[] bys) {
982        if (bys == null || bys.length == 0 ) {
983            return false;
984        }
985
986        for (int i = 0, s = bys.length; i < s; i++) {
987
988            try {
989
990                if (isVisible(bys[i])) {
991                    return true;
992                }
993
994            } catch (NoSuchElementException nsee) {
995                // don't fail
996            }
997
998        }
999
1000        return false;
1001    }
1002
1003    /**
1004     * Uses Selenium's findElements method which does not throw a test exception if not found.
1005     * @param by
1006     * @return
1007     */
1008    protected boolean isElementPresent(By by) {
1009        return (driver.findElements(by)).size() > 0;
1010    }
1011
1012    /**
1013     * Uses Selenium's findElements method which does not throw a test exception if not found.
1014     * @param locator
1015     * @return
1016     */
1017    protected boolean isElementPresent(String locator) {
1018        return (driver.findElements(By.cssSelector(locator))).size() > 0;
1019    }
1020
1021    protected boolean isElementPresentById(String id) {
1022        return isElementPresent(By.id(id));
1023    }
1024
1025    protected boolean isElementPresentByName(String name) {
1026        return isElementPresent(By.name(name));
1027    }
1028
1029    protected boolean isElementPresentByXpath(String locator) {
1030        return isElementPresent(By.xpath(locator));
1031    }
1032
1033    protected boolean isElementPresentByLinkText(String locator) {
1034        return isElementPresent(By.linkText(locator));
1035    }
1036
1037    protected boolean isElementPresentByDataAttributeValue(String dataAttributeName, String dataAttributeValue) {
1038        return isElementPresent(By.cssSelector("[data-" + dataAttributeName + "='" + dataAttributeValue + "']"));
1039    }
1040
1041    protected boolean isNotVisible(By by) {
1042        return !(isVisible(by));
1043    }
1044
1045    protected Boolean isTextPresent(String text) {
1046        return WebDriverUtils.isTextPresent(driver, driver.getPageSource(), text);
1047    }
1048
1049    protected Boolean isTextPresent(String[] texts) {
1050        String pageSource = driver.getPageSource();
1051        for (String text: texts) {
1052            if (!WebDriverUtils.isTextPresent(driver, pageSource, text)) {
1053                return false;
1054            }
1055        }
1056        return true;
1057    }
1058
1059    protected void javascriptErrorsReport() {List javascriptErrors = WebDriverUtils.javascriptErrors(getDriver());
1060        if (javascriptErrors != null && javascriptErrors.size() > 0) {
1061            jGrowl("JAVASCRIPT ERRORS DETECTED - " + WebDriverUtils.javascriptErrorsToString(javascriptErrors));
1062        }
1063    }
1064
1065    protected void jGrowl(String message) {
1066        WebDriverUtils.jGrowl(driver, jGrowlHeader, false, message);
1067        if (webDriverScreenshotHelper.screenshotSteps()) {
1068            screenshot();
1069        }
1070    }
1071
1072    /**
1073     * Sticky is used on fail, making a call to jGrowl(String) from this method will result
1074     * in an infinite loop if JGROWL_ERROR_FAILURE is true so please don't.
1075     */
1076    protected void jGrowlSticky(String message) {
1077        WebDriverUtils.jGrowl(driver, jGrowlHeader, true, message);
1078        if (webDriverScreenshotHelper.screenshotSteps()) {
1079            screenshot();
1080        }
1081    }
1082
1083    /**
1084     * <p>
1085     * Logs in using the KRAD Login Page, if the JVM arg remote.autologin is set, auto login as admin will not be done.
1086     * </p>
1087     *
1088     * @param driver to login with
1089     * @param userName to login with
1090     * @param failable to fail on if there is a login problem
1091     * @throws InterruptedException
1092     */
1093    public void login(WebDriver driver, String userName, JiraAwareFailable failable) throws InterruptedException {
1094        if ("true".equalsIgnoreCase(System.getProperty(WebDriverUtils.REMOTE_AUTOLOGIN_PROPERTY, "true"))) {
1095            driver.findElement(By.name("login_user")).clear();
1096            driver.findElement(By.name("login_user")).sendKeys(userName);
1097            driver.findElement(By.id("Rice-LoginButton")).click();
1098            Thread.sleep(1000);
1099            String contents = driver.getPageSource();
1100            AutomatedFunctionalTestUtils.failOnInvalidUserName(userName, contents, failable);
1101            AutomatedFunctionalTestUtils.checkForIncidentReport(driver.getPageSource(), "Login", "Login failure",
1102                    failable);
1103        }
1104    }
1105
1106    protected void logout() throws InterruptedException {
1107        // KRAD Logout requires server configuration, currently env14 is not configured so throws Incident Report.
1108        //        } else {
1109        //            String logoutUrl = getBaseUrlString() + "/kr-krad/login?methodToCall=logout";
1110        //            jGrowl("Logging out with " + logoutUrl);
1111        //            open(logoutUrl);
1112    }
1113
1114    protected String multiValueResultCount() throws InterruptedException {
1115        WebElement dataTableInfo = waitAndGetElementByAttributeValue("class", "dataTables_info");
1116        String resultsCount = dataTableInfo.getText();
1117        resultsCount = resultsCount.substring(resultsCount.indexOf(" of ") + 4, resultsCount.indexOf(" entries")).trim();
1118        return resultsCount;
1119    }
1120
1121    protected void open(String url) {
1122        driver.get(url);
1123    }
1124
1125    @Override
1126    protected void navigate() throws Exception {
1127        // No-op for convenience
1128    }
1129
1130    protected void screenshot() {
1131        try {
1132            webDriverScreenshotHelper.screenshot(driver, this.getClass().getSimpleName(), testName.getMethodName(),
1133                    determinePage());
1134        } catch (Throwable t) {
1135            System.out.println("Problem with screenshot " + t.getMessage());
1136        }
1137    }
1138
1139    protected void startSession(Method method) throws Exception {
1140        testMethodName = method.getName(); // TestNG
1141    }
1142
1143    /**
1144     * Uses Selenium's findElements method which does not throw a test exception if not found.
1145     * @param by
1146     * @param selectText
1147     * @throws InterruptedException
1148     */
1149    protected void select(By by, String selectText) throws InterruptedException {
1150        //        checkForIncidentReport(by.toString(), "trying to select text " + selectText); // I think a report will now be picked-up by the jiraAwareFail
1151        WebElement select1 = findElement(by);
1152        WebDriverUtils.highlightElement(driver, select1);
1153        String name = select1.getAttribute("name");
1154        jGrowl("Select " + selectText + " from " + name);
1155        List<WebElement> options = select1.findElements(By.tagName("option"));
1156
1157        for (WebElement option : options) {
1158            if (option.getText().equals(selectText)) {
1159                option.click();
1160                break; // continuing the loop after clicking on an option often causes cache problems other times it seems breaking here causes hangs?!
1161            }
1162        }
1163    }
1164
1165    protected void selectByXpath(String locator, String selectText) throws InterruptedException {
1166        select(By.xpath(locator), selectText);
1167    }
1168
1169    protected void selectByName(String name, String selectText) throws InterruptedException {
1170        select(By.name(name), selectText);
1171    }
1172
1173    protected void selectChildWindow() {
1174        if (!driver.getWindowHandles().toArray()[1].toString().isEmpty()) {
1175            selectWindow(driver.getWindowHandles().toArray()[1].toString());
1176        }
1177    }
1178
1179    protected void selectParentWindow() {
1180        selectWindow(driver.getWindowHandles().toArray()[0].toString());
1181    }
1182
1183    protected void selectTopFrame() {
1184        driver.switchTo().defaultContent();
1185    }
1186
1187    protected void selectWindow(String locator) {
1188        driver.switchTo().window(locator);
1189    }
1190
1191    /**
1192     * If a window contains the given title switchTo it.
1193     * @param title
1194     */
1195    public void switchToWindow(String title) {
1196        Set<String> windows = driver.getWindowHandles();
1197
1198        for (String window : windows) {
1199            driver.switchTo().window(window);
1200            if (driver.getTitle().contains(title)) {
1201                return;
1202            }
1203        }
1204    }
1205
1206    /**
1207     * Tear down test as configured.  Do not allow exceptions to be thrown by tearDown, it kills the test run.
1208     * {@link WebDriverUtils#tearDown(boolean, String, String, String)}
1209     * {@link WebDriverUtils#REMOTE_PUBLIC_USERPOOL_PROPERTY}
1210     * {@link WebDriverUtils#dontTearDownPropertyNotSet()}
1211     * @throws Exception
1212     */
1213    @After
1214    public void tearDown() {
1215        try {
1216
1217            if (!isPassed()) {
1218                try { // if saucelabs has timed out getCurrentUrl throws an exception
1219                    System.out.println("Last AFT URL: " + driver.getCurrentUrl());
1220                } catch (Throwable t) {
1221                    System.out.println("Unable to determine LAST AFT URL due to " + t.getMessage());
1222                }
1223            }
1224
1225            try { // saucelabs
1226                if ((!isPassed() && webDriverScreenshotHelper.screenshotOnFailure()) || webDriverScreenshotHelper.screenshotSteps()) {
1227                    screenshot();
1228                }
1229            } catch (Throwable t2) {
1230                System.out.println("Unable to take failure screenshot " + t2.getMessage());
1231            }
1232
1233            try { // saucelabs
1234                if (isPassed() && WebDriverUtils.dontTearDownPropertyNotSet() && WebDriverUtils.dontTearDownOnFailure(isPassed())) {
1235                    logout();
1236                }
1237            } catch (Throwable t3) {
1238                System.out.println("Unable to logout " + t3.getMessage());
1239            }
1240
1241            WebDriverUtils.tearDown(isPassed(), sessionId, this.toString().trim(), user, getClass().getSimpleName(), testName.getMethodName());
1242        } catch (Throwable t) {
1243            System.out.println("Exception in tearDown " + t.getMessage());
1244            t.printStackTrace();
1245        }
1246
1247        // going to the login page and closing other windows so tests can be run in one browser
1248//        acceptAlertIfPresent();
1249//        closeAllOtherWindows(oneBrowserHandle);
1250//        driver.get(getBaseUrlString()
1251//                + "/kr-login/login?viewId=DummyLoginView&returnLocation=%2Fkr-krad%2Fkradsampleapp%3FviewId%3DKradSampleAppHome%26methodToCall%3Dstart");
1252//        acceptAlertIfPresent();
1253
1254        // comment out finally block for one browser
1255        finally {
1256            try {
1257                closeAndQuitWebDriver();
1258            } catch (Throwable t) {
1259                System.out.println(t.getMessage() + " occurred during tearDown, ignoring to avoid killing test run.");
1260                t.printStackTrace();
1261                System.out.println(t.getMessage() + " occurred during tearDown, ignoring to avoid killing test run.");
1262            }
1263        }
1264    }
1265
1266    /**
1267     * Failures in testSetup cause the test to not be recorded.  Future plans are to extract form @Before and call at the start of each test.
1268     * Setup the WebDriver properties, test, and login.  Named testSetUp so it runs after TestNG's startSession(Method)
1269     * {@link WebDriverUtils#determineUser(String)}
1270     * {@link WebDriverUtils#setUp(String, String, String, String)}
1271     */
1272    @Before
1273    public void testSetUp() {
1274        // TODO it would be better if all opening of urls and logging in was not done in setUp, failures in setUp case the test to not be recorded. extract to setUp and call first for all tests.
1275        try { // Don't throw any exception from this methods, exceptions in Before annotations really mess up maven, surefire, or failsafe
1276            setUpSetUp();
1277
1278            driver = WebDriverUtils.setUp(getClass().getSimpleName(), testMethodName); // one browser comment this out
1279
1280            String testUrl = getTestUrl();
1281            // TODO Got into the situation where the first url doesn't expect server, but all others do.  Readdress once
1282            // the NavIT WDIT conversion has been completed.
1283            if (!testUrl.startsWith("http")) {
1284                testUrl = getBaseUrlString() + testUrl;
1285            }
1286            WebDriverUtils.openTestUrl(driver, testUrl);
1287
1288//            oneBrowserHandle = driver.getWindowHandle(); // one browser other windows will be closed
1289//            System.out.println("One Browser handle " + oneBrowserHandle);
1290//            closeAllOtherWindows(oneBrowserHandle); // close all others than one browser
1291
1292            this.sessionId = ((RemoteWebDriver) driver).getSessionId().toString();
1293            System.out.println(jGrowlHeader + " sessionId is " + sessionId);
1294
1295//            if (isVisible(By.name("login_user"))) { // one browser
1296                login(driver, getUserName(), this);
1297//            }
1298
1299            navigateInternal(); // SeleniumBaseTest.fail from navigateInternal results in the test not being recorded as a failure in CI.
1300
1301            javascriptErrorsReport();
1302
1303        } catch (Throwable t) {
1304            System.out.println("Throwable " + t.getMessage() + " in Before annotated method is very bad, ignoring and letting first method of test class to fail.");
1305            t.printStackTrace();
1306            System.out.println("Throwable " + t.getMessage()
1307                    + " in Before annotated method is very bad, ignoring and letting first method of test class to fail.");
1308        }
1309    }
1310
1311    public void setUpSetUp() {
1312        determineTestMethodName();
1313        determineImplicitWait();
1314        determineUser();
1315        determineJgrowlHeader();
1316    }
1317
1318    protected void uncheck(By by) throws InterruptedException {
1319        WebElement element = findElement(by);
1320        if (element.isSelected()) {
1321            element.click();
1322        }
1323    }
1324
1325    protected void uncheckByName(String name) throws InterruptedException {
1326        uncheck(By.name(name));
1327    }
1328
1329    protected void uncheckByXpath(String locator) throws InterruptedException {
1330        uncheck(By.xpath(locator));
1331    }
1332
1333    protected void waitAndClick(String locator) throws InterruptedException {
1334        waitAndClick(locator, this.getClass().toString());
1335    }
1336
1337    protected void waitAndClick(By by) throws InterruptedException {
1338        jiraAwareWaitAndClick(by, this.getClass().toString());
1339    }
1340
1341    protected void waitAndClick(By by, JiraAwareFailable failable) throws InterruptedException {
1342        jiraAwareWaitAndClick(by, this.getClass().toString(), failable);
1343    }
1344
1345    protected void waitAndClick(String locator, String message) throws InterruptedException {
1346        jiraAwareWaitAndClick(By.cssSelector(locator), message);
1347    }
1348
1349    protected void waitAndClickById(String id) throws InterruptedException {
1350        jiraAwareWaitAndClick(By.id(id), this.getClass().toString());
1351    }
1352
1353    protected void waitAndClickById(String id, String message) throws InterruptedException {
1354        jiraAwareWaitAndClick(By.id(id), message);
1355    }
1356
1357    protected void waitAndClickByLinkText(String text) throws InterruptedException {
1358        waitAndClickByLinkText(text, this.getClass().toString());
1359    }
1360
1361    protected void waitAndClickByLinkText(String text, String message) throws InterruptedException {
1362        waitAndClickByLinkText(text, message, this);
1363    }
1364
1365    protected void waitAndClickByLinkText(String text, JiraAwareFailable failable) throws InterruptedException {
1366        waitAndClickByLinkText(text, this.getClass().toString(), failable);
1367    }
1368
1369    protected void waitAndClickByLinkText(String text, String message, JiraAwareFailable failable) throws InterruptedException {
1370        jGrowl("Click " + text + " link.");
1371        jiraAwareWaitAndClick(By.linkText(text), message, failable);
1372    }
1373
1374    protected void waitAndClickLabeledLink(String label, String linkText) throws InterruptedException {
1375        jGrowl("Click link " + linkText + " labeled with " + label);
1376        waitAndClick(By.xpath(
1377                "//th/label[contains(text(), '" + label + "')]/../following-sibling::*/div/span/a[contains(text(), '"
1378                        + linkText + "')]"));
1379    }
1380
1381    protected void waitAndClickLabeledQuickFinder(String label) throws InterruptedException {
1382        jGrowl("Click link quickfinder labeled with " + label);
1383        waitAndClick(By.xpath("//th/label[contains(text(), '" + label
1384                + "')]/../following-sibling::*/div/div/div/button[@class='btn btn-default uif-action icon-search']"));
1385        screenshot();
1386    }
1387
1388    protected void waitAndTypeLabeledInput(String label, String text) throws InterruptedException {
1389        jGrowl("Type " + text + " in input labeled with " + label);
1390        waitAndTypeByXpath("//th/label[contains(text(), '" + label + "')]/../following-sibling::*//input", text);
1391        screenshot();
1392    }
1393
1394    protected void waitAndSelectLabeled(String label, String text) throws InterruptedException {
1395        jGrowl("Select " + text + " labeled with " + label);
1396        waitAndSelectBy(By.xpath("//th/label[contains(text(), '" + label + "')]/../following-sibling::*//select"), text);
1397        screenshot();
1398    }
1399
1400    protected void waitAndClickLightBoxClose() throws InterruptedException {
1401        jGrowl("Click lightbox close");
1402        waitAndClickByXpath("//button[contains(text(),'x')]");
1403    }
1404
1405    protected void waitAndClickLinkContainingText(String linkText) throws InterruptedException {
1406        waitAndClickLinkContainingText(linkText, this.getClass().toString());
1407    }
1408
1409    protected void waitAndClickLinkContainingText(String linkText, String message) throws InterruptedException {
1410        jGrowl("Click link containing " + linkText + " .");
1411        waitAndClickByXpath("//a[contains(text(), '" + linkText + "')]", message);
1412    }
1413
1414    protected void waitAndClickByName(String name) throws InterruptedException {
1415        jGrowl("Click By Name " + name);
1416        jiraAwareWaitAndClick(By.name(name), this.getClass().toString());
1417    }
1418
1419    protected void waitAndClickByValue(String value) throws InterruptedException {
1420        waitAndGetElementByAttributeValue("value", value).click();
1421    }
1422
1423    protected void waitAndClickByXpath(String xpath) throws InterruptedException {
1424        waitAndClick(By.xpath(xpath));
1425    }
1426
1427    protected void waitAndClickByXpath(String xpath, JiraAwareFailable failable) throws InterruptedException {
1428        waitAndClick(By.xpath(xpath), failable);
1429    }
1430
1431    protected void waitAndClickByName(String name, String message) throws InterruptedException {
1432        jiraAwareWaitAndClick(By.name(name), message);
1433    }
1434
1435    protected void waitAndClickByXpath(String xpath, String message) throws InterruptedException {
1436        jiraAwareWaitAndClick(By.xpath(xpath), message);
1437    }
1438
1439    protected void waitAndClickByXpath(String xpath, int waitSeconds, String message) throws InterruptedException {
1440        jiraAwareWaitAndClick(By.xpath(xpath), waitSeconds, message, this);
1441    }
1442
1443    protected void waitAndClickButtonByText(String buttonText) throws InterruptedException {
1444        waitAndClickButtonByText(buttonText, this.getClass().toString());
1445    }
1446
1447    protected void waitAndClickButtonByText(String buttonText, int waitSeconds) throws InterruptedException {
1448        waitAndClickButtonByText(buttonText, waitSeconds, this.getClass().toString());
1449    }
1450
1451    protected void waitAndClickButtonByText(String buttonText, String message) throws InterruptedException {
1452        jGrowl("Click " + buttonText + " button.");
1453        waitAndClickByXpath("//button[contains(text(), '" + buttonText + "')]", message);
1454    }
1455
1456    protected void waitAndClickButtonByText(String buttonText, int waitSeconds, String message) throws InterruptedException {
1457        jGrowl("Click " + buttonText + " button.");
1458        waitAndClickByXpath("//button[contains(text(), '" + buttonText + "')]", waitSeconds, message);
1459    }
1460
1461    protected void waitAndClickButtonByExactText(String buttonText) throws InterruptedException {
1462        waitAndClickButtonByExactText(buttonText, this.getClass().toString());
1463    }
1464
1465    protected void waitAndClickButtonByExactText(String buttonText, String message) throws InterruptedException {
1466        jGrowl("Click " + buttonText + " button.");
1467        waitAndClickByXpath("//button[normalize-space(.)='" + buttonText + "']", message);
1468    }
1469
1470    protected void waitAndClickAllByName(String name) throws InterruptedException{
1471        List<WebElement> elements = driver.findElements(By.name(name));
1472        for(WebElement ele : elements){
1473            ele.click();
1474        }
1475    }
1476    protected void waitAndClickConfirmCancelOk() throws InterruptedException {
1477        jGrowl("Click OK Confirmation");
1478        String xpath = "//div[@data-parent='ConfirmCancelDialog']/button[contains(text(),'OK')]";
1479        waitForElementVisibleBy(By.xpath(xpath)).click();
1480    }
1481
1482    protected void waitAndClickConfirmBlanketApproveOk() throws InterruptedException {
1483        jGrowl("Click OK Confirmation");
1484        String xpath = "//div[@data-parent='ConfirmBlanketApproveDialog']/button[contains(text(),'OK')]";
1485        waitForElementVisibleBy(By.xpath(xpath)).click();
1486    }
1487
1488    protected void waitAndClickConfirmDeleteYes() throws InterruptedException {
1489        jGrowl("Click Yes Confirmation");
1490        String xpath = "//section[@id='DialogGroup-DeleteFileUploadLine']//button[contains(text(),'Yes')]";
1491        waitForElementVisibleBy(By.xpath(xpath)).click();
1492    }
1493
1494    protected void waitAndClickConfirmSaveOnClose() throws InterruptedException {
1495        jGrowl("Click OK Confirmation");
1496        waitForElementVisibleBy(By.xpath("//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'Yes')]"));
1497        waitAndClickByXpath("//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'Yes')]");
1498    }
1499
1500    protected void waitAndClickCancelSaveOnClose() throws InterruptedException {
1501        jGrowl("Click OK Confirmation");
1502        waitForElementVisibleBy(By.xpath(
1503                "//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'No')]"));
1504        waitAndClickByXpath("//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'No')]");
1505    }
1506
1507
1508    protected void waitAndClickConfirmSubmitOk() throws InterruptedException {
1509        jGrowl("Click OK Confirmation");
1510        String xpath = "//div[@data-parent='ConfirmSubmitDialog']/button[contains(text(),'OK')]";
1511        waitForElementVisibleBy(By.xpath(xpath)).click();
1512    }
1513
1514    protected void waitAndClickDropDown(String dropDownText) throws InterruptedException {
1515        jGrowl("Click the " + dropDownText + " drop down.");
1516        WebElement dropdownMenu = waitAndGetElementByAttributeValue("class", "dropdown-toggle");
1517        Thread.sleep(1000);
1518        dropdownMenu.click();
1519        waitAndClickByLinkText(dropDownText, "dropdown click " + dropDownText + " problem");
1520    }
1521
1522    protected void waitAndClickReturnValue() throws InterruptedException {
1523        waitAndClickByLinkText(RETURN_VALUE_LINK_TEXT, "Unable to click return value " + this.getClass().toString());
1524    }
1525
1526    protected void waitAndClickReturnValue(String message) throws InterruptedException {
1527        waitAndClickByLinkText(RETURN_VALUE_LINK_TEXT, message);
1528    }
1529
1530    protected void waitAndClickSearch3() throws InterruptedException {
1531        jGrowl("Click Search");
1532        waitAndClickByXpath(SEARCH_XPATH_3);
1533    }
1534
1535    protected String waitAndGetAttribute(By by, String attribute) throws InterruptedException {
1536        jiraAwareWaitFor(by, attribute);
1537
1538        return findElement(by).getAttribute(attribute);
1539    }
1540
1541    /**
1542     * Get value of any attribute by using element name
1543     *
1544     * @param name name of an element
1545     * @param attribute the name of an attribute whose value is to be retrieved
1546     */
1547    protected String waitAndGetAttributeByName(String name, String attribute) throws InterruptedException {
1548        return waitAndGetAttribute(By.name(name), attribute);
1549    }
1550
1551    /**
1552     * Get value of any attribute by using element xpath
1553     *
1554     * @param locator locating mechanism of an element
1555     * @param attribute the name of an attribute whose value is to be retrieved
1556     */
1557    protected String waitAndGetAttributeByXpath(String locator, String attribute) throws InterruptedException {
1558        return waitAndGetAttribute(By.xpath(locator), attribute);
1559    }
1560
1561    protected WebElement waitAndGetElementByAttributeValue(String attribute, String attributeValue) throws InterruptedException {
1562        return WebDriverUtils.waitAndGetElementByAttributeValue(driver, attribute, attributeValue, waitSeconds);
1563    }
1564
1565    protected List<WebElement> waitAndGetElementsByAttributeValue(String attribute, String attributeValue) throws InterruptedException {
1566        // jenkins implies that implicitlyWait is worse than sleep loop for finding elements by 100+ test failures on the old sampleapp
1567        //        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1568        //        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1569
1570        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1571
1572        boolean failed = false;
1573
1574        for (int second = 0;; second++) {
1575            Thread.sleep(1000);
1576            if (second >= waitSeconds)
1577                failed = true;
1578            try {
1579                if (failed || (getElementsByAttributeValue(attribute, attributeValue) != null)) {
1580                    break;
1581                }
1582            } catch (Exception e) {}
1583        }
1584
1585        List<WebElement> elements = getElementsByAttributeValue(attribute, attributeValue);
1586        driver.manage().timeouts().implicitlyWait(WebDriverUtils.configuredImplicityWait(), TimeUnit.SECONDS);
1587        return elements;
1588    }
1589
1590    protected String waitAndGetLabeledText(String label) throws InterruptedException {
1591        return waitForElementPresent(By.xpath("//th/label[contains(text(), '"
1592                + label
1593                + "')]/../following-sibling::*/div/span")).getText();
1594    }
1595
1596    protected String[] waitAndGetText(By by) throws InterruptedException {
1597        WebDriverUtils.waitFors(driver, WebDriverUtils.configuredImplicityWait(), by, this.getClass().toString());
1598        List<WebElement> found = findElements(by);
1599        String[] texts = new String[found.size()];
1600        int i = 0;
1601
1602        for (WebElement element: found) {
1603            texts[i++] = element.getText();
1604        }
1605
1606        if (texts.length == 0) {
1607            jiraAwareFail(by.toString());
1608        }
1609
1610        return texts;
1611    }
1612
1613
1614    protected void waitAndSelectBy(By by, String selectText) throws InterruptedException {
1615        waitFor(by, selectText + " not found.");
1616        select(by, selectText);
1617    }
1618
1619    protected void waitAndSelectByName(String name, String selectText) throws InterruptedException {
1620        waitAndSelectBy(By.name(name), selectText);
1621    }
1622
1623    protected WebElement waitAndType(By by, String text) throws InterruptedException {
1624        return waitAndType(by, text, this.getClass().toString());
1625    }
1626
1627    protected WebElement waitAndType(String selector, String text) throws InterruptedException {
1628        return waitAndType(By.cssSelector(selector), text);
1629    }
1630
1631    protected WebElement waitAndTypeById(String id, String text) throws InterruptedException {
1632        return waitAndType(By.id(id), text);
1633    }
1634
1635    protected WebElement waitAndTypeByXpath(String locator, String text) throws InterruptedException {
1636        return waitAndType(By.xpath(locator), text);
1637    }
1638
1639    protected WebElement waitAndTypeByXpath(String locator, String text, String message) throws InterruptedException {
1640        return waitAndType(By.xpath(locator), text, message);
1641    }
1642
1643    protected WebElement waitAndTypeByName(String name, String text) throws InterruptedException {
1644        return waitAndType(By.name(name), text);
1645    }
1646
1647    protected boolean waitAreAnyVisible(By[] bys) throws InterruptedException {
1648        if (bys == null || bys.length == 0 ) {
1649            return false;
1650        }
1651
1652        for (int second = 0; second < waitSeconds; second++) {
1653
1654            if (isVisible(bys)) {
1655                return true;
1656            }
1657
1658            Thread.sleep(1000);
1659        }
1660
1661        return false;
1662    }
1663
1664    /**
1665     * {@deprecated} use any of the various wait methods over this, waitForElementPresent for example.
1666     * @throws InterruptedException
1667     */
1668    protected void waitForPageToLoad() throws InterruptedException {
1669        Thread.sleep(5000);
1670        checkForIncidentReport();
1671    }
1672
1673    protected WebElement waitFor(By by) throws InterruptedException {
1674        return jiraAwareWaitFor(by, this.getClass().toString());
1675    }
1676
1677    /**
1678     * Should be called from jiraAwareWaitFor to get KULRICE error output in CI.
1679     *
1680     * Inner most waitFor, let it throw the failure so the timeout message reflects the waitSeconds time, not the 1
1681     * second it is set to before returning.
1682     * @param by
1683     * @param message
1684     * @throws InterruptedException
1685     */
1686    protected void waitFor(By by, String message) throws InterruptedException {
1687        WebDriverUtils.waitFor(this.driver, this.waitSeconds, by, message);
1688    }
1689
1690    /**
1691     * Uses Selenium's findElements method which does not throw a test exception if not found.
1692     * @param elementLocator
1693     * @param message
1694     * @throws InterruptedException
1695     */
1696    protected WebElement waitForElementVisible(String elementLocator, String message) throws InterruptedException {
1697        return waitForElementVisibleBy(By.cssSelector(elementLocator), message);
1698    }
1699
1700    protected WebElement waitForElementVisibleBy(By by) throws InterruptedException {
1701        return waitForElementVisibleBy(by, by.toString() + " NOT visible for class " + this.getClass().getSimpleName());
1702    }
1703
1704    protected WebElement waitForElementVisibleBy(By by, String message) throws InterruptedException {
1705        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1706
1707        boolean failed = false;
1708
1709        for (int second = 0;; second++) {
1710            if (second >= waitSeconds)
1711                failed = true;
1712            try {
1713                if (failed || driver.findElement(by).isDisplayed())
1714                    break;
1715            } catch (Exception e) {}
1716            Thread.sleep(1000);
1717        }
1718
1719        checkForIncidentReport(by.toString()); // after timeout to be sure page is loaded
1720
1721        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1722
1723        if (failed) {
1724            jiraAwareFail("timeout of " + waitSeconds + " seconds waiting for " + by + " " + message + " " + driver
1725                    .getCurrentUrl());
1726            return null;
1727        }
1728        return driver.findElements(by).get(0);
1729    }
1730
1731    protected void waitForElementVisibleById(String id, String message) throws InterruptedException {
1732        waitForElementVisibleBy(By.id(id), message);
1733    }
1734
1735    protected WebElement waitForElementPresent(By by) throws InterruptedException {
1736        return jiraAwareWaitFor(by, this.getClass().toString());
1737    }
1738
1739    protected WebElement waitForElementPresent(By by, String message) throws InterruptedException {
1740        return jiraAwareWaitFor(by, message);
1741    }
1742
1743    protected WebElement waitForElementPresent(String locator) throws InterruptedException {
1744        return jiraAwareWaitFor(By.cssSelector(locator), this.getClass().toString());
1745    }
1746
1747    protected WebElement waitForElementPresentByClassName(String name) throws InterruptedException {
1748        return jiraAwareWaitFor(By.className(name), this.getClass().toString());
1749    }
1750
1751    protected WebElement waitForElementPresentByClassName(String name, String message) throws InterruptedException {
1752        return jiraAwareWaitFor(By.className(name), message);
1753    }
1754
1755    protected WebElement waitForElementPresentByClassName(String name, int seconds) throws InterruptedException {
1756        return jiraAwareWaitFor(By.className(name), seconds, this.getClass().toString());
1757    }
1758
1759    protected void waitForElementsPresentByClassName(String name, String message) throws InterruptedException {
1760        jiraAwareWaitFors(By.className(name), message);
1761    }
1762
1763    protected String waitForLabeledText(String label) throws InterruptedException {
1764        return waitForElementVisibleBy(By.xpath("//th/label[contains(text(), '"
1765                + label
1766                + "')]/../following-sibling::*/div/span")).getText();
1767    }
1768
1769    /**
1770     * {@see WebDriverUtils#waitFor}.
1771     *
1772     * @param by to find
1773     * @param message on failure
1774     */
1775    protected List<WebElement> waitAndGetElementsFor(By by, String message) throws InterruptedException {
1776        try {
1777            return WebDriverUtils.waitFors(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
1778        } catch (Throwable t) {
1779            jiraAwareFail(by, message, t);
1780        }
1781        return new ArrayList<WebElement>();
1782    }
1783
1784    protected WebElement waitForElementPresentById(String id) throws InterruptedException {
1785        return jiraAwareWaitFor(By.id(id), this.getClass().toString());
1786    }
1787
1788    protected void waitForElementPresentById(String id, String message) throws InterruptedException {
1789        jiraAwareWaitFor(By.id(id), message);
1790    }
1791
1792    protected void waitForElementPresentById(String id, String message, int seconds) throws InterruptedException {
1793        jiraAwareWaitFor(By.id(id), seconds, message);
1794    }
1795
1796    protected void waitForElementsPresentById(String id, String message) throws InterruptedException {
1797        jiraAwareWaitFors(By.id(id), message);
1798    }
1799
1800    protected WebElement waitForElementPresentByName(String name) throws InterruptedException {
1801        return waitForElementPresentByName(name, this.getClass().toString());
1802    }
1803
1804    protected WebElement waitForElementPresentByName(String name, String message) throws InterruptedException {
1805        return jiraAwareWaitFor(By.name(name), message);
1806    }
1807
1808    protected WebElement waitForElementPresentByXpath(String xpath) throws InterruptedException {
1809        return jiraAwareWaitFor(By.xpath(xpath), this.getClass().toString());
1810    }
1811
1812    protected WebElement waitForElementPresentByXpath(String xpath, String message) throws InterruptedException {
1813        return jiraAwareWaitFor(By.xpath(xpath), message);
1814    }
1815
1816    protected void waitForElementsPresentByXpath(String xpathLocator) throws InterruptedException {
1817        jiraAwareWaitFors(By.xpath(xpathLocator), this.getClass().toString());
1818    }
1819
1820    protected void waitForElementNotPresent(By by) throws InterruptedException {
1821        waitForElementNotPresent(by, WebDriverUtils.configuredImplicityWait());
1822    }
1823
1824    protected void waitForElementNotPresent(By by, int secondsToWait) throws InterruptedException {
1825        waitForElementNotPresent(by, this.getClass().getSimpleName(), secondsToWait);
1826    }
1827
1828    protected void waitForElementNotPresent(By by, String message) throws InterruptedException {
1829        waitForElementNotPresent(by, this.getClass().getSimpleName(), WebDriverUtils.configuredImplicityWait());
1830    }
1831
1832    protected void waitForElementNotPresent(By by, String message, int secondsToWait) throws InterruptedException {
1833        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1834        while (isElementPresent(by)) {
1835            if (secondsToWait == 0) {
1836                break;
1837            }
1838            secondsToWait -= 1;
1839            Thread.sleep(1000);
1840        }
1841        if (isElementPresent(by)) {
1842            jiraAwareFail(by + " is still present " + message);
1843        }
1844        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1845    }
1846
1847
1848    protected boolean waitForIsTextPresent(String text) throws InterruptedException {
1849        boolean present = false;
1850        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1851        int secondsToWait = WebDriverUtils.configuredImplicityWait();
1852        while (!isTextPresent(text) && secondsToWait > 0) {
1853            secondsToWait -= 1;
1854            Thread.sleep(1000);
1855        }
1856        if (isTextPresent(text)) {
1857            present = true;
1858        }
1859        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1860        return present;
1861    }
1862
1863    protected void waitForProgress(String altText) throws InterruptedException {
1864        waitForProgress(altText, waitSeconds);
1865    }
1866
1867    protected void waitForProgress(String altText, int timeout) throws InterruptedException {
1868        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1869        for (int second = 0;; second++) {
1870            Thread.sleep(1000); // sleep for a second first, give element time to exist
1871
1872            if (second >= timeout) {
1873                jiraAwareFail(TIMEOUT_MESSAGE + " still Loading after " + timeout + " seconds.");
1874            }
1875
1876            try {
1877                if (!isElementPresentByXpath("//img[@alt='" + altText + "']") || !isVisible(By.xpath("//img[@alt='" + altText + "']"))) {
1878                    break;
1879                }
1880            } catch (Exception e) {
1881                // assume timing with img going away and continue with test
1882                break;
1883            }
1884
1885        }
1886        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1887    }
1888
1889    protected void waitForProgressAddingLine() throws InterruptedException {
1890        waitForProgress("Adding Line...");
1891    }
1892
1893    protected void waitForProgressDeletingLine() throws InterruptedException {
1894        waitForProgress("Deleting Line...");
1895    }
1896
1897    protected void waitForProgressAddingLine(int secondsToWait) throws InterruptedException {
1898        waitForProgress("Adding Line...", secondsToWait);
1899    }
1900
1901    protected void waitForProgressLoading() throws InterruptedException {
1902        waitForProgress("Loading...", WebDriverUtils.configuredImplicityWait() * 4);
1903    }
1904
1905    protected void waitForProgressLoading(int secondsToWait) throws InterruptedException {
1906        waitForProgress("Loading...", secondsToWait);
1907    }
1908
1909    protected void waitForProgressSaving() throws InterruptedException {
1910        waitForProgress("Saving...", WebDriverUtils.configuredImplicityWait() * 4);
1911    }
1912
1913    protected void waitForProgressSaving(int secondsToWait) throws InterruptedException {
1914        waitForProgress("Saving...", secondsToWait);
1915    }
1916
1917    protected void waitForTextPresent(String text) throws InterruptedException {
1918        waitForTextPresent(text, WebDriverUtils.configuredImplicityWait());
1919    }
1920
1921    protected void waitForTextPresent(String text, String message) throws InterruptedException {
1922        waitForTextPresent(text, WebDriverUtils.configuredImplicityWait(), message);
1923    }
1924
1925    protected void waitForTextPresent(String text, int secondsToWait) throws InterruptedException {
1926        waitForTextPresent(text, secondsToWait, this.getClass().getSimpleName());
1927    }
1928
1929    protected void waitForTextPresent(String text, int secondsToWait, String message) throws InterruptedException {
1930        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1931        while (!isTextPresent(text) && secondsToWait > 0) {
1932            secondsToWait -= 1;
1933            Thread.sleep(1000);
1934        }
1935        if (!isTextPresent(text)) {
1936            jiraAwareFail(message + " " + text + " is not present for " + this.getClass().toString());
1937        }
1938        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1939    }
1940
1941    protected void waitForTextNotPresent(String text) throws InterruptedException {
1942        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1943        int secondsToWait = WebDriverUtils.configuredImplicityWait();
1944        while (isTextPresent(text) && secondsToWait > 0) {
1945            secondsToWait -= 1;
1946            Thread.sleep(1000);
1947        }
1948        if (isTextPresent(text)) {
1949            jiraAwareFail(text + " is still present for " + this.getClass().toString());
1950        }
1951        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1952    }
1953
1954    protected void waitIsVisible(By by) throws InterruptedException {
1955        waitIsVisible(by, this.getClass().getSimpleName());
1956    }
1957
1958    protected void waitIsVisible(By by, String message) throws InterruptedException {
1959        for (int second = 0;; second++) {
1960            if (second >= waitSeconds) {
1961                jiraAwareFail(TIMEOUT_MESSAGE + " " + by.toString() + " " + message);
1962            }
1963            if (isVisible(by)) {
1964                break;
1965            }
1966            Thread.sleep(1000);
1967        }
1968
1969        if (!isVisible(by)) {
1970            jiraAwareFail(by.toString() + " not visiable", message);
1971        }
1972    }
1973
1974    protected void waitIsVisible(String locator) throws InterruptedException {
1975        waitIsVisible(By.cssSelector(locator));
1976    }
1977
1978    protected void waitIsVisibleByXpath(String locator) throws InterruptedException {
1979        waitIsVisible(By.xpath(locator));
1980    }
1981
1982    protected void waitIsVisibleByXpath(String locator, String message) throws InterruptedException {
1983        waitIsVisible(By.xpath(locator), message);
1984    }
1985
1986    protected void waitNotVisible(By by) throws InterruptedException {
1987        waitNotVisible(by, this.getClass().getSimpleName());
1988    }
1989
1990    protected void waitNotVisible(By by, String message) throws InterruptedException {
1991        for (int second = 0;; second++) {
1992            if (second >= waitSeconds) {
1993                jiraAwareFail(TIMEOUT_MESSAGE + " " + message);
1994            }
1995            if (!isVisible(by)) {
1996                break;
1997            }
1998            Thread.sleep(1000);
1999        }
2000    }
2001
2002    protected void waitNotVisibleByXpath(String locator) throws InterruptedException {
2003        waitNotVisible(By.xpath(locator));
2004    }
2005
2006    protected void waitNotVisibleByXpath(String locator, String message) throws InterruptedException {
2007        waitNotVisible(By.xpath(locator), message);
2008    }
2009}