View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.testtools.selenium;
17  
18  import org.junit.Assert;
19  import org.kuali.rice.testtools.common.JiraAwareFailable;
20  import org.kuali.rice.testtools.common.JiraAwareFailureUtils;
21  import org.openqa.selenium.By;
22  import org.openqa.selenium.WebDriver;
23  import org.openqa.selenium.WebElement;
24  
25  import java.util.List;
26  
27  /**
28   * <p>
29   * Jira Aware Automated Functional Test Base.
30   * </p><p>
31   *     <img src="https://wiki.kuali.org/download/attachments/330268881/JiraAwareFailure.png"/>
32   * <ul>
33   *     <li>{@see JiraAwareWebDriverUtils}</li>
34   *     <li>{@see JiraAwareFailable}</li>
35   *     <li>{@see JiraAwareFailure}</li>
36   * </ul>
37   * TODO: promote the various jiraAware methods from WebDriverLegacyITBase
38   * </p>
39   *
40   * @author Kuali Rice Team (rice.collab@kuali.org)
41   */
42  public abstract class JiraAwareAftBase extends AutomatedFunctionalTestBase implements JiraAwareFailable {
43  
44      /**
45       * Test state, used for Saucelabs REST API call to set test state via @{see SauceLabsWebDriverHelper#tearDown}.
46       */
47      private boolean passed = false;
48  
49      /**
50       * Implement to check for Incident Report or other on screen errors, should call {@see JiraAwareFailable#fail} to fail,
51       * without calling any of the jiraAwareFail methods to avoid an infinite loop.
52       *
53       * @param locator used in failure message if there is an incident report can be blank
54       * @param message used in failure message if there is an incident report can be blank
55       */
56      protected abstract void checkForIncidentReport(String locator, String message);
57  
58      /**
59       * WebDriver used in fail and pass to display jGrowl messages.
60       *
61       * @return WebDriver used to display jGrowl messages on fail and pass
62       */
63      protected abstract WebDriver getDriver();
64  
65      /**
66       * {@see WebDriverUtils#assertButtonDisabledByText}
67       *
68       * @param buttonText of button to assert is disabled
69       */
70      protected void assertButtonDisabledByText(String buttonText) {
71          JiraAwareWebDriverUtils.assertButtonDisabledByText(getDriver(), buttonText, this);
72      }
73  
74      /**
75       * {@see WebDriverUtils.assertButtonEnabledByText}.
76       *
77       * @param buttonText of button to assert is disabled
78       */
79      protected void assertButtonEnabledByText(String buttonText) {
80          JiraAwareWebDriverUtils.assertButtonEnabledByText(getDriver(), buttonText, this);
81      }
82  
83      protected void assertDataTableContains(String[][] data) throws InterruptedException {
84          boolean dataPresent = true;
85          String missingMessage = "";
86          String dataTableRow;
87          for (int i = 0, s = data.length; i < s; i++) {
88              dataTableRow = findDataTableRow(data[i][0]).getText();
89              for (int j = 1, t = data[i].length; j < t; j++) {
90                  if (!dataTableRow.contains(data[i][j])) {
91                      dataPresent = false;
92                      missingMessage += data[i][j] + " not present in data table row containing " + data[i][0] + ". ";
93                  }
94              }
95              WebDriverUtils.jGrowl(getDriver(), "Assert DataTable Row", false, "Assert datatable row '" + dataTableRow
96                      + "' contains '" + data[i] + "' " + dataPresent);
97          }
98          if (!dataPresent) {
99              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 (contents == null) {
620             contents = getDriver().getPageSource();
621         }
622 
623         if (message == null) {
624             message = "";
625         }
626 
627         if (!contents.startsWith("\nIncident report") && !message.startsWith("\nIncident report")) {
628             String errorMessage = AutomatedFunctionalTestUtils.incidentReportMessage(getDriver().getPageSource(), "", message);
629             if (errorMessage != null) {
630                 JiraAwareFailureUtils.failOnMatchedJira(errorMessage, message, failable);
631                 JiraAwareFailureUtils.fail(errorMessage, message, throwable, failable);
632             }
633         }
634 
635         JiraAwareFailureUtils.fail(contents, message, throwable, failable);
636     }
637 
638     /**
639      * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
640      *
641      * @param by to click on
642      * @param message on failure
643      * @throws InterruptedException
644      */
645     protected void jiraAwareWaitAndClick(By by, String message) throws InterruptedException {
646         jiraAwareWaitAndClick(by, message, this);
647     }
648 
649     protected WebElement jiraAwareType(By by, String text) {
650         return jiraAwareType(by, text, this.getClass().toString().replace("class ", ""));
651     }
652 
653     protected WebElement jiraAwareType(By by, String text, String failureMessage) {
654         try {
655             return type(by, text);
656         } catch (Throwable t) {
657             JiraAwareFailureUtils.failOnMatchedJira(by.toString(), failureMessage, this);
658             jiraAwareFail(t.getMessage()
659                     + " "
660                     + by.toString()
661                     + "  unable to type text '"
662                     + text
663                     + "'  "
664                     + failureMessage
665                     + " current url "
666                     + getDriver().getCurrentUrl()
667                     + "\n"
668                     + AutomatedFunctionalTestUtils.deLinespace(getDriver().getPageSource()));
669         }
670         return null;
671     }
672 
673     protected WebElement jiraAwareTypeByName(String name, String text) {
674         return jiraAwareType(By.name(name), text, this.getClass().toString().replace("class ", ""));
675     }
676 
677     protected WebElement jiraAwareTypeByName(String name, String text, String failureMessage) {
678         return jiraAwareType(By.name(name), text, failureMessage);
679     }
680 
681     /**
682      * {@see #jiraAwareWaitFor}
683      *
684      * @param by to click on
685      * @param message on failure
686      * @param failable to fail on if not found
687      * @throws InterruptedException
688      */
689     protected void jiraAwareWaitAndClick(By by, String message, JiraAwareFailable failable) throws InterruptedException {
690         jiraAwareWaitAndClick(by, WebDriverUtils.configuredImplicityWait(), message, failable);
691     }
692 
693     protected void jiraAwareWaitAndClick(By by, int waitSeconds, String message, JiraAwareFailable failable) throws InterruptedException {
694         try {
695             jiraAwareWaitFor(by, waitSeconds, message, failable);
696             findElement(by).click();
697             // possible future code of outputting clicked components in a more generic way, but need to look into duplicates, don't delete
698             //            WebElement element = findElement(by);
699             //            String jgrowl = element.getAttribute("name");
700             //            if (jgrowl == null || "".equals(jgrowl)) {
701             //                jgrowl = element.getAttribute("id");
702             //            }
703             //            if (jgrowl == null || "".equals(jgrowl)) {
704             //                jgrowl = by.toString();
705             //            }
706             //            WebDriverUtils.jGrowl(getDriver(), "Click " + jgrowl, false, "Click " + jgrowl);
707             //            element.click();
708         } catch (Throwable t) {
709             failable.jiraAwareFail(by.toString(), message, t);
710         }
711     }
712 
713     /**
714      * {@see WebDriverUtils#waitFor}.
715      *
716      * @param by to find
717      * @return WebElement found with given by
718      * @throws InterruptedException
719      */
720     protected WebElement jiraAwareWaitFor(By by) throws InterruptedException {
721         return jiraAwareWaitFor(by, this.getClass().toString());
722     }
723 
724     /**
725      * {@see WebDriverUtils#waitFor}.
726      *
727      * @param by to find
728      * @param message on failure
729      * @return WebElement found with given by
730      * @throws InterruptedException
731      */
732     protected WebElement jiraAwareWaitFor(By by, String message) throws InterruptedException {
733         try {
734             return WebDriverUtils.waitFor(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
735         } catch (Throwable t) {
736             jiraAwareFail(by, message + " " + this.getClass().toString(), t);
737         }
738         return null; // required, but the jiraAwareFail will will end test before this statement is reached
739     }
740 
741     /**
742      * {@see WebDriverUtils#waitFor}.
743      *
744      * @param by to find
745      * @param message on failure
746      * @throws InterruptedException
747      */
748     protected void jiraAwareWaitFors(By by, String message) throws InterruptedException {
749         try {
750             WebDriverUtils.waitFors(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
751         } catch (Throwable t) {
752             jiraAwareFail(by, message, t);
753         }
754     }
755 
756     /**
757      * {@see WebDriverUtils#waitFor}.
758      *
759      * @param by to find
760      * @param message on failure
761      * @param failable to fail if given by is not found
762      * @throws InterruptedException
763      */
764     protected void jiraAwareWaitFor(By by, String message, JiraAwareFailable failable) throws InterruptedException {
765         jiraAwareWaitFor(by, WebDriverUtils.configuredImplicityWait(), message, failable);
766     }
767 
768     protected void jiraAwareWaitFor(By by, int waitSeconds, String message, JiraAwareFailable failable) throws InterruptedException {
769         try {
770             WebDriverUtils.waitFor(getDriver(), waitSeconds, by, message);
771         } catch (Throwable t) {
772             jiraAwareFail(by.toString(), message, t, failable);
773         }
774     }
775 
776     /**
777      * {@see WebDriverUtils#waitFor}.
778      *
779      * @param by to find
780      * @param seconds to wait
781      * @param message on failure
782      * @return WebElement found with given by
783      * @throws InterruptedException
784      */
785     protected WebElement jiraAwareWaitFor(By by, int seconds, String message) throws InterruptedException {
786         try {
787             return WebDriverUtils.waitFor(getDriver(), seconds, by, message);
788         } catch (Throwable t) {
789             jiraAwareFail(by, message, t);
790         }
791         return null; // required, but the jiraAwareFail will will end test before this statement is reached
792     }
793 
794     /**
795      * @return passed
796      */
797     public boolean isPassed() {
798         return passed;
799     }
800 
801     protected void selectOptionByName(String name, String optionValue) throws InterruptedException {
802         selectOption(By.name(name), optionValue);
803     }
804 
805     protected void selectOptionByXpath(String locator, String optionValue) throws InterruptedException {
806         selectOption(By.name(locator), optionValue);
807     }
808 
809     /**
810      * Uses Selenium's findElements method which does not throw a test exception if not found.
811      * @param by
812      * @param optionValue
813      * @throws InterruptedException
814      */
815     protected void selectOption(By by, String optionValue) throws InterruptedException {
816         WebElement select1 = findElement(by);
817         List<WebElement> options = select1.findElements(By.tagName("option"));
818 
819         String name = select1.getAttribute("name");
820 
821         if (options == null || options.size() == 0) {
822             jiraAwareFail("No options for select "
823                     + select1.toString()
824                     + " was looking for value "
825                     + optionValue
826                     + " using "
827                     + by.toString());
828         }
829 
830         for (WebElement option : options) {
831             if (option.getAttribute("value").equals(optionValue)) {
832                 WebDriverUtils.jGrowl(getDriver(), "Select " + option.getText(), false, "Select " + option.getText() + " from " + name);
833                 option.click();
834                 break;
835             }
836         }
837     }
838 
839     /**
840      * Uses Selenium's findElements method which does not throw a test exception if not found.
841      * @param by
842      * @param optionText
843      * @throws InterruptedException
844      */
845     protected void selectOptionText(By by, String optionText) throws InterruptedException {
846         WebElement select1 = findElement(by);
847         List<WebElement> options = select1.findElements(By.tagName("option"));
848 
849         String name = select1.getAttribute("name");
850 
851         if (options == null || options.size() == 0) {
852             jiraAwareFail("No options for select "
853                     + select1.toString()
854                     + " was looking for text "
855                     + optionText
856                     + " using "
857                     + by.toString());
858         }
859 
860         for (WebElement option : options) {
861             if (option.getText().equals(optionText)) {
862                 WebDriverUtils.jGrowl(getDriver(), "Select " + option.getText(), false, "Select " + option.getText() + " from " + name);
863                 option.click();
864                 break;
865             }
866         }
867     }
868 
869     private WebElement type(By by, String text) {
870         WebElement element = findElement(by);
871         String name = element.getAttribute("name");
872         WebDriverUtils.jGrowl(getDriver(), "Type", false, "Type into " + name + " the text: " + text);
873         WebDriverUtils.highlightElement(getDriver(), element);
874         element.sendKeys(text);
875         return element;
876     }
877 
878     private WebElement typeByName(String name, String text) {
879         return type(By.name(name), text);
880     }
881 
882     /**
883      * <p>
884      * Set the test state to passed, call jGrowl sticky with success, required to be called at the conclusion of a test
885      * for the saucelabs state of a test to be updated to passed.
886      * </p>
887      */
888     protected void passed() {
889         if (passed == true) {
890             WebDriverUtils.jGrowl(getDriver(), "Passed has been called more than once " + getClass().getSimpleName(), true, "Passed");
891         }
892         passed = true;
893         WebDriverUtils.jGrowl(getDriver(), "Success " + getClass().getSimpleName(), true, "Passed");
894     }
895 
896     protected WebElement waitAndType(By by, String text, String message) throws InterruptedException {
897         try {
898             jiraAwareWaitFor(by, message);
899             return type(by, text);
900         } catch (Throwable t) {
901             checkForIncidentReport(by.toString(), message);
902             JiraAwareFailureUtils.failOnMatchedJira(by.toString(), message, this);
903             jiraAwareFail(t.getMessage()
904                     + " "
905                     + by.toString()
906                     + "  unable to type text '"
907                     + text
908                     + "'  "
909                     + message
910                     + " current url "
911                     + getDriver().getCurrentUrl()
912                     + "\n"
913                     + AutomatedFunctionalTestUtils.deLinespace(getDriver().getPageSource()));
914         }
915         return null;
916     }
917 }