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   * <ul>
32   *     <li>{@see JiraAwareWebDriverUtils}</li>
33   *     <li>{@see JiraAwareFailable}</li>
34   *     <li>{@see JiraAwareFailure}</li>
35   * </ul>
36   * TODO: promote the various jiraAware methods from WebDriverLegacyITBase
37   * </p>
38   *
39   * @author Kuali Rice Team (rice.collab@kuali.org)
40   */
41  public abstract class JiraAwareAftBase extends AutomatedFunctionalTestBase implements JiraAwareFailable {
42  
43      /**
44       * Test state, used for Saucelabs REST API call to set test state via @{see SauceLabsWebDriverHelper#tearDown}.
45       */
46      private boolean passed = false;
47  
48      /**
49       * Implement to check for Incident Report or other on screen errors, should call {@see JiraAwareFailable#fail} to fail,
50       * without calling any of the jiraAwareFail methods to avoid an infinite loop.
51       *
52       * @param locator used in failure message if there is an incident report can be blank
53       * @param message used in failure message if there is an incident report can be blank
54       */
55      protected abstract void checkForIncidentReport(String locator, String message);
56  
57      /**
58       * WebDriver used in fail and pass to display jGrowl messages.
59       *
60       * @return WebDriver used to display jGrowl messages on fail and pass
61       */
62      protected abstract WebDriver getDriver();
63  
64      /**
65       * {@see WebDriverUtils#assertButtonDisabledByText}
66       *
67       * @param buttonText of button to assert is disabled
68       */
69      protected void assertButtonDisabledByText(String buttonText) {
70          JiraAwareWebDriverUtils.assertButtonDisabledByText(getDriver(), buttonText, this);
71      }
72  
73      /**
74       * {@see WebDriverUtils.assertButtonEnabledByText}.
75       *
76       * @param buttonText of button to assert is disabled
77       */
78      protected void assertButtonEnabledByText(String buttonText) {
79          JiraAwareWebDriverUtils.assertButtonEnabledByText(getDriver(), buttonText, this);
80      }
81  
82      protected void assertDataTableContains(String[][] data) throws InterruptedException {
83          boolean dataPresent = true;
84          String missingMessage = "";
85          String dataTableRow;
86          for (int i = 0, s = data.length; i < s; i++) {
87              dataTableRow = findDataTableRow(data[i][0]).getText();
88              for (int j = 1, t = data[i].length; j < t; j++) {
89                  if (!dataTableRow.contains(data[i][j])) {
90                      dataPresent = false;
91                      missingMessage += data[i][j] + " not present in data table row containing " + data[i][0] + ". ";
92                  }
93              }
94              WebDriverUtils.jGrowl(getDriver(), "Assert DataTable Row", false, "Assert datatable row '" + dataTableRow
95                      + "' contains '" + data[i] + "' " + dataPresent);
96          }
97          if (!dataPresent) {
98              jiraAwareFail(missingMessage);
99          }
100     }
101 
102     protected void assertDataTableContains(String[][] data, String tableClass) throws InterruptedException {
103         boolean dataPresent = true;
104         String missingMessage = "";
105         String dataTableRow;
106         for (int i = 0, s = data.length; i < s; i++) {
107             dataTableRow = findDataTableRow(data[i][0], tableClass).getText();
108             for (int j = 1, t = data[i].length; j < t; j++) {
109                 if (!dataTableRow.contains(data[i][j])) {
110                     dataPresent = false;
111                     missingMessage += data[i][j] + " not present in data table row containing " + data[i][0] + ". ";
112                 }
113             }
114         }
115         if (!dataPresent) {
116             jiraAwareFail(missingMessage);
117         }
118     }
119 
120     protected void assertElementPresentByName(String name) {
121         assertElementPresentByName(name, this.getClass().toString());
122     }
123 
124     protected void assertElementPresentByName(String name, String message) {
125         try {
126             findElement(By.name(name));
127         } catch (Throwable t) {
128             jiraAwareFail(name + " not present " + message);
129         }
130     }
131 
132     protected void assertElementPresentByXpath(String locator) {
133         assertElementPresentByXpath(locator, this.getClass().toString());
134     }
135 
136     protected void assertElementPresent(By by) {
137         assertElementPresent(by, this.getClass().toString());
138     }
139 
140     protected void assertElementPresent(By by, String message) {
141         try {
142             findElement(by);
143         } catch (Throwable t) {
144             jiraAwareFail(by, message, t);
145         }
146     }
147 
148     protected void assertElementPresentByXpath(String locator, String message) {
149         try {
150             findElement(By.xpath(locator));
151         } catch (Throwable t) {
152             jiraAwareFail(By.xpath(locator), message, t);
153         }
154     }
155 
156     protected void assertElementPresentByLinkText(String linkText) {
157         try {
158             findElement(By.linkText(linkText));
159         } catch (Throwable t) {
160             jiraAwareFail(By.cssSelector(linkText), this.getClass().toString(), t);
161         }
162 
163     }
164 
165     protected void assertElementPresent(String locator) {
166         try {
167             findElement(By.cssSelector(locator));
168         } catch (Throwable t) {
169             jiraAwareFail(By.cssSelector(locator), this.getClass().toString(), t);
170         }
171     }
172 
173     protected void assertEquals(boolean expected, boolean actual) {
174         if (expected != actual) {
175             jiraAwareFail("Expected \"" + expected + "\" but saw \"" + actual + "\" instead");
176         }
177     }
178 
179     protected void assertEquals(int expected, int actual) {
180         if (expected != actual) {
181             jiraAwareFail("Expected \"" + expected + "\" but saw \"" + actual + "\" instead");
182         }
183     }
184 
185     protected void assertEquals(String message, int expected, int actual) {
186         if (expected != actual) {
187             jiraAwareFail("Expected \"" + expected + "\" but saw \"" + actual + "\" instead " + message);
188         }
189     }
190 
191 
192     protected void assertEquals(String expected, String actual) {
193         if (!expected.equals(actual)) {
194             jiraAwareFail("Expected \"" + expected + "\" but saw \"" + actual + "\" instead in " + getClass().toString());
195         }
196     }
197 
198     /**
199      * If booleanToAssertFalse is true call {@see jiraAwareFail}.
200      *
201      * @param booleanToAssertFalse
202      */
203     protected void assertFalse(boolean booleanToAssertFalse) {
204         JiraAwareWebDriverUtils.assertFalse(booleanToAssertFalse, this);
205     }
206 
207     /**
208      * If booleanToAssertFalse is true call {@see jiraAwareFail}.
209      *
210      * @param message to include if booleanToAssertTrue is true
211      * @param booleanToAssertFalse
212      */
213     protected void assertFalse(String message, boolean booleanToAssertFalse) {
214         JiraAwareWebDriverUtils.assertFalse(message, booleanToAssertFalse, this);
215     }
216 
217     protected void assertIsVisible(String locator) {
218         if (!isVisible(locator)) {
219             jiraAwareFail(locator + " is not visible and should be");
220         }
221     }
222 
223     protected void assertIsVisible(By by, String message) {
224         if (!isVisible(by)) {
225             jiraAwareFail(by + " not visible " + message);
226         }
227     }
228 
229     protected void assertIsVisibleById(String id) {
230         if (!isVisibleById(id)) {
231             jiraAwareFail(id + " is not visible and should be");
232         }
233     }
234 
235     protected void assertIsVisibleByXpath(String xpath, String message) {
236         if (!isVisibleByXpath(xpath)) {
237             jiraAwareFail(xpath + " not visible " + message);
238         }
239     }
240 
241     protected void assertIsNotVisible(By by) {
242         assertIsNotVisible(by, this.getClass().toString());
243     }
244 
245     protected void assertIsNotVisible(By by, String message) {
246         if (isVisible(by)) {
247             jiraAwareFail(by + " is visible and should not be " + message);
248         }
249     }
250 
251     protected void assertIsNotVisible(String locator) {
252         if (isVisible(locator)) {
253             jiraAwareFail(locator + " is visible and should not be");
254         }
255     }
256 
257     protected void assertIsNotVisibleByXpath(String xpath) {
258         if (isVisible(By.xpath(xpath))) {
259             jiraAwareFail(xpath + " is visible and should not be");
260         }
261     }
262 
263     protected void assertIsNotVisibleByXpath(String xpath, String message) {
264         if (isVisibleByXpath(xpath)) {
265             jiraAwareFail(xpath + " visible and should not be " + message);
266         }
267     }
268 
269     protected void assertLabeledTextNotPresent(String[][] labeledText) {
270         boolean allLabeledTextNotPresent = true;
271         String missingMessage = "";
272         for (int i = 0, s = labeledText.length; i < s; i++) {
273             if (isLabeledTextPresent(labeledText[i][0], labeledText[i][1])) {
274                 allLabeledTextNotPresent = false;
275                 missingMessage += "Text: " + labeledText[i][1] + " labeled by: " + labeledText[i][0] + " present. ";
276             }
277         }
278         if (!allLabeledTextNotPresent) {
279             jiraAwareFail(missingMessage);
280         }
281     }
282 
283     protected void assertLabeledTextPresent(String[][] labeledText) {
284         boolean allLabeledTextPresent = true;
285         String missingMessage = "";
286         for (int i = 0, s = labeledText.length; i < s; i++) {
287             if (!isLabeledTextPresent(labeledText[i][0], labeledText[i][1])) {
288                 allLabeledTextPresent = false;
289                 missingMessage += "Text: " + labeledText[i][1] + " labeled by: " + labeledText[i][0] + " not present. ";
290             }
291         }
292         if (!allLabeledTextPresent) {
293             jiraAwareFail(missingMessage);
294         }
295     }
296 
297     protected void assertLabeledTextPresent(String label, String text) {
298         if (!isLabeledTextPresent(label, text)) {
299             jiraAwareFail("Text: " + text + " labeled by: " + label + " not present");
300         }
301     }
302 
303     protected void assertResultCount(String count) throws InterruptedException {
304         jiraAwareWaitFor(By.cssSelector("div.dataTables_info"), "result count for " + this.getClass().toString());
305         assertTextPresent("of " + count + " entries", "div.dataTables_info", this.getClass().toString());
306     }
307 
308     /**
309      * <b>WARNING:</b> this only does a check against the page source.  The form url can have random character that match
310      * simple text.  A narrowly scoped locator for {@see #assertTextPresent(String String String)}
311      *
312      * @param text
313      */
314     protected void assertTextPresent(String text) {
315         assertTextPresent(text, this.getClass().toString());
316     }
317 
318     /**
319      * <b>WARNING:</b> this only does a check against the page source.  The form url can have random character that match simple text
320      * @param text
321      */
322     protected void assertTextPresent(String text, String message) {
323         WebDriverUtils.jGrowl(getDriver(), "Assert Text Present", false, "Assert text '" + text + "' is present.");
324         String pageSource = getDriver().getPageSource();
325         if (!pageSource.contains(text)) {
326             jiraAwareFail(text + " not present " + message);
327         }
328         WebDriverUtils.highlightElement(getDriver(), By.xpath("//*[contains(text(), '" + text + "')]"));
329     }
330 
331     /**
332      * @param text
333      */
334     protected void assertTextPresent(String text, String cssSelector, String message){
335         WebElement element = findElement(By.cssSelector(cssSelector));
336         if (!element.getText().contains(text)){
337             jiraAwareFail(text + " for " + cssSelector + " not present " + message);
338         }
339     }
340 
341     /**
342      * Asset that the given text does not occur in the page
343      * Warning, this only does a check against the page source.  The form url can have random character that match simple text
344      * @param text the text to search for
345      */
346     protected void assertTextNotPresent(String text) {
347         assertTextNotPresent(text, this.getClass().toString());
348     }
349 
350     /**
351      * Assert that the given text does not occur in the page, and add an additional message to the failure
352      * @param text the text to search for
353      * @param message the message to add to the failure
354      */
355     protected void assertTextNotPresent(String text, String message) {
356         String contents = getDriver().getPageSource();
357         if (contents.contains(text)) {
358             jiraAwareFail(text + " is present and should not be " + message);
359         }
360     }
361 
362     /**
363      * @param text
364      */
365     protected void assertTextNotPresent(String text, String cssSelector, String message){
366         WebElement element = findElement(By.cssSelector(cssSelector));
367         if (element.getText().contains(text)){
368             jiraAwareFail(text + " for " + cssSelector + " is present and shouldn't be " + message);
369         }
370     }
371 
372     /**
373      * If booleanToAssertTrue is false call {@see jiraAwareFail}.
374      *
375      * @param booleanToAssertTrue
376      */
377     protected void assertTrue(boolean booleanToAssertTrue) {
378         JiraAwareWebDriverUtils.assertTrue(getClass().toString(), booleanToAssertTrue, this);
379     }
380 
381     /**
382      * If booleanToAssertTrue is false call {@see jiraAwareFail}.
383      *
384      * @param message to include if booleanToAssertTrue is false
385      * @param booleanToAssertTrue
386      */
387     protected void assertTrue(String message, boolean booleanToAssertTrue) {
388         JiraAwareWebDriverUtils.assertTrue(message, booleanToAssertTrue, this);
389     }
390 
391     /**
392      * {@inheritDoc}
393      * <p>
394      * Set passed to false, call jGrowl sticky with the given message, then fails using  {@see JiraAwareFailable#fail}.
395      * </p>
396      * @param message to display with failure
397      */
398     @Override
399     public void fail(String message) {
400         passed = false;
401         WebDriverUtils.jGrowl(getDriver(), "Failure " + getClass().getSimpleName(), true, message);
402         Assert.fail(message); // The final fail that JiraAwareFailure calls, do not change this to a JiraAwareFailure.
403     }
404 
405     protected WebElement findDataTableRow(String keyText) throws InterruptedException {
406         return findDataTableRow(keyText, "dataTable");
407     }
408 
409     protected WebElement findDataTableRow(String keyText, String className) throws InterruptedException {
410         jiraAwareWaitFor(By.className(className));
411         WebElement element = findElement(By.className(className));
412         return findElement(By.xpath("./*/tr//*[contains(text(), '" + keyText + "')]/ancestor::tr"), element);
413     }
414 
415     /**
416      * {@see WebDriverUtils#findElement}.
417      *
418      * @param by to find element with
419      * @return WebElement found with given by
420      */
421     protected WebElement findElement(By by) {
422         try {
423             return WebDriverUtils.findElement(getDriver(), by);
424         } catch (Throwable t) {
425             jiraAwareFail(by.toString(), t.getMessage(), t);
426         }
427         return null; // required by compiler, never reached
428     }
429 
430     protected WebElement findElement(By by, WebElement elementToFindOn) {
431         try {
432             WebElement found = elementToFindOn.findElement(by);
433             WebDriverUtils.highlightElement(getDriver(), found);
434             return found;
435         } catch (Throwable t) {
436             jiraAwareFail(by.toString(), t.getMessage() + " " + this.getClass().toString(), t);
437         }
438         return null; // required by compiler, never reached
439     }
440 
441     protected boolean isLabeledTextPresent(String label, String text) {
442         WebElement element = findElement(By.xpath("//tr/th/label[contains(text(), '" + label + "')]/ancestor::tr/td"));
443         String labeledText = element.getText().trim();
444         WebDriverUtils.jGrowl(getDriver(), "Is Labeled Text Present", false, "Is text '" + text + "' present for label '" + label + "'? " + labeledText.contains(text));
445         return labeledText.contains(text);
446     }
447 
448     protected boolean isVisible(String locator) {
449         return isVisible(By.cssSelector(locator));
450     }
451 
452     protected boolean isVisible(By by) {
453         List<WebElement> elements = getDriver().findElements(by);
454         for (WebElement element: elements) {
455             if (element.isDisplayed()) {
456                 return true;
457             }
458         }
459         return false;
460     }
461 
462     protected boolean isVisibleById(String id) {
463         return isVisible(By.id(id));
464     }
465 
466     protected boolean isVisibleByXpath(String locator) {
467         return isVisible(By.xpath(locator));
468     }
469 
470     /**
471      * {@inheritDoc}
472      * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
473      *
474      * @param message to check for a Jira match and fail with.
475      */
476     @Override
477     public void jiraAwareFail(String message) {
478         jiraAwareFail("", message, null, this);
479     }
480 
481     /**
482      * {@inheritDoc}
483      * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
484      *
485      * @param contents to check for a Jira match
486      * @param message to check for a Jira match and fail with.
487      */
488     @Override
489     public void jiraAwareFail(String contents, String message) {
490         jiraAwareFail(contents, message, null, this);
491     }
492 
493     /**
494      * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
495      *
496      * @param by to check for a Jira match
497      * @param message to check for a Jira match and fail with.
498      * @param throwable to check for a Jira match
499      */
500     protected void jiraAwareFail(By by, String message, Throwable throwable) {
501         jiraAwareFail(by.toString(), message, throwable, this);
502     }
503 
504     /**
505      * {@inheritDoc}
506      * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
507      *
508      * @param contents to check for a Jira match
509      * @param message to check for a Jira match and fail with.
510      * @param throwable to check for a Jira match
511      */
512     @Override
513     public void jiraAwareFail(String contents, String message, Throwable throwable) {
514         jiraAwareFail(contents, message, throwable, this);
515     }
516 
517     /**
518      * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
519      *
520      * @param contents to check for a Jira match
521      * @param message to check for a Jira match and fail with.
522      * @param throwable to check for a Jira match
523      * @param failable to call fail on
524      */
525     protected void jiraAwareFail(String contents, String message, Throwable throwable, JiraAwareFailable failable) {
526         if (!contents.startsWith("\nIncident report") && !message.startsWith("\nIncident report")) {
527             String errorMessage = AutomatedFunctionalTestUtils.incidentReportMessage(getDriver().getPageSource(), "", message);
528             if (errorMessage != null) {
529                 JiraAwareFailureUtils.failOnMatchedJira(errorMessage, message, failable);
530                 JiraAwareFailureUtils.fail(errorMessage, message, throwable, failable);
531             }
532         }
533         JiraAwareFailureUtils.fail(contents, message, throwable, failable);
534     }
535 
536     /**
537      * {@see #checkForIncidentReport} and {@see JiraAwareFailureUtils#fail}.
538      *
539      * @param by to click on
540      * @param message on failure
541      * @throws InterruptedException
542      */
543     protected void jiraAwareWaitAndClick(By by, String message) throws InterruptedException {
544         jiraAwareWaitAndClick(by, message, this);
545     }
546 
547     protected WebElement jiraAwareType(By by, String text) {
548         return jiraAwareType(by, text, this.getClass().toString().replace("class ", ""));
549     }
550 
551     protected WebElement jiraAwareType(By by, String text, String failureMessage) {
552         try {
553             return type(by, text);
554         } catch (Throwable t) {
555             JiraAwareFailureUtils.failOnMatchedJira(by.toString(), failureMessage, this);
556             jiraAwareFail(t.getMessage()
557                     + " "
558                     + by.toString()
559                     + "  unable to type text '"
560                     + text
561                     + "'  "
562                     + failureMessage
563                     + " current url "
564                     + getDriver().getCurrentUrl()
565                     + "\n"
566                     + AutomatedFunctionalTestUtils.deLinespace(getDriver().getPageSource()));
567         }
568         return null;
569     }
570 
571     protected WebElement jiraAwareTypeByName(String name, String text) {
572         return jiraAwareType(By.name(name), text, this.getClass().toString().replace("class ", ""));
573     }
574 
575     protected WebElement jiraAwareTypeByName(String name, String text, String failureMessage) {
576         return jiraAwareType(By.name(name), text, failureMessage);
577     }
578 
579     /**
580      * {@see #jiraAwareWaitFor}
581      *
582      * @param by to click on
583      * @param message on failure
584      * @param failable to fail on if not found
585      * @throws InterruptedException
586      */
587     protected void jiraAwareWaitAndClick(By by, String message, JiraAwareFailable failable) throws InterruptedException {
588         try {
589             jiraAwareWaitFor(by, message, failable);
590             WebElement element = findElement(by);
591             // possible future code of outputting clicked components in a more generic way, but need to look into duplicates, don't delete
592 //            String jgrowl = element.getAttribute("name");
593 //            if (jgrowl == null || "".equals(jgrowl)) {
594 //                jgrowl = element.getAttribute("id");
595 //            }
596 //            if (jgrowl == null || "".equals(jgrowl)) {
597 //                jgrowl = by.toString();
598 //            }
599 //            WebDriverUtils.jGrowl(getDriver(), "Click " + jgrowl, false, "Click " + jgrowl);
600             element.click();
601         } catch (Throwable t) {
602             failable.jiraAwareFail(by.toString(), message, t);
603         }
604     }
605 
606     /**
607      * {@see WebDriverUtils#waitFor}.
608      *
609      * @param by to find
610      * @return WebElement found with given by
611      * @throws InterruptedException
612      */
613     protected WebElement jiraAwareWaitFor(By by) throws InterruptedException {
614         return jiraAwareWaitFor(by, this.getClass().toString());
615     }
616 
617     /**
618      * {@see WebDriverUtils#waitFor}.
619      *
620      * @param by to find
621      * @param message on failure
622      * @return WebElement found with given by
623      * @throws InterruptedException
624      */
625     protected WebElement jiraAwareWaitFor(By by, String message) throws InterruptedException {
626         try {
627             return WebDriverUtils.waitFor(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
628         } catch (Throwable t) {
629             jiraAwareFail(by, message + " " + this.getClass().toString(), t);
630         }
631         return null; // required, but the jiraAwareFail will will end test before this statement is reached
632     }
633 
634     /**
635      * {@see WebDriverUtils#waitFor}.
636      *
637      * @param by to find
638      * @param message on failure
639      * @throws InterruptedException
640      */
641     protected void jiraAwareWaitFors(By by, String message) throws InterruptedException {
642         try {
643             WebDriverUtils.waitFors(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
644         } catch (Throwable t) {
645             jiraAwareFail(by, message, t);
646         }
647     }
648 
649     /**
650      * {@see WebDriverUtils#waitFor}.
651      *
652      * @param by to find
653      * @param message on failure
654      * @param failable to fail if given by is not found
655      * @throws InterruptedException
656      */
657     protected void jiraAwareWaitFor(By by, String message, JiraAwareFailable failable) throws InterruptedException {
658         try {
659             WebDriverUtils.waitFor(getDriver(), WebDriverUtils.configuredImplicityWait(), by, message);
660         } catch (Throwable t) {
661             jiraAwareFail(by.toString(), message, t, failable);
662         }
663     }
664 
665     /**
666      * {@see WebDriverUtils#waitFor}.
667      *
668      * @param by to find
669      * @param seconds to wait
670      * @param message on failure
671      * @return WebElement found with given by
672      * @throws InterruptedException
673      */
674     protected WebElement jiraAwareWaitFor(By by, int seconds, String message) throws InterruptedException {
675         try {
676             return WebDriverUtils.waitFor(getDriver(), seconds, by, message);
677         } catch (Throwable t) {
678             jiraAwareFail(by, message, t);
679         }
680         return null; // required, but the jiraAwareFail will will end test before this statement is reached
681     }
682 
683     /**
684      * @return passed
685      */
686     public boolean isPassed() {
687         return passed;
688     }
689 
690     protected void selectOptionByName(String name, String optionValue) throws InterruptedException {
691         selectOption(By.name(name), optionValue);
692     }
693 
694     protected void selectOptionByXpath(String locator, String optionValue) throws InterruptedException {
695         selectOption(By.name(locator), optionValue);
696     }
697 
698     /**
699      * Uses Selenium's findElements method which does not throw a test exception if not found.
700      * @param by
701      * @param optionValue
702      * @throws InterruptedException
703      */
704     protected void selectOption(By by, String optionValue) throws InterruptedException {
705         WebElement select1 = findElement(by);
706         List<WebElement> options = select1.findElements(By.tagName("option"));
707 
708         String name = select1.getAttribute("name");
709 
710         if (options == null || options.size() == 0) {
711             jiraAwareFail("No options for select "
712                     + select1.toString()
713                     + " was looking for value "
714                     + optionValue
715                     + " using "
716                     + by.toString());
717         }
718 
719         for (WebElement option : options) {
720             if (option.getAttribute("value").equals(optionValue)) {
721                 WebDriverUtils.jGrowl(getDriver(), "Select " + option.getText(), false, "Select " + option.getText() + " from " + name);
722                 option.click();
723                 break;
724             }
725         }
726     }
727 
728     private WebElement type(By by, String text) {
729         WebElement element = findElement(by);
730         String name = element.getAttribute("name");
731         WebDriverUtils.jGrowl(getDriver(), "Type", false, "Type into " + name + " the text: " + text);
732         WebDriverUtils.highlightElement(getDriver(), element);
733         element.sendKeys(text);
734         return element;
735     }
736 
737     private WebElement typeByName(String name, String text) {
738         return type(By.name(name), text);
739     }
740 
741     /**
742      * <p>
743      * Set the test state to passed, call jGrowl sticky with success, required to be called at the conclusion of a test
744      * for the saucelabs state of a test to be updated to passed.
745      * </p>
746      */
747     protected void passed() {
748         passed = true;
749         WebDriverUtils.jGrowl(getDriver(), "Success " + getClass().getSimpleName(), true, "Passed");
750     }
751 
752     protected WebElement waitAndType(By by, String text, String message) throws InterruptedException {
753         try {
754             jiraAwareWaitFor(by, message);
755             return type(by, text);
756         } catch (Throwable t) {
757             JiraAwareFailureUtils.failOnMatchedJira(by.toString(), message, this);
758             jiraAwareFail(t.getMessage()
759                     + " "
760                     + by.toString()
761                     + "  unable to type text '"
762                     + text
763                     + "'  "
764                     + message
765                     + " current url "
766                     + getDriver().getCurrentUrl()
767                     + "\n"
768                     + AutomatedFunctionalTestUtils.deLinespace(getDriver().getPageSource()));
769         }
770         return null;
771     }
772 }