001/**
002 * Copyright 2005-2018 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.Assert;
019import org.kuali.rice.testtools.common.JiraAwareFailable;
020import org.kuali.rice.testtools.common.JiraAwareFailureUtils;
021import org.openqa.selenium.By;
022import org.openqa.selenium.WebDriver;
023import org.openqa.selenium.WebElement;
024
025import java.util.List;
026
027/**
028 * <p>
029 * Jira Aware Automated Functional Test Base.
030 * </p><p>
031 *     <img src="https://wiki.kuali.org/download/attachments/330268881/JiraAwareFailure.png"/>
032 * <ul>
033 *     <li>{@see JiraAwareWebDriverUtils}</li>
034 *     <li>{@see JiraAwareFailable}</li>
035 *     <li>{@see JiraAwareFailure}</li>
036 * </ul>
037 * TODO: promote the various jiraAware methods from WebDriverLegacyITBase
038 * </p>
039 *
040 * @author Kuali Rice Team (rice.collab@kuali.org)
041 */
042public abstract class JiraAwareAftBase extends AutomatedFunctionalTestBase implements JiraAwareFailable {
043
044    /**
045     * Test state, used for Saucelabs REST API call to set test state via @{see SauceLabsWebDriverHelper#tearDown}.
046     */
047    private boolean passed = false;
048
049    /**
050     * Implement to check for Incident Report or other on screen errors, should call {@see JiraAwareFailable#fail} to fail,
051     * without calling any of the jiraAwareFail methods to avoid an infinite loop.
052     *
053     * @param locator used in failure message if there is an incident report can be blank
054     * @param message used in failure message if there is an incident report can be blank
055     */
056    protected abstract void checkForIncidentReport(String locator, String message);
057
058    /**
059     * WebDriver used in fail and pass to display jGrowl messages.
060     *
061     * @return WebDriver used to display jGrowl messages on fail and pass
062     */
063    protected abstract WebDriver getDriver();
064
065    /**
066     * {@see WebDriverUtils#assertButtonDisabledByText}
067     *
068     * @param buttonText of button to assert is disabled
069     */
070    protected void assertButtonDisabledByText(String buttonText) {
071        JiraAwareWebDriverUtils.assertButtonDisabledByText(getDriver(), buttonText, this);
072    }
073
074    /**
075     * {@see WebDriverUtils.assertButtonEnabledByText}.
076     *
077     * @param buttonText of button to assert is disabled
078     */
079    protected void assertButtonEnabledByText(String buttonText) {
080        JiraAwareWebDriverUtils.assertButtonEnabledByText(getDriver(), buttonText, this);
081    }
082
083    protected void assertDataTableContains(String[][] data) throws InterruptedException {
084        boolean dataPresent = true;
085        String missingMessage = "";
086        String dataTableRow;
087        for (int i = 0, s = data.length; i < s; i++) {
088            dataTableRow = findDataTableRow(data[i][0]).getText();
089            for (int j = 1, t = data[i].length; j < t; j++) {
090                if (!dataTableRow.contains(data[i][j])) {
091                    dataPresent = false;
092                    missingMessage += data[i][j] + " not present in data table row containing " + data[i][0] + ". ";
093                }
094            }
095            WebDriverUtils.jGrowl(getDriver(), "Assert DataTable Row", false, "Assert datatable row '" + dataTableRow
096                    + "' contains '" + data[i] + "' " + dataPresent);
097        }
098        if (!dataPresent) {
099            jiraAwareFail(missingMessage);
100        }
101    }
102
103    protected void assertDataTableContains(String[][] data, String tableClass) throws InterruptedException {
104        boolean dataPresent = true;
105        String missingMessage = "";
106        String dataTableRow;
107        for (int i = 0, s = data.length; i < s; i++) {
108            dataTableRow = findDataTableRow(data[i][0], tableClass).getText();
109            for (int j = 1, t = data[i].length; j < t; j++) {
110                if (!dataTableRow.contains(data[i][j])) {
111                    dataPresent = false;
112                    missingMessage += data[i][j] + " not present in data table row containing " + data[i][0] + ". ";
113                }
114            }
115        }
116        if (!dataPresent) {
117            jiraAwareFail(missingMessage);
118        }
119    }
120
121    protected void assertElementPresentByName(String name) {
122        assertElementPresentByName(name, this.getClass().toString());
123    }
124
125    protected void assertElementPresentByName(String name, String message) {
126        try {
127            findElement(By.name(name));
128        } catch (Throwable t) {
129            jiraAwareFail(name + " not present " + message);
130        }
131    }
132
133    protected void assertElementPresentByXpath(String locator) {
134        assertElementPresentByXpath(locator, this.getClass().toString());
135    }
136
137    protected void assertElementPresent(By by) {
138        assertElementPresent(by, this.getClass().toString());
139    }
140
141    protected void assertElementPresent(By by, String message) {
142        try {
143            findElement(by);
144        } catch (Throwable t) {
145            jiraAwareFail(by, message, t);
146        }
147    }
148
149    protected void assertElementPresentByXpath(String locator, String message) {
150        try {
151            findElement(By.xpath(locator));
152        } catch (Throwable t) {
153            jiraAwareFail(By.xpath(locator), message, t);
154        }
155    }
156
157    protected void assertElementPresentByLinkText(String linkText) {
158        try {
159            findElement(By.linkText(linkText));
160        } catch (Throwable t) {
161            jiraAwareFail(By.cssSelector(linkText), this.getClass().toString(), t);
162        }
163
164    }
165
166    protected void assertElementPresent(String locator) {
167        try {
168            findElement(By.cssSelector(locator));
169        } catch (Throwable t) {
170            jiraAwareFail(By.cssSelector(locator), this.getClass().toString(), t);
171        }
172    }
173
174    protected void assertEquals(boolean expected, boolean actual) {
175        if (expected != actual) {
176            jiraAwareFail("Expected \"" + expected + "\" but saw \"" + actual + "\" instead");
177        }
178    }
179
180    protected void assertEquals(int expected, int actual) {
181        if (expected != actual) {
182            jiraAwareFail("Expected \"" + expected + "\" but saw \"" + actual + "\" instead");
183        }
184    }
185
186    protected void assertEquals(String message, int expected, int actual) {
187        if (expected != actual) {
188            jiraAwareFail("Expected \"" + expected + "\" but saw \"" + actual + "\" instead " + message);
189        }
190    }
191
192
193    protected void assertEquals(String expected, String actual) {
194        if (!expected.equals(actual)) {
195            jiraAwareFail("Expected \"" + expected + "\" but saw \"" + actual + "\" instead in " + getClass().toString());
196        }
197    }
198
199    protected void assertEquals(String message, String expected, String actual) {
200        if (!expected.equals(actual)) {
201            jiraAwareFail("Expected \"" + expected + "\" but saw \"" + actual + "\" instead " + message);
202        }
203    }
204
205    /**
206     * If booleanToAssertFalse is true call {@see jiraAwareFail}.
207     *
208     * @param booleanToAssertFalse
209     */
210    protected void assertFalse(boolean booleanToAssertFalse) {
211        JiraAwareWebDriverUtils.assertFalse(booleanToAssertFalse, this);
212    }
213
214    /**
215     * If booleanToAssertFalse is true call {@see jiraAwareFail}.
216     *
217     * @param message to include if booleanToAssertTrue is true
218     * @param booleanToAssertFalse
219     */
220    protected void assertFalse(String message, boolean booleanToAssertFalse) {
221        JiraAwareWebDriverUtils.assertFalse(message, booleanToAssertFalse, this);
222    }
223
224    protected void assertIsVisible(String locator) {
225        if (!isVisible(locator)) {
226            jiraAwareFail(locator + " is not visible and should be");
227        }
228    }
229
230    protected void assertIsVisible(By by, String message) {
231        if (!isVisible(by)) {
232            jiraAwareFail(by + " not visible " + message);
233        }
234    }
235
236    protected void assertIsVisibleById(String id) {
237        if (!isVisibleById(id)) {
238            jiraAwareFail(id + " is not visible and should be");
239        }
240    }
241
242    protected void assertIsVisibleByXpath(String xpath, String message) {
243        if (!isVisibleByXpath(xpath)) {
244            jiraAwareFail(xpath + " not visible " + message);
245        }
246    }
247
248    protected void assertIsNotVisible(By by) {
249        assertIsNotVisible(by, this.getClass().toString());
250    }
251
252    protected void assertIsNotVisible(By by, String message) {
253        if (isVisible(by)) {
254            jiraAwareFail(by + " is visible and should not be " + message);
255        }
256    }
257
258    protected void assertIsNotVisible(String locator) {
259        if (isVisible(locator)) {
260            jiraAwareFail(locator + " is visible and should not be");
261        }
262    }
263
264    protected void assertIsNotVisibleByXpath(String xpath) {
265        if (isVisible(By.xpath(xpath))) {
266            jiraAwareFail(xpath + " is visible and should not be");
267        }
268    }
269
270    protected void assertIsNotVisibleByXpath(String xpath, String message) {
271        if (isVisibleByXpath(xpath)) {
272            jiraAwareFail(xpath + " visible and should not be " + message);
273        }
274    }
275
276    protected void assertLabeledTextNotPresent(String[][] labeledText) {
277        boolean allLabeledTextNotPresent = true;
278        String missingMessage = "";
279        for (int i = 0, s = labeledText.length; i < s; i++) {
280            if (isLabeledTextPresent(labeledText[i][0], labeledText[i][1])) {
281                allLabeledTextNotPresent = false;
282                missingMessage += "Text: " + labeledText[i][1] + " labeled by: " + labeledText[i][0] + " present. ";
283            }
284        }
285        if (!allLabeledTextNotPresent) {
286            jiraAwareFail(missingMessage);
287        }
288    }
289
290    protected void assertLabeledTextPresent(String[][] labeledText) {
291        boolean allLabeledTextPresent = true;
292        String missingMessage = "";
293        for (int i = 0, s = labeledText.length; i < s; i++) {
294            if (!isLabeledTextPresent(labeledText[i][0], labeledText[i][1])) {
295                allLabeledTextPresent = false;
296                missingMessage += "Text: " + labeledText[i][1] + " labeled by: " + labeledText[i][0] + " not present. ";
297            }
298        }
299        if (!allLabeledTextPresent) {
300            jiraAwareFail(missingMessage);
301        }
302    }
303
304    /**
305     * Looks for values in input or select
306     * @param labeledText
307     */
308    protected void assertLabeledInputTextPresent(String[][] labeledText) {
309        boolean allLabeledTextPresent = true;
310        String missingMessage = "";
311        for (int i = 0, s = labeledText.length; i < s; i++) {
312            if (!isLabeledInputTextPresent(labeledText[i][0], labeledText[i][1])) {
313                allLabeledTextPresent = false;
314                missingMessage += "Text: " + labeledText[i][1] + " labeled by: " + labeledText[i][0] + " not present. ";
315            }
316        }
317        if (!allLabeledTextPresent) {
318            jiraAwareFail(missingMessage);
319        }
320    }
321
322    protected void assertLabeledTextPresent(String label, String text) {
323        if (!isLabeledTextPresent(label, text)) {
324            jiraAwareFail("Text: " + text + " labeled by: " + label + " not present");
325        }
326    }
327
328    protected void assertResultCount(String count) throws InterruptedException {
329        jiraAwareWaitFor(By.cssSelector("div.dataTables_info"), "result count for " + this.getClass().toString());
330        assertTextPresent("of " + count + " entries", "div.dataTables_info", this.getClass().toString());
331    }
332
333    /**
334     * <b>WARNING:</b> this only does a check against the page source.  The form url can have random character that match
335     * simple text.  A narrowly scoped locator for {@see #assertTextPresent(String String String)}
336     *
337     * @param text
338     */
339    protected void assertTextPresent(String text) {
340        assertTextPresent(text, this.getClass().toString());
341    }
342
343    /**
344     * <b>WARNING:</b> this only does a check against the page source.  The form url can have random character that match simple text
345     * @param text
346     */
347    protected void assertTextPresent(String text, String message) {
348        WebDriverUtils.jGrowl(getDriver(), "Assert Text Present", false, "Assert text '" + text + "' is present.");
349        String pageSource = getDriver().getPageSource();
350        if (!pageSource.contains(text)) {
351            jiraAwareFail(text + " not present " + message);
352        }
353        WebDriverUtils.highlightElement(getDriver(), By.xpath("//*[contains(text(), '" + text + "')]"));
354    }
355
356    /**
357     * @param text
358     */
359    protected void assertTextPresent(String text, String cssSelector, String message){
360        WebElement element = findElement(By.cssSelector(cssSelector));
361        if (!element.getText().contains(text)){
362            jiraAwareFail(text + " for " + cssSelector + " not present " + message);
363        }
364    }
365
366    /**
367     * Asset that the given text does not occur in the page
368     * Warning, this only does a check against the page source.  The form url can have random character that match simple text
369     * @param text the text to search for
370     */
371    protected void assertTextNotPresent(String text) {
372        assertTextNotPresent(text, this.getClass().toString());
373    }
374
375    /**
376     * Assert that the given text does not occur in the page, and add an additional message to the failure
377     * @param text the text to search for
378     * @param message the message to add to the failure
379     */
380    protected void assertTextNotPresent(String text, String message) {
381        String contents = getDriver().getPageSource();
382        if (contents.contains(text)) {
383            jiraAwareFail(text + " is present and should not be " + message);
384        }
385    }
386
387    /**
388     * @param text
389     */
390    protected void assertTextNotPresent(String text, String cssSelector, String message){
391        WebElement element = findElement(By.cssSelector(cssSelector));
392        if (element.getText().contains(text)){
393            jiraAwareFail(text + " for " + cssSelector + " is present and shouldn't be " + message);
394        }
395    }
396
397    /**
398     * If booleanToAssertTrue is false call {@see jiraAwareFail}.
399     *
400     * @param booleanToAssertTrue
401     */
402    protected void assertTrue(boolean booleanToAssertTrue) {
403        JiraAwareWebDriverUtils.assertTrue(getClass().toString(), booleanToAssertTrue, this);
404    }
405
406    /**
407     * If booleanToAssertTrue is false call {@see jiraAwareFail}.
408     *
409     * @param message to include if booleanToAssertTrue is false
410     * @param booleanToAssertTrue
411     */
412    protected void assertTrue(String message, boolean booleanToAssertTrue) {
413        JiraAwareWebDriverUtils.assertTrue(message, booleanToAssertTrue, this);
414    }
415
416    /**
417     * {@inheritDoc}
418     * <p>
419     * Set passed to false, call jGrowl sticky with the given message, then fails using  {@see JiraAwareFailable#fail}.
420     * </p>
421     * @param message to display with failure
422     */
423    @Override
424    public void fail(String message) {
425        passed = false;
426        WebDriverUtils.jGrowl(getDriver(), "Failure " + getClass().getSimpleName(), true, message);
427        Assert.fail(message); // The final fail that JiraAwareFailure calls, do not change this to a JiraAwareFailure.
428    }
429
430    protected WebElement findDataTableRow(String keyText) throws InterruptedException {
431        return findDataTableRow(keyText, "dataTable");
432    }
433
434    protected WebElement findDataTableRow(String keyText, String className) throws InterruptedException {
435        jiraAwareWaitFor(By.className(className));
436        WebElement element = findElement(By.className(className));
437        return findElement(By.xpath("./*/tr//*[contains(text(), '" + keyText + "')]/ancestor::tr"), element);
438    }
439
440    /**
441     * {@see WebDriverUtils#findElement}.
442     *
443     * @param by to find element with
444     * @return WebElement found with given by
445     */
446    protected WebElement findElement(By by) {
447        try {
448            return WebDriverUtils.findElement(getDriver(), by);
449        } catch (Throwable t) {
450            checkForIncidentReport(by.toString(), t.getMessage());
451            jiraAwareFail(by.toString(), t.getMessage(), t);
452        }
453        return null; // required by compiler, never reached
454    }
455
456    protected WebElement findElement(By by, WebElement elementToFindOn) {
457        try {
458            WebElement found = elementToFindOn.findElement(by);
459            WebDriverUtils.highlightElement(getDriver(), found);
460            return found;
461        } catch (Throwable t) {
462            checkForIncidentReport(by.toString(), t.getMessage());
463            jiraAwareFail(by.toString(), t.getMessage() + " " + this.getClass().toString(), t);
464        }
465        return null; // required by compiler, never reached
466    }
467
468    protected boolean isLabeledTextPresent(String label, String text) {
469        WebElement element = findElement(By.xpath("//tr/th/label[contains(text(), '" + label + "')]/ancestor::tr/td"));
470        String labeledText = element.getText().trim();
471        WebDriverUtils.jGrowl(getDriver(), "Is Labeled Text Present", false, "Is text '" + text + "' present for label '"
472                + label + "'? " + labeledText.contains(text) + " saw " + labeledText);
473        return labeledText.contains(text);
474    }
475
476    protected boolean isLabeledInputTextPresent(String label, String text) {
477        String labeledText = "no input or select found no text returned";
478        List<WebElement> inputs = getDriver().findElements(By.xpath("//tr/th/label[contains(text(), '" + label + "')]/ancestor::tr/td/div/input"));
479
480        if (inputs.size() > 1) {
481            System.out.println("found more elements in labeled input than expected");
482        }
483
484        if (inputs.size() == 1) {
485            labeledText = inputs.get(0).getAttribute("value").trim();
486            // seeing this on Agenda Context select, value is getting uppercased somewhere...
487            if (labeledText.equals(text.toUpperCase())) {
488                text = text.toUpperCase();
489            }
490
491        } else {
492            inputs = getDriver().findElements(By.xpath("//tr/th/label[contains(text(), '" + label + "')]/ancestor::tr/td/div/select"));
493
494            if (inputs.size() > 1) {
495                System.out.println("found more elements in labeled input than expected");
496            }
497
498            if (inputs.size() == 1) {
499                List<WebElement> options = inputs.get(0).findElements(By.tagName("option"));
500                for (WebElement option : options) {
501                    if (option.getAttribute("selected") != null) {
502                        labeledText = option.getText().trim();
503                    }
504                }
505            }
506        }
507
508        WebDriverUtils.jGrowl(getDriver(), "Is Labeled Text Present", false, "Is text '" + text + "' present for label '"
509                + label + "'? " + labeledText.contains(text) + " saw " + labeledText);
510        return labeledText.contains(text);
511    }
512
513    protected boolean isVisible(String locator) {
514        return isVisible(By.cssSelector(locator));
515    }
516
517    protected boolean isVisible(By by) {
518        List<WebElement> elements = getDriver().findElements(by);
519        for (WebElement element: elements) {
520            try {
521                if (element.isDisplayed()) {
522                    return true;
523                }
524            } catch (Throwable t) {
525                // don't fail
526            }
527        }
528        return false;
529    }
530
531    protected boolean isVisibleById(String id) {
532        return isVisible(By.id(id));
533    }
534
535    protected boolean isVisibleByXpath(String locator) {
536        return isVisible(By.xpath(locator));
537    }
538
539    protected WebElement jiraAwareClearType(By by, String text) {
540        return jiraAwareClearAndType(by, text, this.getClass().toString().replace("class ", ""));
541    }
542
543    protected WebElement jiraAwareClearAndType(By by, String text, String failureMessage) {
544        findElement(by).clear();
545        return jiraAwareType(by, text, failureMessage);
546    }
547
548    protected WebElement jiraAwareClearAndTypeByName(String name, String text) {
549        return jiraAwareClearAndType(By.name(name), text, this.getClass().toString().replace("class ", ""));
550    }
551
552    protected WebElement jiraAwareClearAndTypeByName(String name, String text, String failureMessage) {
553        return jiraAwareClearAndType(By.name(name), text, failureMessage);
554    }
555
556    /**
557     * {@inheritDoc}
558     * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
559     *
560     * @param message to check for a Jira match and fail with.
561     */
562    @Override
563    public void jiraAwareFail(String message) {
564        jiraAwareFail("", message, null, this);
565    }
566
567    /**
568     * {@inheritDoc}
569     * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
570     *
571     * @param contents to check for a Jira match
572     * @param message to check for a Jira match and fail with.
573     */
574    @Override
575    public void jiraAwareFail(String contents, String message) {
576        jiraAwareFail(contents, message, null, this);
577    }
578
579    /**
580     * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
581     *
582     * @param by to check for a Jira match
583     * @param message to check for a Jira match and fail with.
584     * @param throwable to check for a Jira match
585     */
586    protected void jiraAwareFail(By by, String message, Throwable throwable) {
587        jiraAwareFail(by.toString(), message, throwable, this);
588    }
589
590    /**
591     * {@inheritDoc}
592     * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
593     *
594     * @param contents to check for a Jira match
595     * @param message to check for a Jira match and fail with.
596     * @param throwable to check for a Jira match
597     */
598    @Override
599    public void jiraAwareFail(String contents, String message, Throwable throwable) {
600        jiraAwareFail(contents, message, throwable, this);
601    }
602
603    public void jiraAwareFail(String pageSource, By by, String message, Throwable t) {
604
605    }
606
607
608    /**
609     * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
610     *
611     * @param contents to check for a Jira match
612     * @param message to check for a Jira match and fail with.
613     * @param throwable to check for a Jira match
614     * @param failable to call fail on
615     */
616    protected void jiraAwareFail(String contents, String message, Throwable throwable, JiraAwareFailable failable) {
617        passed = false;
618
619        if (message == null) {
620            message = "";
621        }
622
623        String javascriptErrors = WebDriverUtils.javascriptErrorsToString(WebDriverUtils.javascriptErrors(getDriver()));
624        message = javascriptErrors + message;
625
626        if (contents == null) {
627            contents = getDriver().getPageSource();
628        }
629
630        if (!contents.startsWith("\nIncident report") && !message.startsWith("\nIncident report")) {
631            String errorMessage = AutomatedFunctionalTestUtils.incidentReportMessage(getDriver().getPageSource(), "", message);
632            if (errorMessage != null) {
633                JiraAwareFailureUtils.failOnMatchedJira(errorMessage, message, failable);
634                JiraAwareFailureUtils.fail(errorMessage, message, throwable, failable);
635            }
636        }
637
638        JiraAwareFailureUtils.fail(contents, message, throwable, failable);
639    }
640
641    /**
642     * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
643     *
644     * @param by to click on
645     * @param message on failure
646     * @throws InterruptedException
647     */
648    protected void jiraAwareWaitAndClick(By by, String message) throws InterruptedException {
649        jiraAwareWaitAndClick(by, message, this);
650    }
651
652    protected WebElement jiraAwareType(By by, String text) {
653        return jiraAwareType(by, text, this.getClass().toString().replace("class ", ""));
654    }
655
656    protected WebElement jiraAwareType(By by, String text, String failureMessage) {
657        try {
658            return type(by, text);
659        } catch (Throwable t) {
660            JiraAwareFailureUtils.failOnMatchedJira(by.toString(), failureMessage, this);
661            jiraAwareFail(t.getMessage()
662                    + " "
663                    + by.toString()
664                    + "  unable to type text '"
665                    + text
666                    + "'  "
667                    + failureMessage
668                    + " current url "
669                    + getDriver().getCurrentUrl()
670                    + "\n"
671                    + AutomatedFunctionalTestUtils.deLinespace(getDriver().getPageSource()));
672        }
673        return null;
674    }
675
676    protected WebElement jiraAwareTypeByName(String name, String text) {
677        return jiraAwareType(By.name(name), text, this.getClass().toString().replace("class ", ""));
678    }
679
680    protected WebElement jiraAwareTypeByName(String name, String text, String failureMessage) {
681        return jiraAwareType(By.name(name), text, failureMessage);
682    }
683
684    /**
685     * {@see #jiraAwareWaitFor}
686     *
687     * @param by to click on
688     * @param message on failure
689     * @param failable to fail on if not found
690     * @throws InterruptedException
691     */
692    protected void jiraAwareWaitAndClick(By by, String message, JiraAwareFailable failable) throws InterruptedException {
693        jiraAwareWaitAndClick(by, WebDriverUtils.configuredImplicityWait(), message, failable);
694    }
695
696    protected void jiraAwareWaitAndClick(By by, int waitSeconds, String message, JiraAwareFailable failable) throws InterruptedException {
697        try {
698            jiraAwareWaitFor(by, waitSeconds, message, failable);
699            findElement(by).click();
700            // possible future code of outputting clicked components in a more generic way, but need to look into duplicates, don't delete
701            //            WebElement element = findElement(by);
702            //            String jgrowl = element.getAttribute("name");
703            //            if (jgrowl == null || "".equals(jgrowl)) {
704            //                jgrowl = element.getAttribute("id");
705            //            }
706            //            if (jgrowl == null || "".equals(jgrowl)) {
707            //                jgrowl = by.toString();
708            //            }
709            //            WebDriverUtils.jGrowl(getDriver(), "Click " + jgrowl, false, "Click " + jgrowl);
710            //            element.click();
711        } catch (Throwable t) {
712            failable.jiraAwareFail(by.toString(), message, t);
713        }
714    }
715
716    /**
717     * {@see WebDriverUtils#waitFor}.
718     *
719     * @param by to find
720     * @return WebElement found with given by
721     * @throws InterruptedException
722     */
723    protected WebElement jiraAwareWaitFor(By by) throws InterruptedException {
724        return jiraAwareWaitFor(by, this.getClass().toString());
725    }
726
727    /**
728     * {@see WebDriverUtils#waitFor}.
729     *
730     * @param by to find
731     * @param message on failure
732     * @return WebElement found with given by
733     * @throws InterruptedException
734     */
735    protected WebElement jiraAwareWaitFor(By by, String message) throws InterruptedException {
736        try {
737            return WebDriverUtils.waitFor(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
738        } catch (Throwable t) {
739            jiraAwareFail(by, message + " " + this.getClass().toString(), t);
740        }
741        return null; // required, but the jiraAwareFail will will end test before this statement is reached
742    }
743
744    /**
745     * {@see WebDriverUtils#waitFor}.
746     *
747     * @param by to find
748     * @param message on failure
749     * @throws InterruptedException
750     */
751    protected void jiraAwareWaitFors(By by, String message) throws InterruptedException {
752        try {
753            WebDriverUtils.waitFors(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
754        } catch (Throwable t) {
755            jiraAwareFail(by, message, t);
756        }
757    }
758
759    /**
760     * {@see WebDriverUtils#waitFor}.
761     *
762     * @param by to find
763     * @param message on failure
764     * @param failable to fail if given by is not found
765     * @throws InterruptedException
766     */
767    protected void jiraAwareWaitFor(By by, String message, JiraAwareFailable failable) throws InterruptedException {
768        jiraAwareWaitFor(by, WebDriverUtils.configuredImplicityWait(), message, failable);
769    }
770
771    protected void jiraAwareWaitFor(By by, int waitSeconds, String message, JiraAwareFailable failable) throws InterruptedException {
772        try {
773            WebDriverUtils.waitFor(getDriver(), waitSeconds, by, message);
774        } catch (Throwable t) {
775            jiraAwareFail(by.toString(), message, t, failable);
776        }
777    }
778
779    /**
780     * {@see WebDriverUtils#waitFor}.
781     *
782     * @param by to find
783     * @param seconds to wait
784     * @param message on failure
785     * @return WebElement found with given by
786     * @throws InterruptedException
787     */
788    protected WebElement jiraAwareWaitFor(By by, int seconds, String message) throws InterruptedException {
789        try {
790            return WebDriverUtils.waitFor(getDriver(), seconds, by, message);
791        } catch (Throwable t) {
792            jiraAwareFail(by, message, t);
793        }
794        return null; // required, but the jiraAwareFail will will end test before this statement is reached
795    }
796
797    /**
798     * @return passed
799     */
800    public boolean isPassed() {
801        return passed;
802    }
803
804    protected void selectOptionByName(String name, String optionValue) throws InterruptedException {
805        selectOption(By.name(name), optionValue);
806    }
807
808    protected void selectOptionByXpath(String locator, String optionValue) throws InterruptedException {
809        selectOption(By.name(locator), optionValue);
810    }
811
812    /**
813     * Uses Selenium's findElements method which does not throw a test exception if not found.
814     * @param by
815     * @param optionValue
816     * @throws InterruptedException
817     */
818    protected void selectOption(By by, String optionValue) throws InterruptedException {
819        WebElement select1 = findElement(by);
820        List<WebElement> options = select1.findElements(By.tagName("option"));
821
822        String name = select1.getAttribute("name");
823
824        if (options == null || options.size() == 0) {
825            jiraAwareFail("No options for select "
826                    + select1.toString()
827                    + " was looking for value "
828                    + optionValue
829                    + " using "
830                    + by.toString());
831        }
832
833        for (WebElement option : options) {
834            if (option.getAttribute("value").equals(optionValue)) {
835                WebDriverUtils.jGrowl(getDriver(), "Select " + option.getText(), false, "Select " + option.getText() + " from " + name);
836                option.click();
837                break;
838            }
839        }
840    }
841
842    /**
843     * Uses Selenium's findElements method which does not throw a test exception if not found.
844     * @param by
845     * @param optionText
846     * @throws InterruptedException
847     */
848    protected void selectOptionText(By by, String optionText) throws InterruptedException {
849        WebElement select1 = findElement(by);
850        List<WebElement> options = select1.findElements(By.tagName("option"));
851
852        String name = select1.getAttribute("name");
853
854        if (options == null || options.size() == 0) {
855            jiraAwareFail("No options for select "
856                    + select1.toString()
857                    + " was looking for text "
858                    + optionText
859                    + " using "
860                    + by.toString());
861        }
862
863        for (WebElement option : options) {
864            if (option.getText().equals(optionText)) {
865                WebDriverUtils.jGrowl(getDriver(), "Select " + option.getText(), false, "Select " + option.getText() + " from " + name);
866                option.click();
867                break;
868            }
869        }
870    }
871
872    private WebElement type(By by, String text) {
873        WebElement element = findElement(by);
874        String name = element.getAttribute("name");
875        WebDriverUtils.jGrowl(getDriver(), "Type", false, "Type into " + name + " the text: " + text);
876        WebDriverUtils.highlightElement(getDriver(), element);
877        element.sendKeys(text);
878        return element;
879    }
880
881    private WebElement typeByName(String name, String text) {
882        return type(By.name(name), text);
883    }
884
885    /**
886     * <p>
887     * Set the test state to passed, call jGrowl sticky with success, required to be called at the conclusion of a test
888     * for the saucelabs state of a test to be updated to passed.
889     * </p>
890     */
891    protected void passed() {
892        if (passed == true) {
893            WebDriverUtils.jGrowl(getDriver(), "Passed has been called more than once " + getClass().getSimpleName(), true, "Passed");
894        }
895        passed = true;
896        WebDriverUtils.jGrowl(getDriver(), "Success " + getClass().getSimpleName(), true, "Passed");
897    }
898
899    protected WebElement waitAndType(By by, String text, String message) throws InterruptedException {
900        try {
901            jiraAwareWaitFor(by, message);
902            return type(by, text);
903        } catch (Throwable t) {
904            checkForIncidentReport(by.toString(), message);
905            JiraAwareFailureUtils.failOnMatchedJira(by.toString(), message, this);
906            jiraAwareFail(t.getMessage()
907                    + " "
908                    + by.toString()
909                    + "  unable to type text '"
910                    + text
911                    + "'  "
912                    + message
913                    + " current url "
914                    + getDriver().getCurrentUrl()
915                    + "\n"
916                    + AutomatedFunctionalTestUtils.deLinespace(getDriver().getPageSource()));
917        }
918        return null;
919    }
920}