001/**
002 * Copyright 2005-2016 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        selectWindow(driver.getWindowHandles().toArray()[1].toString());
1175    }
1176
1177    protected void selectParentWindow() {
1178        selectWindow(driver.getWindowHandles().toArray()[0].toString());
1179    }
1180
1181    protected void selectTopFrame() {
1182        driver.switchTo().defaultContent();
1183    }
1184
1185    protected void selectWindow(String locator) {
1186        driver.switchTo().window(locator);
1187    }
1188
1189    /**
1190     * If a window contains the given title switchTo it.
1191     * @param title
1192     */
1193    public void switchToWindow(String title) {
1194        Set<String> windows = driver.getWindowHandles();
1195
1196        for (String window : windows) {
1197            driver.switchTo().window(window);
1198            if (driver.getTitle().contains(title)) {
1199                return;
1200            }
1201        }
1202    }
1203
1204    /**
1205     * Tear down test as configured.  Do not allow exceptions to be thrown by tearDown, it kills the test run.
1206     * {@link WebDriverUtils#tearDown(boolean, String, String, String)}
1207     * {@link WebDriverUtils#REMOTE_PUBLIC_USERPOOL_PROPERTY}
1208     * {@link WebDriverUtils#dontTearDownPropertyNotSet()}
1209     * @throws Exception
1210     */
1211    @After
1212    public void tearDown() {
1213        try {
1214
1215            if (!isPassed()) {
1216                try { // if saucelabs has timed out getCurrentUrl throws an exception
1217                    System.out.println("Last AFT URL: " + driver.getCurrentUrl());
1218                } catch (Throwable t) {
1219                    System.out.println("Unable to determine LAST AFT URL due to " + t.getMessage());
1220                }
1221            }
1222
1223            try { // saucelabs
1224                if ((!isPassed() && webDriverScreenshotHelper.screenshotOnFailure()) || webDriverScreenshotHelper.screenshotSteps()) {
1225                    screenshot();
1226                }
1227            } catch (Throwable t2) {
1228                System.out.println("Unable to take failure screenshot " + t2.getMessage());
1229            }
1230
1231            try { // saucelabs
1232                if (isPassed() && WebDriverUtils.dontTearDownPropertyNotSet() && WebDriverUtils.dontTearDownOnFailure(isPassed())) {
1233                    logout();
1234                }
1235            } catch (Throwable t3) {
1236                System.out.println("Unable to logout " + t3.getMessage());
1237            }
1238
1239            WebDriverUtils.tearDown(isPassed(), sessionId, this.toString().trim(), user, getClass().getSimpleName(), testName.getMethodName());
1240        } catch (Throwable t) {
1241            System.out.println("Exception in tearDown " + t.getMessage());
1242            t.printStackTrace();
1243        }
1244
1245        // going to the login page and closing other windows so tests can be run in one browser
1246//        acceptAlertIfPresent();
1247//        closeAllOtherWindows(oneBrowserHandle);
1248//        driver.get(getBaseUrlString()
1249//                + "/kr-login/login?viewId=DummyLoginView&returnLocation=%2Fkr-krad%2Fkradsampleapp%3FviewId%3DKradSampleAppHome%26methodToCall%3Dstart");
1250//        acceptAlertIfPresent();
1251
1252        // comment out finally block for one browser
1253        finally {
1254            try {
1255                closeAndQuitWebDriver();
1256            } catch (Throwable t) {
1257                System.out.println(t.getMessage() + " occurred during tearDown, ignoring to avoid killing test run.");
1258                t.printStackTrace();
1259                System.out.println(t.getMessage() + " occurred during tearDown, ignoring to avoid killing test run.");
1260            }
1261        }
1262    }
1263
1264    /**
1265     * 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.
1266     * Setup the WebDriver properties, test, and login.  Named testSetUp so it runs after TestNG's startSession(Method)
1267     * {@link WebDriverUtils#determineUser(String)}
1268     * {@link WebDriverUtils#setUp(String, String, String, String)}
1269     */
1270    @Before
1271    public void testSetUp() {
1272        // 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.
1273        try { // Don't throw any exception from this methods, exceptions in Before annotations really mess up maven, surefire, or failsafe
1274            setUpSetUp();
1275
1276            driver = WebDriverUtils.setUp(getClass().getSimpleName(), testMethodName); // one browser comment this out
1277
1278            String testUrl = getTestUrl();
1279            // TODO Got into the situation where the first url doesn't expect server, but all others do.  Readdress once
1280            // the NavIT WDIT conversion has been completed.
1281            if (!testUrl.startsWith("http")) {
1282                testUrl = getBaseUrlString() + testUrl;
1283            }
1284            WebDriverUtils.openTestUrl(driver, testUrl);
1285
1286//            oneBrowserHandle = driver.getWindowHandle(); // one browser other windows will be closed
1287//            System.out.println("One Browser handle " + oneBrowserHandle);
1288//            closeAllOtherWindows(oneBrowserHandle); // close all others than one browser
1289
1290            this.sessionId = ((RemoteWebDriver) driver).getSessionId().toString();
1291            System.out.println(jGrowlHeader + " sessionId is " + sessionId);
1292
1293//            if (isVisible(By.name("login_user"))) { // one browser
1294                login(driver, getUserName(), this);
1295//            }
1296
1297            navigateInternal(); // SeleniumBaseTest.fail from navigateInternal results in the test not being recorded as a failure in CI.
1298
1299            javascriptErrorsReport();
1300
1301        } catch (Throwable t) {
1302            System.out.println("Throwable " + t.getMessage() + " in Before annotated method is very bad, ignoring and letting first method of test class to fail.");
1303            t.printStackTrace();
1304            System.out.println("Throwable " + t.getMessage()
1305                    + " in Before annotated method is very bad, ignoring and letting first method of test class to fail.");
1306        }
1307    }
1308
1309    public void setUpSetUp() {
1310        determineTestMethodName();
1311        determineImplicitWait();
1312        determineUser();
1313        determineJgrowlHeader();
1314    }
1315
1316    protected void uncheck(By by) throws InterruptedException {
1317        WebElement element = findElement(by);
1318        if (element.isSelected()) {
1319            element.click();
1320        }
1321    }
1322
1323    protected void uncheckByName(String name) throws InterruptedException {
1324        uncheck(By.name(name));
1325    }
1326
1327    protected void uncheckByXpath(String locator) throws InterruptedException {
1328        uncheck(By.xpath(locator));
1329    }
1330
1331    protected void waitAndClick(String locator) throws InterruptedException {
1332        waitAndClick(locator, this.getClass().toString());
1333    }
1334
1335    protected void waitAndClick(By by) throws InterruptedException {
1336        jiraAwareWaitAndClick(by, this.getClass().toString());
1337    }
1338
1339    protected void waitAndClick(By by, JiraAwareFailable failable) throws InterruptedException {
1340        jiraAwareWaitAndClick(by, this.getClass().toString(), failable);
1341    }
1342
1343    protected void waitAndClick(String locator, String message) throws InterruptedException {
1344        jiraAwareWaitAndClick(By.cssSelector(locator), message);
1345    }
1346
1347    protected void waitAndClickById(String id) throws InterruptedException {
1348        jiraAwareWaitAndClick(By.id(id), this.getClass().toString());
1349    }
1350
1351    protected void waitAndClickById(String id, String message) throws InterruptedException {
1352        jiraAwareWaitAndClick(By.id(id), message);
1353    }
1354
1355    protected void waitAndClickByLinkText(String text) throws InterruptedException {
1356        waitAndClickByLinkText(text, this.getClass().toString());
1357    }
1358
1359    protected void waitAndClickByLinkText(String text, String message) throws InterruptedException {
1360        waitAndClickByLinkText(text, message, this);
1361    }
1362
1363    protected void waitAndClickByLinkText(String text, JiraAwareFailable failable) throws InterruptedException {
1364        waitAndClickByLinkText(text, this.getClass().toString(), failable);
1365    }
1366
1367    protected void waitAndClickByLinkText(String text, String message, JiraAwareFailable failable) throws InterruptedException {
1368        jGrowl("Click " + text + " link.");
1369        jiraAwareWaitAndClick(By.linkText(text), message, failable);
1370    }
1371
1372    protected void waitAndClickLabeledLink(String label, String linkText) throws InterruptedException {
1373        jGrowl("Click link " + linkText + " labeled with " + label);
1374        waitAndClick(By.xpath(
1375                "//th/label[contains(text(), '" + label + "')]/../following-sibling::*/div/span/a[contains(text(), '"
1376                        + linkText + "')]"));
1377    }
1378
1379    protected void waitAndClickLabeledQuickFinder(String label) throws InterruptedException {
1380        jGrowl("Click link quickfinder labeled with " + label);
1381        waitAndClick(By.xpath("//th/label[contains(text(), '" + label
1382                + "')]/../following-sibling::*/div/div/div/button[@class='btn btn-default uif-action icon-search']"));
1383        screenshot();
1384    }
1385
1386    protected void waitAndTypeLabeledInput(String label, String text) throws InterruptedException {
1387        jGrowl("Type " + text + " in input labeled with " + label);
1388        waitAndTypeByXpath("//th/label[contains(text(), '" + label + "')]/../following-sibling::*//input", text);
1389        screenshot();
1390    }
1391
1392    protected void waitAndSelectLabeled(String label, String text) throws InterruptedException {
1393        jGrowl("Select " + text + " labeled with " + label);
1394        waitAndSelectBy(By.xpath("//th/label[contains(text(), '" + label + "')]/../following-sibling::*//select"), text);
1395        screenshot();
1396    }
1397
1398    protected void waitAndClickLightBoxClose() throws InterruptedException {
1399        jGrowl("Click lightbox close");
1400        waitAndClickByXpath("//button[contains(text(),'x')]");
1401    }
1402
1403    protected void waitAndClickLinkContainingText(String linkText) throws InterruptedException {
1404        waitAndClickLinkContainingText(linkText, this.getClass().toString());
1405    }
1406
1407    protected void waitAndClickLinkContainingText(String linkText, String message) throws InterruptedException {
1408        jGrowl("Click link containing " + linkText + " .");
1409        waitAndClickByXpath("//a[contains(text(), '" + linkText + "')]", message);
1410    }
1411
1412    protected void waitAndClickByName(String name) throws InterruptedException {
1413        jGrowl("Click By Name " + name);
1414        jiraAwareWaitAndClick(By.name(name), this.getClass().toString());
1415    }
1416
1417    protected void waitAndClickByValue(String value) throws InterruptedException {
1418        waitAndGetElementByAttributeValue("value", value).click();
1419    }
1420
1421    protected void waitAndClickByXpath(String xpath) throws InterruptedException {
1422        waitAndClick(By.xpath(xpath));
1423    }
1424
1425    protected void waitAndClickByXpath(String xpath, JiraAwareFailable failable) throws InterruptedException {
1426        waitAndClick(By.xpath(xpath), failable);
1427    }
1428
1429    protected void waitAndClickByName(String name, String message) throws InterruptedException {
1430        jiraAwareWaitAndClick(By.name(name), message);
1431    }
1432
1433    protected void waitAndClickByXpath(String xpath, String message) throws InterruptedException {
1434        jiraAwareWaitAndClick(By.xpath(xpath), message);
1435    }
1436
1437    protected void waitAndClickByXpath(String xpath, int waitSeconds, String message) throws InterruptedException {
1438        jiraAwareWaitAndClick(By.xpath(xpath), waitSeconds, message, this);
1439    }
1440
1441    protected void waitAndClickButtonByText(String buttonText) throws InterruptedException {
1442        waitAndClickButtonByText(buttonText, this.getClass().toString());
1443    }
1444
1445    protected void waitAndClickButtonByText(String buttonText, int waitSeconds) throws InterruptedException {
1446        waitAndClickButtonByText(buttonText, waitSeconds, this.getClass().toString());
1447    }
1448
1449    protected void waitAndClickButtonByText(String buttonText, String message) throws InterruptedException {
1450        jGrowl("Click " + buttonText + " button.");
1451        waitAndClickByXpath("//button[contains(text(), '" + buttonText + "')]", message);
1452    }
1453
1454    protected void waitAndClickButtonByText(String buttonText, int waitSeconds, String message) throws InterruptedException {
1455        jGrowl("Click " + buttonText + " button.");
1456        waitAndClickByXpath("//button[contains(text(), '" + buttonText + "')]", waitSeconds, message);
1457    }
1458
1459    protected void waitAndClickButtonByExactText(String buttonText) throws InterruptedException {
1460        waitAndClickButtonByExactText(buttonText, this.getClass().toString());
1461    }
1462
1463    protected void waitAndClickButtonByExactText(String buttonText, String message) throws InterruptedException {
1464        jGrowl("Click " + buttonText + " button.");
1465        waitAndClickByXpath("//button[normalize-space(.)='" + buttonText + "']", message);
1466    }
1467
1468    protected void waitAndClickAllByName(String name) throws InterruptedException{
1469        List<WebElement> elements = driver.findElements(By.name(name));
1470        for(WebElement ele : elements){
1471            ele.click();
1472        }
1473    }
1474    protected void waitAndClickConfirmCancelOk() throws InterruptedException {
1475        jGrowl("Click OK Confirmation");
1476        String xpath = "//div[@data-parent='ConfirmCancelDialog']/button[contains(text(),'OK')]";
1477        waitForElementVisibleBy(By.xpath(xpath)).click();
1478    }
1479
1480    protected void waitAndClickConfirmBlanketApproveOk() throws InterruptedException {
1481        jGrowl("Click OK Confirmation");
1482        String xpath = "//div[@data-parent='ConfirmBlanketApproveDialog']/button[contains(text(),'OK')]";
1483        waitForElementVisibleBy(By.xpath(xpath)).click();
1484    }
1485
1486    protected void waitAndClickConfirmDeleteYes() throws InterruptedException {
1487        jGrowl("Click Yes Confirmation");
1488        String xpath = "//section[@id='DialogGroup-DeleteFileUploadLine']//button[contains(text(),'Yes')]";
1489        waitForElementVisibleBy(By.xpath(xpath)).click();
1490    }
1491
1492    protected void waitAndClickConfirmSaveOnClose() throws InterruptedException {
1493        jGrowl("Click OK Confirmation");
1494        waitForElementVisibleBy(By.xpath("//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'Yes')]"));
1495        waitAndClickByXpath("//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'Yes')]");
1496    }
1497
1498    protected void waitAndClickCancelSaveOnClose() throws InterruptedException {
1499        jGrowl("Click OK Confirmation");
1500        waitForElementVisibleBy(By.xpath(
1501                "//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'No')]"));
1502        waitAndClickByXpath("//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'No')]");
1503    }
1504
1505
1506    protected void waitAndClickConfirmSubmitOk() throws InterruptedException {
1507        jGrowl("Click OK Confirmation");
1508        String xpath = "//div[@data-parent='ConfirmSubmitDialog']/button[contains(text(),'OK')]";
1509        waitForElementVisibleBy(By.xpath(xpath)).click();
1510    }
1511
1512    protected void waitAndClickDropDown(String dropDownText) throws InterruptedException {
1513        jGrowl("Click the " + dropDownText + " drop down.");
1514        WebElement dropdownMenu = waitAndGetElementByAttributeValue("class", "dropdown-toggle");
1515        Thread.sleep(1000);
1516        dropdownMenu.click();
1517        waitAndClickByLinkText(dropDownText, "dropdown click " + dropDownText + " problem");
1518    }
1519
1520    protected void waitAndClickReturnValue() throws InterruptedException {
1521        waitAndClickByLinkText(RETURN_VALUE_LINK_TEXT, "Unable to click return value " + this.getClass().toString());
1522    }
1523
1524    protected void waitAndClickReturnValue(String message) throws InterruptedException {
1525        waitAndClickByLinkText(RETURN_VALUE_LINK_TEXT, message);
1526    }
1527
1528    protected void waitAndClickSearch3() throws InterruptedException {
1529        jGrowl("Click Search");
1530        waitAndClickByXpath(SEARCH_XPATH_3);
1531    }
1532
1533    protected String waitAndGetAttribute(By by, String attribute) throws InterruptedException {
1534        jiraAwareWaitFor(by, attribute);
1535
1536        return findElement(by).getAttribute(attribute);
1537    }
1538
1539    /**
1540     * Get value of any attribute by using element name
1541     *
1542     * @param name name of an element
1543     * @param attribute the name of an attribute whose value is to be retrieved
1544     */
1545    protected String waitAndGetAttributeByName(String name, String attribute) throws InterruptedException {
1546        return waitAndGetAttribute(By.name(name), attribute);
1547    }
1548
1549    /**
1550     * Get value of any attribute by using element xpath
1551     *
1552     * @param locator locating mechanism of an element
1553     * @param attribute the name of an attribute whose value is to be retrieved
1554     */
1555    protected String waitAndGetAttributeByXpath(String locator, String attribute) throws InterruptedException {
1556        return waitAndGetAttribute(By.xpath(locator), attribute);
1557    }
1558
1559    protected WebElement waitAndGetElementByAttributeValue(String attribute, String attributeValue) throws InterruptedException {
1560        return WebDriverUtils.waitAndGetElementByAttributeValue(driver, attribute, attributeValue, waitSeconds);
1561    }
1562
1563    protected List<WebElement> waitAndGetElementsByAttributeValue(String attribute, String attributeValue) throws InterruptedException {
1564        // jenkins implies that implicitlyWait is worse than sleep loop for finding elements by 100+ test failures on the old sampleapp
1565        //        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1566        //        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1567
1568        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1569
1570        boolean failed = false;
1571
1572        for (int second = 0;; second++) {
1573            Thread.sleep(1000);
1574            if (second >= waitSeconds)
1575                failed = true;
1576            try {
1577                if (failed || (getElementsByAttributeValue(attribute, attributeValue) != null)) {
1578                    break;
1579                }
1580            } catch (Exception e) {}
1581        }
1582
1583        List<WebElement> elements = getElementsByAttributeValue(attribute, attributeValue);
1584        driver.manage().timeouts().implicitlyWait(WebDriverUtils.configuredImplicityWait(), TimeUnit.SECONDS);
1585        return elements;
1586    }
1587
1588    protected String waitAndGetLabeledText(String label) throws InterruptedException {
1589        return waitForElementPresent(By.xpath("//th/label[contains(text(), '"
1590                + label
1591                + "')]/../following-sibling::*/div/span")).getText();
1592    }
1593
1594    protected String[] waitAndGetText(By by) throws InterruptedException {
1595        WebDriverUtils.waitFors(driver, WebDriverUtils.configuredImplicityWait(), by, this.getClass().toString());
1596        List<WebElement> found = findElements(by);
1597        String[] texts = new String[found.size()];
1598        int i = 0;
1599
1600        for (WebElement element: found) {
1601            texts[i++] = element.getText();
1602        }
1603
1604        if (texts.length == 0) {
1605            jiraAwareFail(by.toString());
1606        }
1607
1608        return texts;
1609    }
1610
1611
1612    protected void waitAndSelectBy(By by, String selectText) throws InterruptedException {
1613        waitFor(by, selectText + " not found.");
1614        select(by, selectText);
1615    }
1616
1617    protected void waitAndSelectByName(String name, String selectText) throws InterruptedException {
1618        waitAndSelectBy(By.name(name), selectText);
1619    }
1620
1621    protected WebElement waitAndType(By by, String text) throws InterruptedException {
1622        return waitAndType(by, text, this.getClass().toString());
1623    }
1624
1625    protected WebElement waitAndType(String selector, String text) throws InterruptedException {
1626        return waitAndType(By.cssSelector(selector), text);
1627    }
1628
1629    protected WebElement waitAndTypeById(String id, String text) throws InterruptedException {
1630        return waitAndType(By.id(id), text);
1631    }
1632
1633    protected WebElement waitAndTypeByXpath(String locator, String text) throws InterruptedException {
1634        return waitAndType(By.xpath(locator), text);
1635    }
1636
1637    protected WebElement waitAndTypeByXpath(String locator, String text, String message) throws InterruptedException {
1638        return waitAndType(By.xpath(locator), text, message);
1639    }
1640
1641    protected WebElement waitAndTypeByName(String name, String text) throws InterruptedException {
1642        return waitAndType(By.name(name), text);
1643    }
1644
1645    protected boolean waitAreAnyVisible(By[] bys) throws InterruptedException {
1646        if (bys == null || bys.length == 0 ) {
1647            return false;
1648        }
1649
1650        for (int second = 0; second < waitSeconds; second++) {
1651
1652            if (isVisible(bys)) {
1653                return true;
1654            }
1655
1656            Thread.sleep(1000);
1657        }
1658
1659        return false;
1660    }
1661
1662    /**
1663     * {@deprecated} use any of the various wait methods over this, waitForElementPresent for example.
1664     * @throws InterruptedException
1665     */
1666    protected void waitForPageToLoad() throws InterruptedException {
1667        Thread.sleep(5000);
1668        checkForIncidentReport();
1669    }
1670
1671    protected WebElement waitFor(By by) throws InterruptedException {
1672        return jiraAwareWaitFor(by, this.getClass().toString());
1673    }
1674
1675    /**
1676     * Should be called from jiraAwareWaitFor to get KULRICE error output in CI.
1677     *
1678     * Inner most waitFor, let it throw the failure so the timeout message reflects the waitSeconds time, not the 1
1679     * second it is set to before returning.
1680     * @param by
1681     * @param message
1682     * @throws InterruptedException
1683     */
1684    protected void waitFor(By by, String message) throws InterruptedException {
1685        WebDriverUtils.waitFor(this.driver, this.waitSeconds, by, message);
1686    }
1687
1688    /**
1689     * Uses Selenium's findElements method which does not throw a test exception if not found.
1690     * @param elementLocator
1691     * @param message
1692     * @throws InterruptedException
1693     */
1694    protected WebElement waitForElementVisible(String elementLocator, String message) throws InterruptedException {
1695        return waitForElementVisibleBy(By.cssSelector(elementLocator), message);
1696    }
1697
1698    protected WebElement waitForElementVisibleBy(By by) throws InterruptedException {
1699        return waitForElementVisibleBy(by, by.toString() + " NOT visible for class " + this.getClass().getSimpleName());
1700    }
1701
1702    protected WebElement waitForElementVisibleBy(By by, String message) throws InterruptedException {
1703        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1704
1705        boolean failed = false;
1706
1707        for (int second = 0;; second++) {
1708            if (second >= waitSeconds)
1709                failed = true;
1710            try {
1711                if (failed || driver.findElement(by).isDisplayed())
1712                    break;
1713            } catch (Exception e) {}
1714            Thread.sleep(1000);
1715        }
1716
1717        checkForIncidentReport(by.toString()); // after timeout to be sure page is loaded
1718
1719        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1720
1721        if (failed) {
1722            jiraAwareFail("timeout of " + waitSeconds + " seconds waiting for " + by + " " + message + " " + driver
1723                    .getCurrentUrl());
1724            return null;
1725        }
1726        return driver.findElements(by).get(0);
1727    }
1728
1729    protected void waitForElementVisibleById(String id, String message) throws InterruptedException {
1730        waitForElementVisibleBy(By.id(id), message);
1731    }
1732
1733    protected WebElement waitForElementPresent(By by) throws InterruptedException {
1734        return jiraAwareWaitFor(by, this.getClass().toString());
1735    }
1736
1737    protected WebElement waitForElementPresent(By by, String message) throws InterruptedException {
1738        return jiraAwareWaitFor(by, message);
1739    }
1740
1741    protected WebElement waitForElementPresent(String locator) throws InterruptedException {
1742        return jiraAwareWaitFor(By.cssSelector(locator), this.getClass().toString());
1743    }
1744
1745    protected WebElement waitForElementPresentByClassName(String name) throws InterruptedException {
1746        return jiraAwareWaitFor(By.className(name), this.getClass().toString());
1747    }
1748
1749    protected WebElement waitForElementPresentByClassName(String name, String message) throws InterruptedException {
1750        return jiraAwareWaitFor(By.className(name), message);
1751    }
1752
1753    protected WebElement waitForElementPresentByClassName(String name, int seconds) throws InterruptedException {
1754        return jiraAwareWaitFor(By.className(name), seconds, this.getClass().toString());
1755    }
1756
1757    protected void waitForElementsPresentByClassName(String name, String message) throws InterruptedException {
1758        jiraAwareWaitFors(By.className(name), message);
1759    }
1760
1761    protected String waitForLabeledText(String label) throws InterruptedException {
1762        return waitForElementVisibleBy(By.xpath("//th/label[contains(text(), '"
1763                + label
1764                + "')]/../following-sibling::*/div/span")).getText();
1765    }
1766
1767    /**
1768     * {@see WebDriverUtils#waitFor}.
1769     *
1770     * @param by to find
1771     * @param message on failure
1772     */
1773    protected List<WebElement> waitAndGetElementsFor(By by, String message) throws InterruptedException {
1774        try {
1775            return WebDriverUtils.waitFors(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
1776        } catch (Throwable t) {
1777            jiraAwareFail(by, message, t);
1778        }
1779        return new ArrayList<WebElement>();
1780    }
1781
1782    protected WebElement waitForElementPresentById(String id) throws InterruptedException {
1783        return jiraAwareWaitFor(By.id(id), this.getClass().toString());
1784    }
1785
1786    protected void waitForElementPresentById(String id, String message) throws InterruptedException {
1787        jiraAwareWaitFor(By.id(id), message);
1788    }
1789
1790    protected void waitForElementPresentById(String id, String message, int seconds) throws InterruptedException {
1791        jiraAwareWaitFor(By.id(id), seconds, message);
1792    }
1793
1794    protected void waitForElementsPresentById(String id, String message) throws InterruptedException {
1795        jiraAwareWaitFors(By.id(id), message);
1796    }
1797
1798    protected WebElement waitForElementPresentByName(String name) throws InterruptedException {
1799        return waitForElementPresentByName(name, this.getClass().toString());
1800    }
1801
1802    protected WebElement waitForElementPresentByName(String name, String message) throws InterruptedException {
1803        return jiraAwareWaitFor(By.name(name), message);
1804    }
1805
1806    protected WebElement waitForElementPresentByXpath(String xpath) throws InterruptedException {
1807        return jiraAwareWaitFor(By.xpath(xpath), this.getClass().toString());
1808    }
1809
1810    protected WebElement waitForElementPresentByXpath(String xpath, String message) throws InterruptedException {
1811        return jiraAwareWaitFor(By.xpath(xpath), message);
1812    }
1813
1814    protected void waitForElementsPresentByXpath(String xpathLocator) throws InterruptedException {
1815        jiraAwareWaitFors(By.xpath(xpathLocator), this.getClass().toString());
1816    }
1817
1818    protected void waitForElementNotPresent(By by) throws InterruptedException {
1819        waitForElementNotPresent(by, WebDriverUtils.configuredImplicityWait());
1820    }
1821
1822    protected void waitForElementNotPresent(By by, int secondsToWait) throws InterruptedException {
1823        waitForElementNotPresent(by, this.getClass().getSimpleName(), secondsToWait);
1824    }
1825
1826    protected void waitForElementNotPresent(By by, String message) throws InterruptedException {
1827        waitForElementNotPresent(by, this.getClass().getSimpleName(), WebDriverUtils.configuredImplicityWait());
1828    }
1829
1830    protected void waitForElementNotPresent(By by, String message, int secondsToWait) throws InterruptedException {
1831        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1832        while (isElementPresent(by)) {
1833            if (secondsToWait == 0) {
1834                break;
1835            }
1836            secondsToWait -= 1;
1837            Thread.sleep(1000);
1838        }
1839        if (isElementPresent(by)) {
1840            jiraAwareFail(by + " is still present " + message);
1841        }
1842        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1843    }
1844
1845
1846    protected boolean waitForIsTextPresent(String text) throws InterruptedException {
1847        boolean present = false;
1848        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1849        int secondsToWait = WebDriverUtils.configuredImplicityWait();
1850        while (!isTextPresent(text) && secondsToWait > 0) {
1851            secondsToWait -= 1;
1852            Thread.sleep(1000);
1853        }
1854        if (isTextPresent(text)) {
1855            present = true;
1856        }
1857        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1858        return present;
1859    }
1860
1861    protected void waitForProgress(String altText) throws InterruptedException {
1862        waitForProgress(altText, waitSeconds);
1863    }
1864
1865    protected void waitForProgress(String altText, int timeout) throws InterruptedException {
1866        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1867        for (int second = 0;; second++) {
1868            Thread.sleep(1000); // sleep for a second first, give element time to exist
1869
1870            if (second >= timeout) {
1871                jiraAwareFail(TIMEOUT_MESSAGE + " still Loading after " + timeout + " seconds.");
1872            }
1873
1874            try {
1875                if (!isElementPresentByXpath("//img[@alt='" + altText + "']") || !isVisible(By.xpath("//img[@alt='" + altText + "']"))) {
1876                    break;
1877                }
1878            } catch (Exception e) {
1879                // assume timing with img going away and continue with test
1880                break;
1881            }
1882
1883        }
1884        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1885    }
1886
1887    protected void waitForProgressAddingLine() throws InterruptedException {
1888        waitForProgress("Adding Line...");
1889    }
1890
1891    protected void waitForProgressDeletingLine() throws InterruptedException {
1892        waitForProgress("Deleting Line...");
1893    }
1894
1895    protected void waitForProgressAddingLine(int secondsToWait) throws InterruptedException {
1896        waitForProgress("Adding Line...", secondsToWait);
1897    }
1898
1899    protected void waitForProgressLoading() throws InterruptedException {
1900        waitForProgress("Loading...", WebDriverUtils.configuredImplicityWait() * 4);
1901    }
1902
1903    protected void waitForProgressLoading(int secondsToWait) throws InterruptedException {
1904        waitForProgress("Loading...", secondsToWait);
1905    }
1906
1907    protected void waitForProgressSaving() throws InterruptedException {
1908        waitForProgress("Saving...", WebDriverUtils.configuredImplicityWait() * 4);
1909    }
1910
1911    protected void waitForProgressSaving(int secondsToWait) throws InterruptedException {
1912        waitForProgress("Saving...", secondsToWait);
1913    }
1914
1915    protected void waitForTextPresent(String text) throws InterruptedException {
1916        waitForTextPresent(text, WebDriverUtils.configuredImplicityWait());
1917    }
1918
1919    protected void waitForTextPresent(String text, String message) throws InterruptedException {
1920        waitForTextPresent(text, WebDriverUtils.configuredImplicityWait(), message);
1921    }
1922
1923    protected void waitForTextPresent(String text, int secondsToWait) throws InterruptedException {
1924        waitForTextPresent(text, secondsToWait, this.getClass().getSimpleName());
1925    }
1926
1927    protected void waitForTextPresent(String text, int secondsToWait, String message) throws InterruptedException {
1928        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1929        while (!isTextPresent(text) && secondsToWait > 0) {
1930            secondsToWait -= 1;
1931            Thread.sleep(1000);
1932        }
1933        if (!isTextPresent(text)) {
1934            jiraAwareFail(message + " " + text + " is not present for " + this.getClass().toString());
1935        }
1936        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1937    }
1938
1939    protected void waitForTextNotPresent(String text) throws InterruptedException {
1940        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1941        int secondsToWait = WebDriverUtils.configuredImplicityWait();
1942        while (isTextPresent(text) && secondsToWait > 0) {
1943            secondsToWait -= 1;
1944            Thread.sleep(1000);
1945        }
1946        if (isTextPresent(text)) {
1947            jiraAwareFail(text + " is still present for " + this.getClass().toString());
1948        }
1949        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1950    }
1951
1952    protected void waitIsVisible(By by) throws InterruptedException {
1953        waitIsVisible(by, this.getClass().getSimpleName());
1954    }
1955
1956    protected void waitIsVisible(By by, String message) throws InterruptedException {
1957        for (int second = 0;; second++) {
1958            if (second >= waitSeconds) {
1959                jiraAwareFail(TIMEOUT_MESSAGE + " " + by.toString() + " " + message);
1960            }
1961            if (isVisible(by)) {
1962                break;
1963            }
1964            Thread.sleep(1000);
1965        }
1966
1967        if (!isVisible(by)) {
1968            jiraAwareFail(by.toString() + " not visiable", message);
1969        }
1970    }
1971
1972    protected void waitIsVisible(String locator) throws InterruptedException {
1973        waitIsVisible(By.cssSelector(locator));
1974    }
1975
1976    protected void waitIsVisibleByXpath(String locator) throws InterruptedException {
1977        waitIsVisible(By.xpath(locator));
1978    }
1979
1980    protected void waitIsVisibleByXpath(String locator, String message) throws InterruptedException {
1981        waitIsVisible(By.xpath(locator), message);
1982    }
1983
1984    protected void waitNotVisible(By by) throws InterruptedException {
1985        waitNotVisible(by, this.getClass().getSimpleName());
1986    }
1987
1988    protected void waitNotVisible(By by, String message) throws InterruptedException {
1989        for (int second = 0;; second++) {
1990            if (second >= waitSeconds) {
1991                jiraAwareFail(TIMEOUT_MESSAGE + " " + message);
1992            }
1993            if (!isVisible(by)) {
1994                break;
1995            }
1996            Thread.sleep(1000);
1997        }
1998    }
1999
2000    protected void waitNotVisibleByXpath(String locator) throws InterruptedException {
2001        waitNotVisible(By.xpath(locator));
2002    }
2003
2004    protected void waitNotVisibleByXpath(String locator, String message) throws InterruptedException {
2005        waitNotVisible(By.xpath(locator), message);
2006    }
2007}