001/**
002 * Copyright 2005-2015 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    @Deprecated
501    protected void checkForIncidentReport(String locator, JiraAwareFailable failable, String message) {
502        AutomatedFunctionalTestUtils.checkForIncidentReport(driver.getPageSource(), locator, message, failable);
503    }
504
505    protected void clearText(By by) throws InterruptedException {
506        findElement(by).clear();
507    }
508
509    protected void clearText(String selector) throws InterruptedException {
510        clearText(By.cssSelector(selector));
511    }
512
513    protected void clearTextByName(String name) throws InterruptedException {
514        clearText(By.name(name));
515    }
516
517    protected void clearTextByXpath(String locator) throws InterruptedException {
518        clearText(By.xpath(locator));
519    }
520
521    protected void close() {
522        driver.close();
523    }
524
525    protected void closeAllOtherWindows(String handleToKeep) {
526        Set<String> set = driver.getWindowHandles();
527
528        set.remove(handleToKeep);
529
530        Iterator iter = set.iterator();
531        String handle = "";
532        while (iter.hasNext()) {
533            handle = (String)iter.next();
534            driver.switchTo().window(handle);
535            driver.close();
536        }
537
538        driver.switchTo().window(handleToKeep);
539    }
540
541
542    protected void colapseExpandByXpath(String clickLocator, String visibleLocator) throws InterruptedException {
543        waitAndClickByXpath(clickLocator);
544        waitNotVisibleByXpath(visibleLocator);
545        waitAndClickByXpath(clickLocator);
546        waitIsVisibleByXpath(visibleLocator);
547    }
548
549    /**
550     * If WebDriverUtils.chromeDriverCreateCheck() returns a ChromeDriverService, start it.
551     * {@link org.kuali.rice.testtools.selenium.WebDriverUtils#chromeDriverCreateCheck()}
552     * @throws Exception
553     */
554    @BeforeClass
555    public static void chromeDriverService() throws Exception {
556        chromeDriverService = WebDriverUtils.chromeDriverCreateCheck();
557        if (chromeDriverService != null) {
558            chromeDriverService.start();
559        }
560
561// one browser
562//        driver = WebDriverUtils.setUp("getClass().getSimpleName()", "testMethodName");
563
564    }
565
566    protected void closeAndQuitWebDriver() {
567        if (driver != null) {
568            if (WebDriverUtils.dontTearDownPropertyNotSet() && WebDriverUtils.dontTearDownOnFailure(isPassed())) {
569                try {
570                    acceptAlertIfPresent();
571                    driver.close();
572                } catch (NoSuchWindowException nswe) {
573                    System.out.println("NoSuchWindowException closing WebDriver " + nswe.getMessage());
574                } finally {
575                    if (driver != null) {
576                        driver.quit();
577                    }
578                }
579            }
580        } else {
581            System.out.println("WebDriver is null for " + this.getClass().toString() + " if using a remote hub did you include the port?");
582        }
583    }
584
585    protected void determineImplicitWait() {
586        waitSeconds = WebDriverUtils.configuredImplicityWait();
587    }
588
589    protected void determineJgrowlHeader() {
590        jGrowlHeader = getClass().getSimpleName() + "." + testMethodName;
591    }
592
593    protected String determinePage() {
594        String url = driver.getCurrentUrl();
595
596        String viewId = "";
597        if (url.contains("viewId=")) {
598            viewId = url.substring(url.indexOf("viewId=") + 7, url.length());
599            if (viewId.indexOf("&") > -1) {
600                viewId = viewId.substring(0, viewId.indexOf("&"));
601            } else {
602                viewId = viewId.substring(0, viewId.length());
603            }
604        }
605
606        String pageId = "";
607        if (url.contains("pageId=")) {
608            pageId = url.substring(url.indexOf("pageId=") + 7, url.length());
609            if (pageId.indexOf("&") > -1) {
610                pageId = "-" + pageId.substring(0, pageId.indexOf("&"));
611            } else {
612                pageId = "-" + pageId.substring(0, pageId.length());
613            }
614        }
615
616        return viewId + pageId;
617    }
618
619    protected void determineTestMethodName() {
620        if (testName != null && testName.getMethodName() != null) { // JUnit
621            setTestMethodName(testName.getMethodName());
622        }
623    }
624
625    public void setTestMethodName(String testMethodName) {
626        this.testMethodName = testMethodName;
627    }
628
629    protected void determineUser() {
630        String givenUser = WebDriverUtils.determineUser(this.toString());
631        if (givenUser != null) {
632            user = givenUser;
633        }
634    }
635
636    protected String getDescriptionBase() {
637        return this.getClass().toString().substring(this.getClass().toString().lastIndexOf(".") + 1,
638                this.getClass().toString().length()) +
639                "." + testMethodName + " description";
640    }
641
642    protected String getDescriptionUnique() {
643        if (uniqueString == null) {
644            uniqueString = AutomatedFunctionalTestUtils.createUniqueDtsPlusTwoRandomCharsNot9Digits();
645        }
646        return getDescriptionBase() + " " + uniqueString;
647    }
648
649    protected WebElement findButtonByText(String buttonText) {
650        return WebDriverUtils.findButtonByText(driver, buttonText);
651    }
652
653    protected List<WebElement> findVisibleElements(By by) {
654        List<WebElement> webElements = driver.findElements(by);
655        List<WebElement> visibleWebElements = new LinkedList<WebElement>();
656        for (WebElement webElement: webElements) {
657            if (webElement.isDisplayed()) {
658                visibleWebElements.add(webElement);
659            }
660        }
661
662        return visibleWebElements;
663    }
664
665    protected List<WebElement> findElements(By by) {
666        List<WebElement> found = driver.findElements(by);
667        return found;
668    }
669
670    protected List<WebElement> findElements(By by, WebElement element) {
671        if (element == null) {
672            checkForIncidentReport();
673            throw new AssertionError("element to findElements on for " + by.toString() + " is null in class " + this.getClass().toString());
674        }
675        List<WebElement> found = element.findElements(by);
676        return found;
677    }
678
679    protected void fireEvent(String name, String event) {
680        ((JavascriptExecutor) driver).executeScript("var elements=document.getElementsByName(\"" + name + "\");" +
681                "for (var i = 0; i < elements.length; i++){" +
682                "elements[i]." + event + "();}");
683    }
684
685    protected void fireEvent(String name, String value, String event) {
686        ((JavascriptExecutor) driver).executeScript("var elements=document.getElementsByName(\"" + name + "\");" +
687                "for (var i = 0; i < elements.length; i++){" +
688                "if(elements[i].value=='" + value + "')" +
689                "elements[i]." + event + "();}");
690    }
691
692    /**
693     * {@link org.openqa.selenium.interactions.Actions#moveToElement(org.openqa.selenium.WebElement)}
694     * @param name
695     */
696    public void fireMouseOverEventByName(String name) {
697        this.fireMouseOverEvent(By.name(name));
698    }
699
700    /**
701     * {@link org.openqa.selenium.interactions.Actions#moveToElement(org.openqa.selenium.WebElement)}
702     * @param id
703     */
704    public void fireMouseOverEventById(String id) {
705        this.fireMouseOverEvent(By.id(id));
706    }
707
708    /**
709     * {@link org.openqa.selenium.interactions.Actions#moveToElement(org.openqa.selenium.WebElement)}
710     * @param locator
711     */
712    public void fireMouseOverEventByXpath(String locator) {
713        this.fireMouseOverEvent(By.xpath(locator));
714    }
715
716    /**
717     * {@link org.openqa.selenium.interactions.Actions#moveToElement(org.openqa.selenium.WebElement)}
718     * @param by
719     */
720    public void fireMouseOverEvent(By by) {
721        Actions builder = new Actions(driver);
722        Actions hover = builder.moveToElement(findElement(by));
723        hover.perform();
724    }
725
726    /**
727     * {@link org.openqa.selenium.WebDriver#getWindowHandles()}
728     * @return
729     */
730    public String[] getAllWindowTitles() {
731        return (String[]) driver.getWindowHandles().toArray();
732    }
733
734    protected String getBaseUrlString() {
735        return WebDriverUtils.getBaseUrlString();
736    }
737
738    protected int getCssCount(String selector) {
739        return getCssCount(By.cssSelector(selector));
740    }
741
742    /**
743     * Uses Selenium's findElements method which does not throw a test exception if not found.
744     * @param by
745     * @return
746     */
747    protected int getCssCount(By by) {
748        return (findElements(by)).size();
749    }
750
751    protected String getDateTimeStampFormatted() {
752        return WebDriverUtils.getDateTimeStampFormatted();
753    }
754
755    protected String getDateToday() {
756        Date now = Calendar.getInstance().getTime();
757        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
758        return sdf.format(now);
759    }
760
761    protected String getDateTomorrow() {
762        Calendar now = Calendar.getInstance();
763        now.add(Calendar.DATE, 1);
764        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
765        return sdf.format(now.getTime());
766    }
767
768    /**
769     * {@inheritDoc}
770     *
771     * @return WebDriver
772     */
773    @Override
774    protected WebDriver getDriver() {
775        return driver;
776    }
777
778    public void setDriver(WebDriver driver) {
779        this.driver = driver;
780    }
781
782    protected WebElement getElementByAttribute(String attributeName){
783        return findElement(By.cssSelector("[" + attributeName + "]"));
784    }
785
786    protected WebElement getElementByDataAttribute(String dataAttributeName){
787        return findElement(By.cssSelector("[data-" + dataAttributeName + "]"));
788    }
789
790    protected WebElement getElementByDataAttributeValue(String dataAttributeName, String value){
791        return findElement(By.cssSelector("[data-" + dataAttributeName + "='" + value + "']"));
792    }
793
794    protected WebElement getElementByAttributeValue(String attributeName, String value){
795        return findElement(By.cssSelector("[" + attributeName + "='" + value +"']"));
796    }
797
798    protected List<WebElement> getElementsByAttributeValue(String attributeName, String value){
799        return findElements(By.cssSelector("[" + attributeName + "='" + value + "']"));
800    }
801
802    @Override
803    protected String getNavigationUrl() {
804        String classString = this.getClass().toString();
805        if (classString.contains("krad.demo")) {
806            return AutomatedFunctionalTestUtils.KRAD_PORTAL;
807        } else if (classString.contains("krad.labs")) {
808            return AutomatedFunctionalTestUtils.LABS;
809        } else {
810            return AutomatedFunctionalTestUtils.PORTAL;
811        }
812    }
813
814    /**
815     * Uses Selenium's findElements for getting the options (findElement for the select) method which does not throw a test exception if not found.
816     * @param by
817     * @return
818     * @throws InterruptedException
819     */
820    protected String[] getSelectOptions(By by) throws InterruptedException {
821        WebElement select1 = driver.findElement(by); // don't highlight
822        List<WebElement> options = select1.findElements(By.tagName("option"));
823        String[] optionValues = new String[options.size()];
824        int counter = 0;
825
826        for (WebElement option : options) {
827            optionValues[counter] = option.getAttribute("value");
828            counter++;
829        }
830
831        return optionValues;
832    }
833
834    protected String[] getSelectOptionsByName(String name) throws InterruptedException {
835        return getSelectOptions(By.name(name));
836    }
837
838    protected String[] getSelectOptionsByXpath(String locator) throws InterruptedException {
839        return getSelectOptions(By.xpath(locator));
840    }
841
842    /**
843     *
844     * @return sessionId
845     */
846    public String getSessionId() {
847        return sessionId;
848    }
849
850    protected String getText(By by) throws InterruptedException {
851        WebElement element = findElement(by);
852        return element.getText();
853    }
854
855    protected String getTextByClassName(String className) throws InterruptedException {
856        return getText(By.className(className));
857    }
858
859    protected String getTextById(String id) throws InterruptedException {
860        return getText(By.id(id));
861    }
862
863    protected String getTextByName(String name) throws InterruptedException {
864        return getText(By.name(name));
865    }
866
867    protected String getText(String locator) throws InterruptedException {
868        return getText(By.cssSelector(locator));
869    }
870
871    protected String getTextByXpath(String locator) throws InterruptedException {
872        return getText(By.xpath(locator));
873    }
874
875    protected String getTitle() {
876        return driver.getTitle();
877    }
878
879    /**
880     * "admin" by default.  Can be overridden using {@see WebDriverUtils#REMOTE_PUBLIC_USER_PROPERTY}
881     * @return string
882     */
883    public String getUserName() {
884        return user;
885    }
886
887    /**
888     * Returns the label text of a label-for element
889     * <p>
890     * For usage with elements like this: <label for="some-element-id">The text of the Label</label>
891     * </p>
892     *
893     * @param forElementId the id of the element for which to find the label text
894     * @return label text
895     */
896    protected String getForLabelText(String forElementId) {
897        return findElement(By.cssSelector("label[for=" + forElementId + "]")).getText();
898    }
899
900    protected void gotoIframeById(final String iframeId) {
901        if (driver.findElements(By.id(iframeId)).size() > 0) { // find elements so an exception isn't thrown if not found
902            WebElement contentFrame = driver.findElement(By.id(iframeId)); // don't highlight
903            driver.switchTo().frame(contentFrame);
904        } else {
905            System.out.println("Unable to find " + iframeId);
906        }
907    }
908    protected WebElement gotoIframeByXpath(final String iframeXpath) {
909        if (driver.findElements(By.xpath(iframeXpath)).size() > 0) {  // find elements so an exception isn't thrown if not found
910            WebElement contentFrame = driver.findElement(By.xpath(iframeXpath)); // don't highlight
911            driver.switchTo().frame(contentFrame);
912            return contentFrame;
913        } else {
914            System.out.println("Unable to find " + iframeXpath);
915        }
916        return null;
917    }
918
919    protected void gotoLightBox() throws InterruptedException {
920        waitForElementVisibleBy(By.cssSelector(".uif-lookupDialog-iframe"));
921        driver.switchTo().frame(driver.findElement(By.cssSelector(".uif-lookupDialog-iframe")));
922    }
923
924    protected WebElement gotoLightBoxIframe() {
925        selectTopFrame();
926        return gotoIframeByXpath("//iframe[@class='uif-iFrame uif-lookupDialog-iframe']");
927    }
928
929    protected int howManyAreVisible(By by) throws InterruptedException {
930        int count = 0;
931        if (by == null) {
932
933            return count;
934        }
935
936        List<WebElement> webElementsFound = driver.findElements(by);
937        for (WebElement webElement: webElementsFound) {
938            if (webElement.isDisplayed()) {
939                count++;
940            }
941        }
942
943        return count;
944    }
945
946    protected boolean isNextLinkEnabled() {
947        return findElements(By.xpath("//a[@id='uLookupResults_layout_next' and @class='next paginate_button paginate_button_disabled']")).size() != 1;
948    }
949
950    protected boolean isChecked(By by) {
951        return findElement(by).isSelected();
952    }
953
954    protected boolean isCheckedById(String id) {
955        return isChecked(By.id(id));
956    }
957
958    protected boolean isCheckedByName(String name) {
959        return isChecked(By.name(name));
960    }
961
962    protected boolean isCheckedByXpath(String locator) {
963        return isChecked(By.xpath(locator));
964    }
965
966    protected boolean isEnabled(By by) {
967        return findElement(by).isEnabled();
968    }
969
970    protected boolean isEnabledById(String id) {
971        return isEnabled(By.id(id));
972    }
973
974    protected boolean isEnabledByName(String name) {
975        return isEnabled(By.name(name));
976    }
977
978    protected boolean isEnabledByXpath(String locator) {
979        return isEnabled(By.xpath(locator));
980    }
981
982    protected boolean isVisible(By[] bys) {
983        if (bys == null || bys.length == 0 ) {
984            return false;
985        }
986
987        for (int i = 0, s = bys.length; i < s; i++) {
988
989            try {
990
991                if (isVisible(bys[i])) {
992                    return true;
993                }
994
995            } catch (NoSuchElementException nsee) {
996                // don't fail
997            }
998
999        }
1000
1001        return false;
1002    }
1003
1004    /**
1005     * Uses Selenium's findElements method which does not throw a test exception if not found.
1006     * @param by
1007     * @return
1008     */
1009    protected boolean isElementPresent(By by) {
1010        return (driver.findElements(by)).size() > 0;
1011    }
1012
1013    /**
1014     * Uses Selenium's findElements method which does not throw a test exception if not found.
1015     * @param locator
1016     * @return
1017     */
1018    protected boolean isElementPresent(String locator) {
1019        return (driver.findElements(By.cssSelector(locator))).size() > 0;
1020    }
1021
1022    protected boolean isElementPresentById(String id) {
1023        return isElementPresent(By.id(id));
1024    }
1025
1026    protected boolean isElementPresentByName(String name) {
1027        return isElementPresent(By.name(name));
1028    }
1029
1030    protected boolean isElementPresentByXpath(String locator) {
1031        return isElementPresent(By.xpath(locator));
1032    }
1033
1034    protected boolean isElementPresentByLinkText(String locator) {
1035        return isElementPresent(By.linkText(locator));
1036    }
1037
1038    protected boolean isElementPresentByDataAttributeValue(String dataAttributeName, String dataAttributeValue) {
1039        return isElementPresent(By.cssSelector("[data-" + dataAttributeName + "='" + dataAttributeValue + "']"));
1040    }
1041
1042    protected boolean isNotVisible(By by) {
1043        return !(isVisible(by));
1044    }
1045
1046    protected Boolean isTextPresent(String text) {
1047        return WebDriverUtils.isTextPresent(driver, driver.getPageSource(), text);
1048    }
1049
1050    protected Boolean isTextPresent(String[] texts) {
1051        String pageSource = driver.getPageSource();
1052        for (String text: texts) {
1053            if (!WebDriverUtils.isTextPresent(driver, pageSource, text)) {
1054                return false;
1055            }
1056        }
1057        return true;
1058    }
1059
1060    protected void javascriptErrorsReport() {List javascriptErrors = WebDriverUtils.javascriptErrors(getDriver());
1061        if (javascriptErrors != null && javascriptErrors.size() > 0) {
1062            jGrowl("JAVASCRIPT ERRORS DETECTED - " + WebDriverUtils.javascriptErrorsToString(javascriptErrors));
1063        }
1064    }
1065
1066    protected void jGrowl(String message) {
1067        WebDriverUtils.jGrowl(driver, jGrowlHeader, false, message);
1068        if (webDriverScreenshotHelper.screenshotSteps()) {
1069            screenshot();
1070        }
1071    }
1072
1073    /**
1074     * Sticky is used on fail, making a call to jGrowl(String) from this method will result
1075     * in an infinite loop if JGROWL_ERROR_FAILURE is true so please don't.
1076     */
1077    protected void jGrowlSticky(String message) {
1078        WebDriverUtils.jGrowl(driver, jGrowlHeader, true, message);
1079        if (webDriverScreenshotHelper.screenshotSteps()) {
1080            screenshot();
1081        }
1082    }
1083
1084    /**
1085     * <p>
1086     * Logs in using the KRAD Login Page, if the JVM arg remote.autologin is set, auto login as admin will not be done.
1087     * </p>
1088     *
1089     * @param driver to login with
1090     * @param userName to login with
1091     * @param failable to fail on if there is a login problem
1092     * @throws InterruptedException
1093     */
1094    public void login(WebDriver driver, String userName, JiraAwareFailable failable) throws InterruptedException {
1095        if ("true".equalsIgnoreCase(System.getProperty(WebDriverUtils.REMOTE_AUTOLOGIN_PROPERTY, "true"))) {
1096            driver.findElement(By.name("login_user")).clear();
1097            driver.findElement(By.name("login_user")).sendKeys(userName);
1098            driver.findElement(By.id("Rice-LoginButton")).click();
1099            Thread.sleep(1000);
1100            String contents = driver.getPageSource();
1101            AutomatedFunctionalTestUtils.failOnInvalidUserName(userName, contents, failable);
1102            AutomatedFunctionalTestUtils.checkForIncidentReport(driver.getPageSource(), "Login", "Login failure",
1103                    failable);
1104        }
1105    }
1106
1107    protected void logout() throws InterruptedException {
1108        // KRAD Logout requires server configuration, currently env14 is not configured so throws Incident Report.
1109        //        } else {
1110        //            String logoutUrl = getBaseUrlString() + "/kr-krad/login?methodToCall=logout";
1111        //            jGrowl("Logging out with " + logoutUrl);
1112        //            open(logoutUrl);
1113    }
1114
1115    protected String multiValueResultCount() throws InterruptedException {
1116        WebElement dataTableInfo = waitAndGetElementByAttributeValue("class", "dataTables_info");
1117        String resultsCount = dataTableInfo.getText();
1118        resultsCount = resultsCount.substring(resultsCount.indexOf(" of ") + 4, resultsCount.indexOf(" entries")).trim();
1119        return resultsCount;
1120    }
1121
1122    protected void open(String url) {
1123        driver.get(url);
1124    }
1125
1126    @Override
1127    protected void navigate() throws Exception {
1128        // No-op for convenience
1129    }
1130
1131    protected void screenshot() {
1132        try {
1133            webDriverScreenshotHelper.screenshot(driver, this.getClass().getSimpleName(), testName.getMethodName(),
1134                    determinePage());
1135        } catch (Throwable t) {
1136            System.out.println("Problem with screenshot " + t.getMessage());
1137        }
1138    }
1139
1140    protected void startSession(Method method) throws Exception {
1141        testMethodName = method.getName(); // TestNG
1142    }
1143
1144    /**
1145     * Uses Selenium's findElements method which does not throw a test exception if not found.
1146     * @param by
1147     * @param selectText
1148     * @throws InterruptedException
1149     */
1150    protected void select(By by, String selectText) throws InterruptedException {
1151        //        checkForIncidentReport(by.toString(), "trying to select text " + selectText); // I think a report will now be picked-up by the jiraAwareFail
1152        WebElement select1 = findElement(by);
1153        WebDriverUtils.highlightElement(driver, select1);
1154        String name = select1.getAttribute("name");
1155        jGrowl("Select " + selectText + " from " + name);
1156        List<WebElement> options = select1.findElements(By.tagName("option"));
1157
1158        for (WebElement option : options) {
1159            if (option.getText().equals(selectText)) {
1160                option.click();
1161                break; // continuing the loop after clicking on an option often causes cache problems other times it seems breaking here causes hangs?!
1162            }
1163        }
1164    }
1165
1166    protected void selectByXpath(String locator, String selectText) throws InterruptedException {
1167        select(By.xpath(locator), selectText);
1168    }
1169
1170    protected void selectByName(String name, String selectText) throws InterruptedException {
1171        select(By.name(name), selectText);
1172    }
1173
1174    protected void selectChildWindow() {
1175        selectWindow(driver.getWindowHandles().toArray()[1].toString());
1176    }
1177
1178    protected void selectParentWindow() {
1179        selectWindow(driver.getWindowHandles().toArray()[0].toString());
1180    }
1181
1182    protected void selectTopFrame() {
1183        driver.switchTo().defaultContent();
1184    }
1185
1186    protected void selectWindow(String locator) {
1187        driver.switchTo().window(locator);
1188    }
1189
1190    /**
1191     * If a window contains the given title switchTo it.
1192     * @param title
1193     */
1194    public void switchToWindow(String title) {
1195        Set<String> windows = driver.getWindowHandles();
1196
1197        for (String window : windows) {
1198            driver.switchTo().window(window);
1199            if (driver.getTitle().contains(title)) {
1200                return;
1201            }
1202        }
1203    }
1204
1205    /**
1206     * Tear down test as configured.  Do not allow exceptions to be thrown by tearDown, it kills the test run.
1207     * {@link WebDriverUtils#tearDown(boolean, String, String, String)}
1208     * {@link WebDriverUtils#REMOTE_PUBLIC_USERPOOL_PROPERTY}
1209     * {@link WebDriverUtils#dontTearDownPropertyNotSet()}
1210     * @throws Exception
1211     */
1212    @After
1213    public void tearDown() {
1214        try {
1215
1216            if (!isPassed()) {
1217                try { // if saucelabs has timed out getCurrentUrl throws an exception
1218                    System.out.println("Last AFT URL: " + driver.getCurrentUrl());
1219                } catch (Throwable t) {
1220                    System.out.println("Unable to determine LAST AFT URL due to " + t.getMessage());
1221                }
1222            }
1223
1224            try { // saucelabs
1225                if ((!isPassed() && webDriverScreenshotHelper.screenshotOnFailure()) || webDriverScreenshotHelper.screenshotSteps()) {
1226                    screenshot();
1227                }
1228            } catch (Throwable t2) {
1229                System.out.println("Unable to take failure screenshot " + t2.getMessage());
1230            }
1231
1232            try { // saucelabs
1233                if (isPassed() && WebDriverUtils.dontTearDownPropertyNotSet() && WebDriverUtils.dontTearDownOnFailure(isPassed())) {
1234                    logout();
1235                }
1236            } catch (Throwable t3) {
1237                System.out.println("Unable to logout " + t3.getMessage());
1238            }
1239
1240            WebDriverUtils.tearDown(isPassed(), sessionId, this.toString().trim(), user, getClass().getSimpleName(), testName.getMethodName());
1241        } catch (Throwable t) {
1242            System.out.println("Exception in tearDown " + t.getMessage());
1243            t.printStackTrace();
1244        }
1245
1246        // going to the login page and closing other windows so tests can be run in one browser
1247//        acceptAlertIfPresent();
1248//        closeAllOtherWindows(oneBrowserHandle);
1249//        driver.get(getBaseUrlString()
1250//                + "/kr-login/login?viewId=DummyLoginView&returnLocation=%2Fkr-krad%2Fkradsampleapp%3FviewId%3DKradSampleAppHome%26methodToCall%3Dstart");
1251//        acceptAlertIfPresent();
1252
1253        // comment out finally block for one browser
1254        finally {
1255            try {
1256                closeAndQuitWebDriver();
1257            } catch (Throwable t) {
1258                System.out.println(t.getMessage() + " occurred during tearDown, ignoring to avoid killing test run.");
1259                t.printStackTrace();
1260                System.out.println(t.getMessage() + " occurred during tearDown, ignoring to avoid killing test run.");
1261            }
1262        }
1263    }
1264
1265    /**
1266     * 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.
1267     * Setup the WebDriver properties, test, and login.  Named testSetUp so it runs after TestNG's startSession(Method)
1268     * {@link WebDriverUtils#determineUser(String)}
1269     * {@link WebDriverUtils#setUp(String, String, String, String)}
1270     */
1271    @Before
1272    public void testSetUp() {
1273        // 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.
1274        try { // Don't throw any exception from this methods, exceptions in Before annotations really mess up maven, surefire, or failsafe
1275            setUpSetUp();
1276
1277            driver = WebDriverUtils.setUp(getClass().getSimpleName(), testMethodName); // one browser comment this out
1278
1279            String testUrl = getTestUrl();
1280            // TODO Got into the situation where the first url doesn't expect server, but all others do.  Readdress once
1281            // the NavIT WDIT conversion has been completed.
1282            if (!testUrl.startsWith("http")) {
1283                testUrl = getBaseUrlString() + testUrl;
1284            }
1285            WebDriverUtils.openTestUrl(driver, testUrl);
1286
1287//            oneBrowserHandle = driver.getWindowHandle(); // one browser other windows will be closed
1288//            System.out.println("One Browser handle " + oneBrowserHandle);
1289//            closeAllOtherWindows(oneBrowserHandle); // close all others than one browser
1290
1291            this.sessionId = ((RemoteWebDriver) driver).getSessionId().toString();
1292            System.out.println(jGrowlHeader + " sessionId is " + sessionId);
1293
1294//            if (isVisible(By.name("login_user"))) { // one browser
1295                login(driver, getUserName(), this);
1296//            }
1297
1298            navigateInternal(); // SeleniumBaseTest.fail from navigateInternal results in the test not being recorded as a failure in CI.
1299
1300            javascriptErrorsReport();
1301
1302        } catch (Throwable t) {
1303            System.out.println("Throwable " + t.getMessage() + " in Before annotated method is very bad, ignoring and letting first method of test class to fail.");
1304            t.printStackTrace();
1305            System.out.println("Throwable " + t.getMessage()
1306                    + " in Before annotated method is very bad, ignoring and letting first method of test class to fail.");
1307        }
1308    }
1309
1310    public void setUpSetUp() {
1311        determineTestMethodName();
1312        determineImplicitWait();
1313        determineUser();
1314        determineJgrowlHeader();
1315    }
1316
1317    protected void uncheck(By by) throws InterruptedException {
1318        WebElement element = findElement(by);
1319        if (element.isSelected()) {
1320            element.click();
1321        }
1322    }
1323
1324    protected void uncheckByName(String name) throws InterruptedException {
1325        uncheck(By.name(name));
1326    }
1327
1328    protected void uncheckByXpath(String locator) throws InterruptedException {
1329        uncheck(By.xpath(locator));
1330    }
1331
1332    protected void waitAndClick(String locator) throws InterruptedException {
1333        waitAndClick(locator, this.getClass().toString());
1334    }
1335
1336    protected void waitAndClick(By by) throws InterruptedException {
1337        jiraAwareWaitAndClick(by, this.getClass().toString());
1338    }
1339
1340    protected void waitAndClick(By by, JiraAwareFailable failable) throws InterruptedException {
1341        jiraAwareWaitAndClick(by, this.getClass().toString(), failable);
1342    }
1343
1344    protected void waitAndClick(String locator, String message) throws InterruptedException {
1345        jiraAwareWaitAndClick(By.cssSelector(locator), message);
1346    }
1347
1348    protected void waitAndClickById(String id) throws InterruptedException {
1349        jiraAwareWaitAndClick(By.id(id), this.getClass().toString());
1350    }
1351
1352    protected void waitAndClickById(String id, String message) throws InterruptedException {
1353        jiraAwareWaitAndClick(By.id(id), message);
1354    }
1355
1356    protected void waitAndClickByLinkText(String text) throws InterruptedException {
1357        waitAndClickByLinkText(text, this.getClass().toString());
1358    }
1359
1360    protected void waitAndClickByLinkText(String text, String message) throws InterruptedException {
1361        waitAndClickByLinkText(text, message, this);
1362    }
1363
1364    protected void waitAndClickByLinkText(String text, JiraAwareFailable failable) throws InterruptedException {
1365        waitAndClickByLinkText(text, this.getClass().toString(), failable);
1366    }
1367
1368    protected void waitAndClickByLinkText(String text, String message, JiraAwareFailable failable) throws InterruptedException {
1369        jGrowl("Click " + text + " link.");
1370        jiraAwareWaitAndClick(By.linkText(text), message, failable);
1371    }
1372
1373    protected void waitAndClickLabeledLink(String label, String linkText) throws InterruptedException {
1374        jGrowl("Click link " + linkText + " labeled with " + label);
1375        waitAndClick(By.xpath(
1376                "//th/label[contains(text(), '" + label + "')]/../following-sibling::*/div/span/a[contains(text(), '"
1377                        + linkText + "')]"));
1378    }
1379
1380    protected void waitAndClickLabeledQuickFinder(String label) throws InterruptedException {
1381        jGrowl("Click link quickfinder labeled with " + label);
1382        waitAndClick(By.xpath("//th/label[contains(text(), '" + label
1383                + "')]/../following-sibling::*/div/div/div/button[@class='btn btn-default uif-action icon-search']"));
1384        screenshot();
1385    }
1386
1387    protected void waitAndTypeLabeledInput(String label, String text) throws InterruptedException {
1388        jGrowl("Type " + text + " in input labeled with " + label);
1389        waitAndTypeByXpath("//th/label[contains(text(), '" + label + "')]/../following-sibling::*//input", text);
1390        screenshot();
1391    }
1392
1393    protected void waitAndSelectLabeled(String label, String text) throws InterruptedException {
1394        jGrowl("Select " + text + " labeled with " + label);
1395        waitAndSelectBy(By.xpath("//th/label[contains(text(), '" + label + "')]/../following-sibling::*//select"), text);
1396        screenshot();
1397    }
1398
1399    protected void waitAndClickLightBoxClose() throws InterruptedException {
1400        jGrowl("Click lightbox close");
1401        waitAndClickByXpath("//button[contains(text(),'x')]");
1402    }
1403
1404    protected void waitAndClickLinkContainingText(String linkText) throws InterruptedException {
1405        waitAndClickLinkContainingText(linkText, this.getClass().toString());
1406    }
1407
1408    protected void waitAndClickLinkContainingText(String linkText, String message) throws InterruptedException {
1409        jGrowl("Click link containing " + linkText + " .");
1410        waitAndClickByXpath("//a[contains(text(), '" + linkText + "')]", message);
1411    }
1412
1413    protected void waitAndClickByName(String name) throws InterruptedException {
1414        jGrowl("Click By Name " + name);
1415        jiraAwareWaitAndClick(By.name(name), this.getClass().toString());
1416    }
1417
1418    protected void waitAndClickByValue(String value) throws InterruptedException {
1419        waitAndGetElementByAttributeValue("value", value).click();
1420    }
1421
1422    protected void waitAndClickByXpath(String xpath) throws InterruptedException {
1423        waitAndClick(By.xpath(xpath));
1424    }
1425
1426    protected void waitAndClickByXpath(String xpath, JiraAwareFailable failable) throws InterruptedException {
1427        waitAndClick(By.xpath(xpath), failable);
1428    }
1429
1430    protected void waitAndClickByName(String name, String message) throws InterruptedException {
1431        jiraAwareWaitAndClick(By.name(name), message);
1432    }
1433
1434    protected void waitAndClickByXpath(String xpath, String message) throws InterruptedException {
1435        jiraAwareWaitAndClick(By.xpath(xpath), message);
1436    }
1437
1438    protected void waitAndClickByXpath(String xpath, int waitSeconds, String message) throws InterruptedException {
1439        jiraAwareWaitAndClick(By.xpath(xpath), waitSeconds, message, this);
1440    }
1441
1442    protected void waitAndClickButtonByText(String buttonText) throws InterruptedException {
1443        waitAndClickButtonByText(buttonText, this.getClass().toString());
1444    }
1445
1446    protected void waitAndClickButtonByText(String buttonText, int waitSeconds) throws InterruptedException {
1447        waitAndClickButtonByText(buttonText, waitSeconds, this.getClass().toString());
1448    }
1449
1450    protected void waitAndClickButtonByText(String buttonText, String message) throws InterruptedException {
1451        jGrowl("Click " + buttonText + " button.");
1452        waitAndClickByXpath("//button[contains(text(), '" + buttonText + "')]", message);
1453    }
1454
1455    protected void waitAndClickButtonByText(String buttonText, int waitSeconds, String message) throws InterruptedException {
1456        jGrowl("Click " + buttonText + " button.");
1457        waitAndClickByXpath("//button[contains(text(), '" + buttonText + "')]", waitSeconds, message);
1458    }
1459
1460    protected void waitAndClickButtonByExactText(String buttonText) throws InterruptedException {
1461        waitAndClickButtonByExactText(buttonText, this.getClass().toString());
1462    }
1463
1464    protected void waitAndClickButtonByExactText(String buttonText, String message) throws InterruptedException {
1465        jGrowl("Click " + buttonText + " button.");
1466        waitAndClickByXpath("//button[normalize-space(.)='" + buttonText + "']", message);
1467    }
1468
1469    protected void waitAndClickAllByName(String name) throws InterruptedException{
1470        List<WebElement> elements = driver.findElements(By.name(name));
1471        for(WebElement ele : elements){
1472            ele.click();
1473        }
1474    }
1475    protected void waitAndClickConfirmCancelOk() throws InterruptedException {
1476        jGrowl("Click OK Confirmation");
1477        String xpath = "//div[@data-parent='ConfirmCancelDialog']/button[contains(text(),'OK')]";
1478        waitForElementVisibleBy(By.xpath(xpath)).click();
1479    }
1480
1481    protected void waitAndClickConfirmBlanketApproveOk() throws InterruptedException {
1482        jGrowl("Click OK Confirmation");
1483        String xpath = "//div[@data-parent='ConfirmBlanketApproveDialog']/button[contains(text(),'OK')]";
1484        waitForElementVisibleBy(By.xpath(xpath)).click();
1485    }
1486
1487    protected void waitAndClickConfirmDeleteYes() throws InterruptedException {
1488        jGrowl("Click Yes Confirmation");
1489        String xpath = "//section[@id='DialogGroup-DeleteFileUploadLine']//button[contains(text(),'Yes')]";
1490        waitForElementVisibleBy(By.xpath(xpath)).click();
1491    }
1492
1493    protected void waitAndClickConfirmSaveOnClose() throws InterruptedException {
1494        jGrowl("Click OK Confirmation");
1495        waitForElementVisibleBy(By.xpath("//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'Yes')]"));
1496        waitAndClickByXpath("//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'Yes')]");
1497    }
1498
1499    protected void waitAndClickCancelSaveOnClose() throws InterruptedException {
1500        jGrowl("Click OK Confirmation");
1501        waitForElementVisibleBy(By.xpath(
1502                "//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'No')]"));
1503        waitAndClickByXpath("//div[@data-parent='ConfirmSaveOnCloseDialog']/button[contains(text(),'No')]");
1504    }
1505
1506
1507    protected void waitAndClickConfirmSubmitOk() throws InterruptedException {
1508        jGrowl("Click OK Confirmation");
1509        String xpath = "//div[@data-parent='ConfirmSubmitDialog']/button[contains(text(),'OK')]";
1510        waitForElementVisibleBy(By.xpath(xpath)).click();
1511    }
1512
1513    protected void waitAndClickDropDown(String dropDownText) throws InterruptedException {
1514        jGrowl("Click the " + dropDownText + " drop down.");
1515        WebElement dropdownMenu = waitAndGetElementByAttributeValue("class", "dropdown-toggle");
1516        Thread.sleep(1000);
1517        dropdownMenu.click();
1518        waitAndClickByLinkText(dropDownText, "dropdown click " + dropDownText + " problem");
1519    }
1520
1521    protected void waitAndClickReturnValue() throws InterruptedException {
1522        waitAndClickByLinkText(RETURN_VALUE_LINK_TEXT, "Unable to click return value " + this.getClass().toString());
1523    }
1524
1525    protected void waitAndClickReturnValue(String message) throws InterruptedException {
1526        waitAndClickByLinkText(RETURN_VALUE_LINK_TEXT, message);
1527    }
1528
1529    protected void waitAndClickSearch3() throws InterruptedException {
1530        jGrowl("Click Search");
1531        waitAndClickByXpath(SEARCH_XPATH_3);
1532    }
1533
1534    protected String waitAndGetAttribute(By by, String attribute) throws InterruptedException {
1535        jiraAwareWaitFor(by, attribute);
1536
1537        return findElement(by).getAttribute(attribute);
1538    }
1539
1540    /**
1541     * Get value of any attribute by using element name
1542     *
1543     * @param name name of an element
1544     * @param attribute the name of an attribute whose value is to be retrieved
1545     */
1546    protected String waitAndGetAttributeByName(String name, String attribute) throws InterruptedException {
1547        return waitAndGetAttribute(By.name(name), attribute);
1548    }
1549
1550    /**
1551     * Get value of any attribute by using element xpath
1552     *
1553     * @param locator locating mechanism of an element
1554     * @param attribute the name of an attribute whose value is to be retrieved
1555     */
1556    protected String waitAndGetAttributeByXpath(String locator, String attribute) throws InterruptedException {
1557        return waitAndGetAttribute(By.xpath(locator), attribute);
1558    }
1559
1560    protected WebElement waitAndGetElementByAttributeValue(String attribute, String attributeValue) throws InterruptedException {
1561        return WebDriverUtils.waitAndGetElementByAttributeValue(driver, attribute, attributeValue, waitSeconds);
1562    }
1563
1564    protected List<WebElement> waitAndGetElementsByAttributeValue(String attribute, String attributeValue) throws InterruptedException {
1565        // jenkins implies that implicitlyWait is worse than sleep loop for finding elements by 100+ test failures on the old sampleapp
1566        //        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1567        //        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1568
1569        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1570
1571        boolean failed = false;
1572
1573        for (int second = 0;; second++) {
1574            Thread.sleep(1000);
1575            if (second >= waitSeconds)
1576                failed = true;
1577            try {
1578                if (failed || (getElementsByAttributeValue(attribute, attributeValue) != null)) {
1579                    break;
1580                }
1581            } catch (Exception e) {}
1582        }
1583
1584        List<WebElement> elements = getElementsByAttributeValue(attribute, attributeValue);
1585        driver.manage().timeouts().implicitlyWait(WebDriverUtils.configuredImplicityWait(), TimeUnit.SECONDS);
1586        return elements;
1587    }
1588
1589    protected String waitAndGetLabeledText(String label) throws InterruptedException {
1590        return waitForElementPresent(By.xpath("//th/label[contains(text(), '"
1591                + label
1592                + "')]/../following-sibling::*/div/span")).getText();
1593    }
1594
1595    protected String[] waitAndGetText(By by) throws InterruptedException {
1596        WebDriverUtils.waitFors(driver, WebDriverUtils.configuredImplicityWait(), by, this.getClass().toString());
1597        List<WebElement> found = findElements(by);
1598        String[] texts = new String[found.size()];
1599        int i = 0;
1600
1601        for (WebElement element: found) {
1602            texts[i++] = element.getText();
1603        }
1604
1605        if (texts.length == 0) {
1606            jiraAwareFail(by.toString());
1607        }
1608
1609        return texts;
1610    }
1611
1612
1613    protected void waitAndSelectBy(By by, String selectText) throws InterruptedException {
1614        waitFor(by, selectText + " not found.");
1615        select(by, selectText);
1616    }
1617
1618    protected void waitAndSelectByName(String name, String selectText) throws InterruptedException {
1619        waitAndSelectBy(By.name(name), selectText);
1620    }
1621
1622    protected WebElement waitAndType(By by, String text) throws InterruptedException {
1623        return waitAndType(by, text, this.getClass().toString());
1624    }
1625
1626    protected WebElement waitAndType(String selector, String text) throws InterruptedException {
1627        return waitAndType(By.cssSelector(selector), text);
1628    }
1629
1630    protected WebElement waitAndTypeById(String id, String text) throws InterruptedException {
1631        return waitAndType(By.id(id), text);
1632    }
1633
1634    protected WebElement waitAndTypeByXpath(String locator, String text) throws InterruptedException {
1635        return waitAndType(By.xpath(locator), text);
1636    }
1637
1638    protected WebElement waitAndTypeByXpath(String locator, String text, String message) throws InterruptedException {
1639        return waitAndType(By.xpath(locator), text, message);
1640    }
1641
1642    protected WebElement waitAndTypeByName(String name, String text) throws InterruptedException {
1643        return waitAndType(By.name(name), text);
1644    }
1645
1646    protected boolean waitAreAnyVisible(By[] bys) throws InterruptedException {
1647        if (bys == null || bys.length == 0 ) {
1648            return false;
1649        }
1650
1651        for (int second = 0; second < waitSeconds; second++) {
1652
1653            if (isVisible(bys)) {
1654                return true;
1655            }
1656
1657            Thread.sleep(1000);
1658        }
1659
1660        return false;
1661    }
1662
1663    /**
1664     * {@deprecated} use any of the various wait methods over this, waitForElementPresent for example.
1665     * @throws InterruptedException
1666     */
1667    protected void waitForPageToLoad() throws InterruptedException {
1668        Thread.sleep(5000);
1669        checkForIncidentReport();
1670    }
1671
1672    protected WebElement waitFor(By by) throws InterruptedException {
1673        return jiraAwareWaitFor(by, this.getClass().toString());
1674    }
1675
1676    /**
1677     * Should be called from jiraAwareWaitFor to get KULRICE error output in CI.
1678     *
1679     * Inner most waitFor, let it throw the failure so the timeout message reflects the waitSeconds time, not the 1
1680     * second it is set to before returning.
1681     * @param by
1682     * @param message
1683     * @throws InterruptedException
1684     */
1685    protected void waitFor(By by, String message) throws InterruptedException {
1686        WebDriverUtils.waitFor(this.driver, this.waitSeconds, by, message);
1687    }
1688
1689    /**
1690     * Uses Selenium's findElements method which does not throw a test exception if not found.
1691     * @param elementLocator
1692     * @param message
1693     * @throws InterruptedException
1694     */
1695    protected WebElement waitForElementVisible(String elementLocator, String message) throws InterruptedException {
1696        return waitForElementVisibleBy(By.cssSelector(elementLocator), message);
1697    }
1698
1699    protected WebElement waitForElementVisibleBy(By by) throws InterruptedException {
1700        return waitForElementVisibleBy(by, by.toString() + " NOT visible for class " + this.getClass().getSimpleName());
1701    }
1702
1703    protected WebElement waitForElementVisibleBy(By by, String message) throws InterruptedException {
1704        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1705
1706        boolean failed = false;
1707
1708        for (int second = 0;; second++) {
1709            if (second >= waitSeconds)
1710                failed = true;
1711            try {
1712                if (failed || driver.findElement(by).isDisplayed())
1713                    break;
1714            } catch (Exception e) {}
1715            Thread.sleep(1000);
1716        }
1717
1718        checkForIncidentReport(by.toString()); // after timeout to be sure page is loaded
1719
1720        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1721
1722        if (failed) {
1723            jiraAwareFail("timeout of " + waitSeconds + " seconds waiting for " + by + " " + message + " " + driver
1724                    .getCurrentUrl());
1725            return null;
1726        }
1727        return driver.findElements(by).get(0);
1728    }
1729
1730    protected void waitForElementVisibleById(String id, String message) throws InterruptedException {
1731        waitForElementVisibleBy(By.id(id), message);
1732    }
1733
1734    protected WebElement waitForElementPresent(By by) throws InterruptedException {
1735        return jiraAwareWaitFor(by, this.getClass().toString());
1736    }
1737
1738    protected WebElement waitForElementPresent(By by, String message) throws InterruptedException {
1739        return jiraAwareWaitFor(by, message);
1740    }
1741
1742    protected WebElement waitForElementPresent(String locator) throws InterruptedException {
1743        return jiraAwareWaitFor(By.cssSelector(locator), this.getClass().toString());
1744    }
1745
1746    protected WebElement waitForElementPresentByClassName(String name) throws InterruptedException {
1747        return jiraAwareWaitFor(By.className(name), this.getClass().toString());
1748    }
1749
1750    protected WebElement waitForElementPresentByClassName(String name, String message) throws InterruptedException {
1751        return jiraAwareWaitFor(By.className(name), message);
1752    }
1753
1754    protected WebElement waitForElementPresentByClassName(String name, int seconds) throws InterruptedException {
1755        return jiraAwareWaitFor(By.className(name), seconds, this.getClass().toString());
1756    }
1757
1758    protected void waitForElementsPresentByClassName(String name, String message) throws InterruptedException {
1759        jiraAwareWaitFors(By.className(name), message);
1760    }
1761
1762    protected String waitForLabeledText(String label) throws InterruptedException {
1763        return waitForElementVisibleBy(By.xpath("//th/label[contains(text(), '"
1764                + label
1765                + "')]/../following-sibling::*/div/span")).getText();
1766    }
1767
1768    /**
1769     * {@see WebDriverUtils#waitFor}.
1770     *
1771     * @param by to find
1772     * @param message on failure
1773     */
1774    protected List<WebElement> waitAndGetElementsFor(By by, String message) throws InterruptedException {
1775        try {
1776            return WebDriverUtils.waitFors(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
1777        } catch (Throwable t) {
1778            jiraAwareFail(by, message, t);
1779        }
1780        return new ArrayList<WebElement>();
1781    }
1782
1783    protected WebElement waitForElementPresentById(String id) throws InterruptedException {
1784        return jiraAwareWaitFor(By.id(id), this.getClass().toString());
1785    }
1786
1787    protected void waitForElementPresentById(String id, String message) throws InterruptedException {
1788        jiraAwareWaitFor(By.id(id), message);
1789    }
1790
1791    protected void waitForElementPresentById(String id, String message, int seconds) throws InterruptedException {
1792        jiraAwareWaitFor(By.id(id), seconds, message);
1793    }
1794
1795    protected void waitForElementsPresentById(String id, String message) throws InterruptedException {
1796        jiraAwareWaitFors(By.id(id), message);
1797    }
1798
1799    protected WebElement waitForElementPresentByName(String name) throws InterruptedException {
1800        return waitForElementPresentByName(name, this.getClass().toString());
1801    }
1802
1803    protected WebElement waitForElementPresentByName(String name, String message) throws InterruptedException {
1804        return jiraAwareWaitFor(By.name(name), message);
1805    }
1806
1807    protected WebElement waitForElementPresentByXpath(String xpath) throws InterruptedException {
1808        return jiraAwareWaitFor(By.xpath(xpath), this.getClass().toString());
1809    }
1810
1811    protected WebElement waitForElementPresentByXpath(String xpath, String message) throws InterruptedException {
1812        return jiraAwareWaitFor(By.xpath(xpath), message);
1813    }
1814
1815    protected void waitForElementsPresentByXpath(String xpathLocator) throws InterruptedException {
1816        jiraAwareWaitFors(By.xpath(xpathLocator), this.getClass().toString());
1817    }
1818
1819    protected void waitForElementNotPresent(By by) throws InterruptedException {
1820        waitForElementNotPresent(by, WebDriverUtils.configuredImplicityWait());
1821    }
1822
1823    protected void waitForElementNotPresent(By by, int secondsToWait) throws InterruptedException {
1824        waitForElementNotPresent(by, this.getClass().getSimpleName(), secondsToWait);
1825    }
1826
1827    protected void waitForElementNotPresent(By by, String message) throws InterruptedException {
1828        waitForElementNotPresent(by, this.getClass().getSimpleName(), WebDriverUtils.configuredImplicityWait());
1829    }
1830
1831    protected void waitForElementNotPresent(By by, String message, int secondsToWait) throws InterruptedException {
1832        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1833        while (isElementPresent(by)) {
1834            if (secondsToWait == 0) {
1835                break;
1836            }
1837            secondsToWait -= 1;
1838            Thread.sleep(1000);
1839        }
1840        if (isElementPresent(by)) {
1841            jiraAwareFail(by + " is still present " + message);
1842        }
1843        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1844    }
1845
1846
1847    protected boolean waitForIsTextPresent(String text) throws InterruptedException {
1848        boolean present = false;
1849        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1850        int secondsToWait = WebDriverUtils.configuredImplicityWait();
1851        while (!isTextPresent(text) && secondsToWait > 0) {
1852            secondsToWait -= 1;
1853            Thread.sleep(1000);
1854        }
1855        if (isTextPresent(text)) {
1856            present = true;
1857        }
1858        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1859        return present;
1860    }
1861
1862    protected void waitForProgress(String altText) throws InterruptedException {
1863        waitForProgress(altText, waitSeconds);
1864    }
1865
1866    protected void waitForProgress(String altText, int timeout) throws InterruptedException {
1867        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1868        for (int second = 0;; second++) {
1869            Thread.sleep(1000); // sleep for a second first, give element time to exist
1870
1871            if (second >= timeout) {
1872                jiraAwareFail(TIMEOUT_MESSAGE + " still Loading after " + timeout + " seconds.");
1873            }
1874
1875            try {
1876                if (!isElementPresentByXpath("//img[@alt='" + altText + "']") || !isVisible(By.xpath("//img[@alt='" + altText + "']"))) {
1877                    break;
1878                }
1879            } catch (Exception e) {
1880                // assume timing with img going away and continue with test
1881                break;
1882            }
1883
1884        }
1885        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1886    }
1887
1888    protected void waitForProgressAddingLine() throws InterruptedException {
1889        waitForProgress("Adding Line...");
1890    }
1891
1892    protected void waitForProgressDeletingLine() throws InterruptedException {
1893        waitForProgress("Deleting Line...");
1894    }
1895
1896    protected void waitForProgressAddingLine(int secondsToWait) throws InterruptedException {
1897        waitForProgress("Adding Line...", secondsToWait);
1898    }
1899
1900    protected void waitForProgressLoading() throws InterruptedException {
1901        waitForProgress("Loading...", WebDriverUtils.configuredImplicityWait() * 4);
1902    }
1903
1904    protected void waitForProgressLoading(int secondsToWait) throws InterruptedException {
1905        waitForProgress("Loading...", secondsToWait);
1906    }
1907
1908    protected void waitForProgressSaving() throws InterruptedException {
1909        waitForProgress("Saving...", WebDriverUtils.configuredImplicityWait() * 4);
1910    }
1911
1912    protected void waitForProgressSaving(int secondsToWait) throws InterruptedException {
1913        waitForProgress("Saving...", secondsToWait);
1914    }
1915
1916    protected void waitForTextPresent(String text) throws InterruptedException {
1917        waitForTextPresent(text, WebDriverUtils.configuredImplicityWait());
1918    }
1919
1920    protected void waitForTextPresent(String text, String message) throws InterruptedException {
1921        waitForTextPresent(text, WebDriverUtils.configuredImplicityWait(), message);
1922    }
1923
1924    protected void waitForTextPresent(String text, int secondsToWait) throws InterruptedException {
1925        waitForTextPresent(text, secondsToWait, this.getClass().getSimpleName());
1926    }
1927
1928    protected void waitForTextPresent(String text, int secondsToWait, String message) throws InterruptedException {
1929        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1930        while (!isTextPresent(text) && secondsToWait > 0) {
1931            secondsToWait -= 1;
1932            Thread.sleep(1000);
1933        }
1934        if (!isTextPresent(text)) {
1935            jiraAwareFail(message + " " + text + " is not present for " + this.getClass().toString());
1936        }
1937        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1938    }
1939
1940    protected void waitForTextNotPresent(String text) throws InterruptedException {
1941        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
1942        int secondsToWait = WebDriverUtils.configuredImplicityWait();
1943        while (isTextPresent(text) && secondsToWait > 0) {
1944            secondsToWait -= 1;
1945            Thread.sleep(1000);
1946        }
1947        if (isTextPresent(text)) {
1948            jiraAwareFail(text + " is still present for " + this.getClass().toString());
1949        }
1950        driver.manage().timeouts().implicitlyWait(waitSeconds, TimeUnit.SECONDS);
1951    }
1952
1953    protected void waitIsVisible(By by) throws InterruptedException {
1954        waitIsVisible(by, this.getClass().getSimpleName());
1955    }
1956
1957    protected void waitIsVisible(By by, String message) throws InterruptedException {
1958        for (int second = 0;; second++) {
1959            if (second >= waitSeconds) {
1960                jiraAwareFail(TIMEOUT_MESSAGE + " " + by.toString() + " " + message);
1961            }
1962            if (isVisible(by)) {
1963                break;
1964            }
1965            Thread.sleep(1000);
1966        }
1967
1968        if (!isVisible(by)) {
1969            jiraAwareFail(by.toString() + " not visiable", message);
1970        }
1971    }
1972
1973    protected void waitIsVisible(String locator) throws InterruptedException {
1974        waitIsVisible(By.cssSelector(locator));
1975    }
1976
1977    protected void waitIsVisibleByXpath(String locator) throws InterruptedException {
1978        waitIsVisible(By.xpath(locator));
1979    }
1980
1981    protected void waitIsVisibleByXpath(String locator, String message) throws InterruptedException {
1982        waitIsVisible(By.xpath(locator), message);
1983    }
1984
1985    protected void waitNotVisible(By by) throws InterruptedException {
1986        waitNotVisible(by, this.getClass().getSimpleName());
1987    }
1988
1989    protected void waitNotVisible(By by, String message) throws InterruptedException {
1990        for (int second = 0;; second++) {
1991            if (second >= waitSeconds) {
1992                jiraAwareFail(TIMEOUT_MESSAGE + " " + message);
1993            }
1994            if (!isVisible(by)) {
1995                break;
1996            }
1997            Thread.sleep(1000);
1998        }
1999    }
2000
2001    protected void waitNotVisibleByXpath(String locator) throws InterruptedException {
2002        waitNotVisible(By.xpath(locator));
2003    }
2004
2005    protected void waitNotVisibleByXpath(String locator, String message) throws InterruptedException {
2006        waitNotVisible(By.xpath(locator), message);
2007    }
2008}