f3187336af38f3583abf4f98fa9b192ae32717bd
[tapestry-5.git] / tapestry-test / src / main / java / org / apache / tapestry5 / test / SeleniumTestCase.java
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12
13 package org.apache.tapestry5.test;
14
15 import com.thoughtworks.selenium.CommandProcessor;
16 import com.thoughtworks.selenium.HttpCommandProcessor;
17 import com.thoughtworks.selenium.Selenium;
18 import com.thoughtworks.selenium.webdriven.WebDriverBackedSelenium;
19 import com.thoughtworks.selenium.webdriven.WebDriverCommandProcessor;
20
21 import io.github.bonigarcia.wdm.FirefoxDriverManager;
22
23 import org.openqa.selenium.By;
24 import org.openqa.selenium.JavascriptExecutor;
25 import org.openqa.selenium.WebDriver;
26 import org.openqa.selenium.WebElement;
27 import org.openqa.selenium.firefox.FirefoxDriver;
28 import org.openqa.selenium.firefox.FirefoxOptions;
29 import org.openqa.selenium.firefox.FirefoxProfile;
30 import org.openqa.selenium.interactions.Actions;
31 import org.openqa.selenium.internal.WrapsDriver;
32 import org.openqa.selenium.remote.DesiredCapabilities;
33 import org.openqa.selenium.support.ui.ExpectedCondition;
34 import org.openqa.selenium.support.ui.ExpectedConditions;
35 import org.openqa.selenium.support.ui.WebDriverWait;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38 import org.testng.Assert;
39 import org.testng.ITestContext;
40 import org.testng.annotations.*;
41 import org.testng.xml.XmlTest;
42
43 import java.io.File;
44 import java.lang.reflect.Method;
45 import java.util.concurrent.TimeUnit;
46
47 /**
48 * Base class for creating Selenium-based integration test cases. This class implements all the
49 * methods of {@link Selenium} and delegates to an instance (setup once per test by
50 * {@link #testStartup(org.testng.ITestContext, org.testng.xml.XmlTest)}.
51 *
52 * @since 5.2.0
53 */
54 public abstract class SeleniumTestCase extends Assert implements Selenium
55 {
56 public final static Logger LOGGER = LoggerFactory.getLogger(SeleniumTestCase.class);
57
58 /**
59 * 15 seconds
60 */
61 public static final String PAGE_LOAD_TIMEOUT = "15000";
62
63 public static final String TOMCAT_6 = "tomcat6";
64
65 public static final String JETTY_7 = "jetty7";
66
67 /**
68 * An XPath expression for locating a submit element (very commonly used
69 * with {@link #clickAndWait(String)}.
70 *
71 * @since 5.3
72 */
73 public static final String SUBMIT = "//input[@type='submit']";
74
75 /**
76 * The underlying {@link Selenium} instance that all the methods of this class delegate to;
77 * this can be useful when attempting to use SeleniumTestCase with a newer version of Selenium which
78 * has added some methods to the interface. This field will not be set until the test case instance
79 * has gone through its full initialization.
80 *
81 * @since 5.3
82 */
83 @Deprecated
84 protected Selenium selenium;
85
86 protected WebDriver webDriver;
87
88 private String baseURL;
89
90 private ErrorReporter errorReporter;
91
92 private ITestContext testContext;
93
94 /**
95 * Starts up the servers for the entire test (i.e., for multiple TestCases). By placing <parameter> elements
96 * inside the appropriate <test> (of your testng.xml configuration
97 * file), you can change the configuration or behavior of the servers. It is common to have two
98 * or more identical tests that differ only in terms of the <code>tapestry.browser-start-command</code> parameter,
99 * to run tests against multiple browsers.
100 * <table>
101 * <tr>
102 * <th>Parameter</th>
103 * <th>Name</th>
104 * <th>Default</th>
105 * <th>Description</th>
106 * </tr>
107 * <tr>
108 * <td>container</td>
109 * <td>tapestry.servlet-container</td>
110 * <td>JETTY_7</td>
111 * <td>The Servlet container to use for the tests. Currently {@link #JETTY_7} or {@link #TOMCAT_6}</td>
112 * </tr>
113 * <tr>
114 * <td>webAppFolder</td>
115 * <td>tapestry.web-app-folder</td>
116 * <td>src/main/webapp</td>
117 * <td>Location of web application context</td>
118 * </tr>
119 * <tr>
120 * <td>contextPath</td>
121 * <td>tapestry.context-path</td>
122 * <td><em>empty string</em></td>
123 * <td>Context path (defaults to root). As elsewhere, the context path should be blank, or start with a slash (but
124 * not end with one).</td>
125 * </tr>
126 * <tr>
127 * <td>port</td>
128 * <td>tapestry.port</td>
129 * <td>9090</td>
130 * <td>Port number for web server to listen to</td>
131 * </tr>
132 * <tr>
133 * <td>sslPort</td>
134 * <td>tapestry.ssl-port</td>
135 * <td>8443</td>
136 * <td>Port number for web server to listen to for secure requests</td>
137 * </tr>
138 * <tr>
139 * <td>browserStartCommand</td>
140 * <td>tapestry.browser-start-command</td>
141 * <td>*firefox</td>
142 * <td>Command string used to launch the browser, as defined by Selenium</td>
143 * </tr>
144 * <caption>Options and defaults</caption>
145 * </table>
146 *
147 * Tests in the <em>beforeStartup</em> group will be run before the start of Selenium. This can be used to
148 * programmatically override the above parameter values.
149 *
150 * This method will be invoked in <em>each</em> subclass, but is set up to only startup the servers once (it checks
151 * the {@link ITestContext} to see if the necessary keys are already present).
152 *
153 * @param testContext
154 * Used to share objects between the launcher and the test suites
155 * @throws Exception
156 */
157 @BeforeTest(dependsOnGroups =
158 {"beforeStartup"})
159 public void testStartup(final ITestContext testContext, XmlTest xmlTest) throws Exception
160 {
161 // This is not actually necessary, because TestNG will only invoke this method once
162 // even when multiple test cases within the test extend from SeleniumTestCase. TestNG
163 // just invokes it on the "first" TestCase instance it has test methods for.
164
165 if (testContext.getAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE) != null)
166 {
167 return;
168 }
169
170 // If a parameter is overridden in another test method, TestNG won't pass the
171 // updated value via a parameter, but still passes the original (coming from testng.xml or the default).
172 // Seems like a TestNG bug.
173
174 // Map<String, String> testParameters = xmlTest.getParameters();
175
176 TapestryTestConfiguration annotation = this.getClass().getAnnotation(TapestryTestConfiguration.class);
177 if (annotation == null)
178 {
179 @TapestryTestConfiguration
180 final class EmptyInnerClass
181 {
182 }
183
184 annotation = EmptyInnerClass.class.getAnnotation(TapestryTestConfiguration.class);
185 }
186
187 String webAppFolder = getParameter(xmlTest, TapestryTestConstants.WEB_APP_FOLDER_PARAMETER,
188 annotation.webAppFolder());
189 String container = getParameter(xmlTest, TapestryTestConstants.SERVLET_CONTAINER_PARAMETER,
190 annotation.container());
191 String contextPath = getParameter(xmlTest, TapestryTestConstants.CONTEXT_PATH_PARAMETER,
192 annotation.contextPath());
193 int port = getIntParameter(xmlTest, TapestryTestConstants.PORT_PARAMETER, annotation.port());
194 int sslPort = getIntParameter(xmlTest, TapestryTestConstants.SSL_PORT_PARAMETER, annotation.sslPort());
195 String browserStartCommand = getParameter(xmlTest, TapestryTestConstants.BROWSER_START_COMMAND_PARAMETER,
196 annotation.browserStartCommand());
197
198 String baseURL = String.format("http://localhost:%d%s/", port, contextPath);
199
200 String sep = System.getProperty("line.separator");
201
202 LOGGER.info("Starting SeleniumTestCase:" + sep +
203 " currentDir: " + System.getProperty("user.dir") + sep +
204 " webAppFolder: " + webAppFolder + sep +
205 " container: " + container + sep +
206 " contextPath: " + contextPath + sep +
207 String.format(" ports: %d / %d", port, sslPort) + sep +
208 " browserStart: " + browserStartCommand + sep +
209 " baseURL: " + baseURL);
210
211 final Runnable stopWebServer = launchWebServer(container, webAppFolder, contextPath, port, sslPort);
212
213 // FirefoxDriverManager.getInstance().setup();
214
215 File ffProfileTemplate = new File(TapestryRunnerConstants.MODULE_BASE_DIR, "src/test/conf/ff_profile_template");
216 DesiredCapabilities desiredCapabilities = DesiredCapabilities.firefox();
217 desiredCapabilities.setCapability(FirefoxDriver.MARIONETTE, false);
218
219 FirefoxOptions options = new FirefoxOptions(desiredCapabilities);
220
221 if (ffProfileTemplate.isDirectory())
222 {
223 FirefoxProfile profile = new FirefoxProfile(ffProfileTemplate);
224 options.setProfile(profile);
225 }
226
227 FirefoxDriver driver = new FirefoxDriver(options);
228 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
229
230 CommandProcessor webDriverCommandProcessor = new WebDriverCommandProcessor(baseURL, driver);
231
232
233 final ErrorReporterImpl errorReporter = new ErrorReporterImpl(driver, testContext);
234
235 ErrorReportingCommandProcessor commandProcessor = new ErrorReportingCommandProcessor(webDriverCommandProcessor,
236 errorReporter);
237
238 Selenium selenium = new WebDriverBackedSelenium(driver, baseURL);
239
240 testContext.setAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE, baseURL);
241 testContext.setAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE, selenium);
242 testContext.setAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE, errorReporter);
243 testContext.setAttribute(TapestryTestConstants.COMMAND_PROCESSOR_ATTRIBUTE, commandProcessor);
244
245 testContext.setAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE, new Runnable()
246 {
247 @Override
248 public void run()
249 {
250 try
251 {
252 LOGGER.info("Shutting down selenium client ...");
253
254 try
255 {
256 selenium.stop();
257 } catch (RuntimeException e)
258 {
259 LOGGER.error("Selenium client shutdown failure.", e);
260 }
261
262 LOGGER.info("Shutting down webdriver ...");
263
264 try
265 {
266 webDriver.quit();
267 } catch (RuntimeException e)
268 {
269 LOGGER.error("Webdriver shutdown failure.", e);
270 }
271
272 LOGGER.info("Shutting down selenium server ...");
273
274 LOGGER.info("Shutting web server ...");
275
276 try
277 {
278 stopWebServer.run();
279 } catch (RuntimeException e)
280 {
281 LOGGER.error("Web server shutdown failure.", e);
282 }
283
284 // Output, at the end of the Test, any html capture or screen shots (this makes it much easier
285 // to locate them at the end of the run; there's such a variance on where they end up based
286 // on whether the tests are running from inside an IDE or via one of the command line
287 // builds.
288
289 errorReporter.writeOutputPaths();
290 } finally
291 {
292 testContext.removeAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE);
293 testContext.removeAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE);
294 testContext.removeAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE);
295 testContext.removeAttribute(TapestryTestConstants.COMMAND_PROCESSOR_ATTRIBUTE);
296 testContext.removeAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE);
297 }
298 }
299 });
300 }
301
302 private final String getParameter(XmlTest xmlTest, String key, String defaultValue)
303 {
304 String value = xmlTest.getParameter(key);
305
306 return value != null ? value : defaultValue;
307 }
308
309 private final int getIntParameter(XmlTest xmlTest, String key, int defaultValue)
310 {
311 String value = xmlTest.getParameter(key);
312
313 return value != null ? Integer.parseInt(value) : defaultValue;
314 }
315
316 /**
317 * Like {@link #testStartup(org.testng.ITestContext, org.testng.xml.XmlTest)} , this may
318 * be called multiple times against multiple instances, but only does work the first time.
319 */
320 @AfterTest
321 public void testShutdown(ITestContext context)
322 {
323 // Likewise, this method should only be invoked once.
324 Runnable r = (Runnable) context.getAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE);
325
326 // This test is still useful, however, because testStartup() may not have completed properly,
327 // and the runnable is the last thing it puts into the test context.
328
329 if (r != null)
330 {
331 LOGGER.info("Shutting down integration test support ...");
332 r.run();
333 }
334 }
335
336 /**
337 * Invoked from {@link #testStartup(org.testng.ITestContext, org.testng.xml.XmlTest)} to launch the web
338 * server to be tested. The return value is a Runnable that can be invoked later to cleanly shut down the launched
339 * server at the end of the test.
340 *
341 * @param container
342 * identifies which web server should be launched
343 * @param webAppFolder
344 * path to the web application context
345 * @param contextPath
346 * the path the context is mapped to, usually the empty string
347 * @param port
348 * the port number the server should handle
349 * @param sslPort
350 * the port number on which the server should handle secure requests
351 * @return Runnable used to shut down the server
352 * @throws Exception
353 */
354 protected Runnable launchWebServer(String container, String webAppFolder, String contextPath, int port, int sslPort)
355 throws Exception
356 {
357 final ServletContainerRunner runner = createWebServer(container, webAppFolder, contextPath, port, sslPort);
358
359 return new Runnable()
360 {
361 @Override
362 public void run()
363 {
364 runner.stop();
365 }
366 };
367 }
368
369 private ServletContainerRunner createWebServer(String container, String webAppFolder, String contextPath, int port, int sslPort) throws Exception
370 {
371 if (TOMCAT_6.equals(container))
372 {
373 return new TomcatRunner(webAppFolder, contextPath, port, sslPort);
374 }
375
376 if (JETTY_7.equals(container))
377 {
378 return new JettyRunner(webAppFolder, contextPath, port, sslPort);
379 }
380
381 throw new RuntimeException("Unknown servlet container: " + container);
382 }
383
384 @BeforeClass
385 public void setup(ITestContext context)
386 {
387 this.testContext = context;
388
389 selenium = (Selenium) context.getAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE);
390 webDriver = ((WrapsDriver) selenium).getWrappedDriver();
391 baseURL = (String) context.getAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE);
392 errorReporter = (ErrorReporter) context.getAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE);
393 }
394
395 @AfterClass
396 public void cleanup()
397 {
398 selenium = null;
399 baseURL = null;
400 errorReporter = null;
401 testContext = null;
402 }
403
404 /**
405 * Delegates to {@link ErrorReporter#writeErrorReport(String)} to capture the current page markup in a
406 * file for later analysis.
407 */
408 protected void writeErrorReport(String reportText)
409 {
410 errorReporter.writeErrorReport(reportText);
411 }
412
413 /**
414 * Returns the base URL for the application. This is of the typically <code>http://localhost:9999/</code> (i.e., it
415 * includes a trailing slash).
416 *
417 * Generally, you should use {@link #openLinks(String...)} to start from your application's home page.
418 */
419 public String getBaseURL()
420 {
421 return baseURL;
422 }
423
424 @BeforeMethod
425 public void indicateTestMethodName(Method testMethod)
426 {
427 LOGGER.info("Executing " + testMethod);
428
429 testContext.setAttribute(TapestryTestConstants.CURRENT_TEST_METHOD_ATTRIBUTE, testMethod);
430
431 String className = testMethod.getDeclaringClass().getSimpleName();
432 String testName = testMethod.getName().replace("_", " ");
433
434 selenium.setContext(className + ": " + testName);
435 }
436
437 @AfterMethod
438 public void cleanupTestMethod()
439 {
440 testContext.setAttribute(TapestryTestConstants.CURRENT_TEST_METHOD_ATTRIBUTE, null);
441 }
442
443 // ---------------------------------------------------------------------
444 // Start of delegate methods
445 //
446 // When upgrading to a new version of Selenium, it is probably easiest
447 // to delete all these methods and use the Generate Delegate Methods
448 // refactoring.
449 // ---------------------------------------------------------------------
450
451 @Override
452 public void addCustomRequestHeader(String key, String value)
453 {
454 selenium.addCustomRequestHeader(key, value);
455 }
456
457 @Override
458 public void addLocationStrategy(String strategyName, String functionDefinition)
459 {
460 selenium.addLocationStrategy(strategyName, functionDefinition);
461 }
462
463 @Override
464 public void addScript(String scriptContent, String scriptTagId)
465 {
466 selenium.addScript(scriptContent, scriptTagId);
467 }
468
469 @Override
470 public void addSelection(String locator, String optionLocator)
471 {
472 selenium.addSelection(locator, optionLocator);
473 }
474
475 @Override
476 public void allowNativeXpath(String allow)
477 {
478 selenium.allowNativeXpath(allow);
479 }
480
481 @Override
482 public void altKeyDown()
483 {
484 selenium.altKeyDown();
485 }
486
487 @Override
488 public void altKeyUp()
489 {
490 selenium.altKeyUp();
491 }
492
493 @Override
494 public void answerOnNextPrompt(String answer)
495 {
496 selenium.answerOnNextPrompt(answer);
497 }
498
499 @Override
500 public void assignId(String locator, String identifier)
501 {
502 selenium.assignId(locator, identifier);
503 }
504
505 @Override
506 public void attachFile(String fieldLocator, String fileLocator)
507 {
508 selenium.attachFile(fieldLocator, fileLocator);
509 }
510
511 @Override
512 public void captureEntirePageScreenshot(String filename, String kwargs)
513 {
514 selenium.captureEntirePageScreenshot(filename, kwargs);
515 }
516
517 @Override
518 public String captureEntirePageScreenshotToString(String kwargs)
519 {
520 return selenium.captureEntirePageScreenshotToString(kwargs);
521 }
522
523 @Override
524 public String captureNetworkTraffic(String type)
525 {
526 return selenium.captureNetworkTraffic(type);
527 }
528
529 @Override
530 public void captureScreenshot(String filename)
531 {
532 selenium.captureScreenshot(filename);
533 }
534
535 @Override
536 public String captureScreenshotToString()
537 {
538 return selenium.captureScreenshotToString();
539 }
540
541 @Override
542 public void check(String locator)
543 {
544 WebElement element = webDriver.findElement(convertLocator(locator));
545 if (!element.isSelected())
546 {
547 ((JavascriptExecutor) webDriver).executeScript("arguments[0].scrollIntoView(true);", element);
548 element.click();
549 }
550 }
551
552 @Override
553 public void chooseCancelOnNextConfirmation()
554 {
555 selenium.chooseCancelOnNextConfirmation();
556 }
557
558 @Override
559 public void chooseOkOnNextConfirmation()
560 {
561 selenium.chooseOkOnNextConfirmation();
562 }
563
564 @Override
565 public void click(String locator)
566 {
567 WebElement element = webDriver.findElement(convertLocator(locator));
568 ((JavascriptExecutor) webDriver).executeScript("arguments[0].scrollIntoView(true);", element);
569 element.click();
570 }
571
572 @Override
573 public void clickAt(String locator, String coordString)
574 {
575 selenium.clickAt(locator, coordString);
576 }
577
578 @Override
579 public void close()
580 {
581 selenium.close();
582 }
583
584 @Override
585 public void contextMenu(String locator)
586 {
587 selenium.contextMenu(locator);
588 }
589
590 @Override
591 public void contextMenuAt(String locator, String coordString)
592 {
593 selenium.contextMenuAt(locator, coordString);
594 }
595
596 @Override
597 public void controlKeyDown()
598 {
599 selenium.controlKeyDown();
600 }
601
602 @Override
603 public void controlKeyUp()
604 {
605 selenium.controlKeyUp();
606 }
607
608 @Override
609 public void createCookie(String nameValuePair, String optionsString)
610 {
611 selenium.createCookie(nameValuePair, optionsString);
612 }
613
614 @Override
615 public void deleteAllVisibleCookies()
616 {
617 selenium.deleteAllVisibleCookies();
618 }
619
620 @Override
621 public void deleteCookie(String name, String optionsString)
622 {
623 selenium.deleteCookie(name, optionsString);
624 }
625
626 @Override
627 public void deselectPopUp()
628 {
629 selenium.deselectPopUp();
630 }
631
632 @Override
633 public void doubleClick(String locator)
634 {
635 selenium.doubleClick(locator);
636 }
637
638 @Override
639 public void doubleClickAt(String locator, String coordString)
640 {
641 selenium.doubleClickAt(locator, coordString);
642 }
643
644 @Override
645 public void dragAndDrop(String locator, String movementsString)
646 {
647 selenium.dragAndDrop(locator, movementsString);
648 }
649
650 @Override
651 public void dragAndDropToObject(String locatorOfObjectToBeDragged, String locatorOfDragDestinationObject)
652 {
653 selenium.dragAndDropToObject(locatorOfObjectToBeDragged, locatorOfDragDestinationObject);
654 }
655
656 @Override
657 public void dragdrop(String locator, String movementsString)
658 {
659 selenium.dragdrop(locator, movementsString);
660 }
661
662 @Override
663 public void fireEvent(String locator, String eventName)
664 {
665 selenium.fireEvent(locator, eventName);
666 }
667
668 @Override
669 public void focus(String locator)
670 {
671 selenium.focus(locator);
672 }
673
674 @Override
675 public String getAlert()
676 {
677 return selenium.getAlert();
678 }
679
680 @Override
681 public String[] getAllButtons()
682 {
683 return selenium.getAllButtons();
684 }
685
686 @Override
687 public String[] getAllFields()
688 {
689 return selenium.getAllFields();
690 }
691
692 @Override
693 public String[] getAllLinks()
694 {
695 return selenium.getAllLinks();
696 }
697
698 @Override
699 public String[] getAllWindowIds()
700 {
701 return selenium.getAllWindowIds();
702 }
703
704 @Override
705 public String[] getAllWindowNames()
706 {
707 return selenium.getAllWindowNames();
708 }
709
710 @Override
711 public String[] getAllWindowTitles()
712 {
713 return selenium.getAllWindowTitles();
714 }
715
716 @Override
717 public String getAttribute(String attributeLocator)
718 {
719 return selenium.getAttribute(attributeLocator);
720 }
721
722 @Override
723 public String[] getAttributeFromAllWindows(String attributeName)
724 {
725 return selenium.getAttributeFromAllWindows(attributeName);
726 }
727
728 @Override
729 public String getBodyText()
730 {
731 return selenium.getBodyText();
732 }
733
734 @Override
735 public String getConfirmation()
736 {
737 return selenium.getConfirmation();
738 }
739
740 @Override
741 public String getCookie()
742 {
743 return selenium.getCookie();
744 }
745
746 @Override
747 public String getCookieByName(String name)
748 {
749 return selenium.getCookieByName(name);
750 }
751
752 @Override
753 public Number getCursorPosition(String locator)
754 {
755 return selenium.getCursorPosition(locator);
756 }
757
758 @Override
759 public Number getElementHeight(String locator)
760 {
761 return selenium.getElementHeight(locator);
762 }
763
764 @Override
765 public Number getElementIndex(String locator)
766 {
767 return selenium.getElementIndex(locator);
768 }
769
770 @Override
771 public Number getElementPositionLeft(String locator)
772 {
773 return selenium.getElementPositionLeft(locator);
774 }
775
776 @Override
777 public Number getElementPositionTop(String locator)
778 {
779 return selenium.getElementPositionTop(locator);
780 }
781
782 @Override
783 public Number getElementWidth(String locator)
784 {
785 return selenium.getElementWidth(locator);
786 }
787
788 @Override
789 public String getEval(String script)
790 {
791 return selenium.getEval(script);
792 }
793
794 @Override
795 public String getExpression(String expression)
796 {
797 return selenium.getExpression(expression);
798 }
799
800 @Override
801 public String getHtmlSource()
802 {
803 return selenium.getHtmlSource();
804 }
805
806 @Override
807 public String getLocation()
808 {
809 return selenium.getLocation();
810 }
811
812 @Override
813 public String getLog()
814 {
815 return selenium.getLog();
816 }
817
818 @Override
819 public Number getMouseSpeed()
820 {
821 return selenium.getMouseSpeed();
822 }
823
824 @Override
825 public String getPrompt()
826 {
827 return selenium.getPrompt();
828 }
829
830 @Override
831 public String getSelectedId(String selectLocator)
832 {
833 return selenium.getSelectedId(selectLocator);
834 }
835
836 @Override
837 public String[] getSelectedIds(String selectLocator)
838 {
839 return selenium.getSelectedIds(selectLocator);
840 }
841
842 @Override
843 public String getSelectedIndex(String selectLocator)
844 {
845 return selenium.getSelectedIndex(selectLocator);
846 }
847
848 @Override
849 public String[] getSelectedIndexes(String selectLocator)
850 {
851 return selenium.getSelectedIndexes(selectLocator);
852 }
853
854 @Override
855 public String getSelectedLabel(String selectLocator)
856 {
857 return selenium.getSelectedLabel(selectLocator);
858 }
859
860 @Override
861 public String[] getSelectedLabels(String selectLocator)
862 {
863 return selenium.getSelectedLabels(selectLocator);
864 }
865
866 @Override
867 public String getSelectedValue(String selectLocator)
868 {
869 return selenium.getSelectedValue(selectLocator);
870 }
871
872 @Override
873 public String[] getSelectedValues(String selectLocator)
874 {
875 return selenium.getSelectedValues(selectLocator);
876 }
877
878 @Override
879 public String[] getSelectOptions(String selectLocator)
880 {
881 return selenium.getSelectOptions(selectLocator);
882 }
883
884 @Override
885 public String getSpeed()
886 {
887 return selenium.getSpeed();
888 }
889
890 @Override
891 public String getTable(String tableCellAddress)
892 {
893 return selenium.getTable(tableCellAddress);
894 }
895
896 @Override
897 public String getText(String locator)
898 {
899 return selenium.getText(locator);
900 }
901
902 @Override
903 public String getTitle()
904 {
905 return selenium.getTitle();
906 }
907
908 @Override
909 public String getValue(String locator)
910 {
911 return selenium.getValue(locator);
912 }
913
914 @Override
915 public boolean getWhetherThisFrameMatchFrameExpression(String currentFrameString, String target)
916 {
917 return selenium.getWhetherThisFrameMatchFrameExpression(currentFrameString, target);
918 }
919
920 @Override
921 public boolean getWhetherThisWindowMatchWindowExpression(String currentWindowString, String target)
922 {
923 return selenium.getWhetherThisWindowMatchWindowExpression(currentWindowString, target);
924 }
925
926 @Override
927 public Number getXpathCount(String xpath)
928 {
929 return selenium.getXpathCount(xpath);
930 }
931
932 @Override
933 public void goBack()
934 {
935 selenium.goBack();
936 }
937
938 @Override
939 public void highlight(String locator)
940 {
941 selenium.highlight(locator);
942 }
943
944 @Override
945 public void ignoreAttributesWithoutValue(String ignore)
946 {
947 selenium.ignoreAttributesWithoutValue(ignore);
948 }
949
950 @Override
951 public boolean isAlertPresent()
952 {
953 return selenium.isAlertPresent();
954 }
955
956 @Override
957 public boolean isChecked(String locator)
958 {
959 return selenium.isChecked(locator);
960 }
961
962 @Override
963 public boolean isConfirmationPresent()
964 {
965 return selenium.isConfirmationPresent();
966 }
967
968 @Override
969 public boolean isCookiePresent(String name)
970 {
971 return selenium.isCookiePresent(name);
972 }
973
974 @Override
975 public boolean isEditable(String locator)
976 {
977 return selenium.isEditable(locator);
978 }
979
980 @Override
981 public boolean isElementPresent(String locator)
982 {
983 return selenium.isElementPresent(locator);
984 }
985
986 @Override
987 public boolean isOrdered(String locator1, String locator2)
988 {
989 return selenium.isOrdered(locator1, locator2);
990 }
991
992 @Override
993 public boolean isPromptPresent()
994 {
995 return selenium.isPromptPresent();
996 }
997
998 @Override
999 public boolean isSomethingSelected(String selectLocator)
1000 {
1001 return selenium.isSomethingSelected(selectLocator);
1002 }
1003
1004 @Override
1005 public boolean isTextPresent(String pattern)
1006 {
1007 return selenium.isTextPresent(pattern);
1008 }
1009
1010 @Override
1011 public boolean isVisible(String locator)
1012 {
1013 return selenium.isVisible(locator);
1014 }
1015
1016 @Override
1017 public void keyDown(String locator, String keySequence)
1018 {
1019 selenium.keyDown(locator, keySequence);
1020 }
1021
1022 @Override
1023 public void keyDownNative(String keycode)
1024 {
1025 selenium.keyDownNative(keycode);
1026 }
1027
1028 @Override
1029 public void keyPress(String locator, String keySequence)
1030 {
1031 selenium.keyPress(locator, keySequence);
1032 }
1033
1034 @Override
1035 public void keyPressNative(String keycode)
1036 {
1037 selenium.keyPressNative(keycode);
1038 }
1039
1040 @Override
1041 public void keyUp(String locator, String keySequence)
1042 {
1043 selenium.keyUp(locator, keySequence);
1044 }
1045
1046 @Override
1047 public void keyUpNative(String keycode)
1048 {
1049 selenium.keyUpNative(keycode);
1050 }
1051
1052 @Override
1053 public void metaKeyDown()
1054 {
1055 selenium.metaKeyDown();
1056 }
1057
1058 @Override
1059 public void metaKeyUp()
1060 {
1061 selenium.metaKeyUp();
1062 }
1063
1064 @Override
1065 public void mouseDown(String locator)
1066 {
1067 selenium.mouseDown(locator);
1068 }
1069
1070 @Override
1071 public void mouseDownAt(String locator, String coordString)
1072 {
1073 selenium.mouseDownAt(locator, coordString);
1074 }
1075
1076 @Override
1077 public void mouseDownRight(String locator)
1078 {
1079 selenium.mouseDownRight(locator);
1080 }
1081
1082 @Override
1083 public void mouseDownRightAt(String locator, String coordString)
1084 {
1085 selenium.mouseDownRightAt(locator, coordString);
1086 }
1087
1088 @Override
1089 public void mouseMove(String locator)
1090 {
1091 selenium.mouseMove(locator);
1092 }
1093
1094 @Override
1095 public void mouseMoveAt(String locator, String coordString)
1096 {
1097 selenium.mouseMoveAt(locator, coordString);
1098 }
1099
1100 @Override
1101 public void mouseOut(String locator)
1102 {
1103 selenium.mouseOut(locator);
1104 }
1105
1106 @Override
1107 public void mouseOver(String locator)
1108 {
1109 selenium.mouseOver(locator);
1110 }
1111
1112 @Override
1113 public void mouseUp(String locator)
1114 {
1115 selenium.mouseUp(locator);
1116 }
1117
1118 @Override
1119 public void mouseUpAt(String locator, String coordString)
1120 {
1121 selenium.mouseUpAt(locator, coordString);
1122 }
1123
1124 @Override
1125 public void mouseUpRight(String locator)
1126 {
1127 selenium.mouseUpRight(locator);
1128 }
1129
1130 @Override
1131 public void mouseUpRightAt(String locator, String coordString)
1132 {
1133 selenium.mouseUpRightAt(locator, coordString);
1134 }
1135
1136 @Override
1137 public void open(String url)
1138 {
1139 selenium.open(url);
1140 }
1141
1142 @Override
1143 public void open(String url, String ignoreResponseCode)
1144 {
1145 selenium.open(url, ignoreResponseCode);
1146 }
1147
1148 @Override
1149 public void openWindow(String url, String windowID)
1150 {
1151 selenium.openWindow(url, windowID);
1152 }
1153
1154 @Override
1155 public void refresh()
1156 {
1157 selenium.refresh();
1158 }
1159
1160 @Override
1161 public void removeAllSelections(String locator)
1162 {
1163 selenium.removeAllSelections(locator);
1164 }
1165
1166 @Override
1167 public void removeScript(String scriptTagId)
1168 {
1169 selenium.removeScript(scriptTagId);
1170 }
1171
1172 @Override
1173 public void removeSelection(String locator, String optionLocator)
1174 {
1175 selenium.removeSelection(locator, optionLocator);
1176 }
1177
1178 @Override
1179 public String retrieveLastRemoteControlLogs()
1180 {
1181 return selenium.retrieveLastRemoteControlLogs();
1182 }
1183
1184 @Override
1185 public void rollup(String rollupName, String kwargs)
1186 {
1187 selenium.rollup(rollupName, kwargs);
1188 }
1189
1190 @Override
1191 public void runScript(String script)
1192 {
1193 selenium.runScript(script);
1194 }
1195
1196 @Override
1197 public void select(String selectLocator, String optionLocator)
1198 {
1199 selenium.select(selectLocator, optionLocator);
1200 }
1201
1202 @Override
1203 public void selectFrame(String locator)
1204 {
1205 selenium.selectFrame(locator);
1206 }
1207
1208 @Override
1209 public void selectPopUp(String windowID)
1210 {
1211 selenium.selectPopUp(windowID);
1212 }
1213
1214 @Override
1215 public void selectWindow(String windowID)
1216 {
1217 selenium.selectWindow(windowID);
1218 }
1219
1220 @Override
1221 public void setBrowserLogLevel(String logLevel)
1222 {
1223 selenium.setBrowserLogLevel(logLevel);
1224 }
1225
1226 @Override
1227 public void setContext(String context)
1228 {
1229 selenium.setContext(context);
1230 }
1231
1232 @Override
1233 public void setCursorPosition(String locator, String position)
1234 {
1235 selenium.setCursorPosition(locator, position);
1236 }
1237
1238 @Override
1239 public void setExtensionJs(String extensionJs)
1240 {
1241 selenium.setExtensionJs(extensionJs);
1242 }
1243
1244 @Override
1245 public void setMouseSpeed(String pixels)
1246 {
1247 selenium.setMouseSpeed(pixels);
1248 }
1249
1250 @Override
1251 public void setSpeed(String value)
1252 {
1253 selenium.setSpeed(value);
1254 }
1255
1256 @Override
1257 public void setTimeout(String timeout)
1258 {
1259 selenium.setTimeout(timeout);
1260 }
1261
1262 @Override
1263 public void shiftKeyDown()
1264 {
1265 selenium.shiftKeyDown();
1266 }
1267
1268 @Override
1269 public void shiftKeyUp()
1270 {
1271 selenium.shiftKeyUp();
1272 }
1273
1274 @Override
1275 public void showContextualBanner()
1276 {
1277 selenium.showContextualBanner();
1278 }
1279
1280 @Override
1281 public void showContextualBanner(String className, String methodName)
1282 {
1283 selenium.showContextualBanner(className, methodName);
1284 }
1285
1286 @Override
1287 public void shutDownSeleniumServer()
1288 {
1289 selenium.shutDownSeleniumServer();
1290 }
1291
1292 @Override
1293 public void start()
1294 {
1295 selenium.start();
1296 }
1297
1298 @Override
1299 public void start(Object optionsObject)
1300 {
1301 selenium.start(optionsObject);
1302 }
1303
1304 @Override
1305 public void start(String optionsString)
1306 {
1307 selenium.start(optionsString);
1308 }
1309
1310 @Override
1311 public void stop()
1312 {
1313 selenium.stop();
1314 }
1315
1316 @Override
1317 public void submit(String formLocator)
1318 {
1319 selenium.submit(formLocator);
1320 }
1321
1322 @Override
1323 public void type(String locator, String value)
1324 {
1325 WebElement element = webDriver.findElement(convertLocator(locator));
1326 ((JavascriptExecutor) webDriver).executeScript("arguments[0].value = arguments[1];", element, value);
1327 }
1328
1329 @Override
1330 public void typeKeys(String locator, String value)
1331 {
1332 WebElement element = webDriver.findElement(convertLocator(locator));
1333 element.sendKeys(value);
1334 }
1335
1336 @Override
1337 public void uncheck(String locator)
1338 {
1339 selenium.uncheck(locator);
1340 }
1341
1342 @Override
1343 public void useXpathLibrary(String libraryName)
1344 {
1345 selenium.useXpathLibrary(libraryName);
1346 }
1347
1348 @Override
1349 public void waitForCondition(String script, String timeout)
1350 {
1351 selenium.waitForCondition(script, timeout);
1352 }
1353
1354 protected void waitForCondition(ExpectedCondition condition)
1355 {
1356 WebDriverWait wait = new WebDriverWait(webDriver, 10);
1357 wait.until(condition);
1358 }
1359
1360 @Override
1361 public void waitForFrameToLoad(String frameAddress, String timeout)
1362 {
1363 selenium.waitForFrameToLoad(frameAddress, timeout);
1364 }
1365
1366 /**
1367 * Waits for page to load, then waits for initialization to finish, which is recognized by the {@code data-page-initialized} attribute
1368 * being set to true on the body element. Polls at increasing intervals, for up-to 30 seconds (that's extraordinarily long, but helps sometimes
1369 * when manually debugging a page that doesn't have the floating console enabled)..
1370 */
1371 @Override
1372 public void waitForPageToLoad(String timeout)
1373 {
1374 selenium.waitForPageToLoad(timeout);
1375
1376 // In a limited number of cases, a "page" is an container error page or raw HTML content
1377 // that does not include the body element and data-page-initialized element. In those cases,
1378 // there will never be page initialization in the Tapestry sense and we return immediately.
1379
1380 if (!isElementPresent("css=body[data-page-initialized]"))
1381 {
1382 return;
1383 }
1384
1385 final long pollingStartTime = System.currentTimeMillis();
1386
1387 long sleepTime = 20;
1388
1389 while (true)
1390 {
1391 if (isElementPresent("css=body[data-page-initialized='true']"))
1392 {
1393 return;
1394 }
1395
1396 if ((System.currentTimeMillis() - pollingStartTime) > 30000)
1397 {
1398 reportAndThrowAssertionError("Page did not finish initializing after 30 seconds.");
1399 }
1400
1401 sleep(sleepTime);
1402
1403 sleepTime *= 2;
1404 }
1405 }
1406
1407 @Override
1408 public void waitForPopUp(String windowID, String timeout)
1409 {
1410 selenium.waitForPopUp(windowID, timeout);
1411 }
1412
1413 @Override
1414 public void windowFocus()
1415 {
1416 selenium.windowFocus();
1417 }
1418
1419 @Override
1420 public void windowMaximize()
1421 {
1422 selenium.windowMaximize();
1423 }
1424
1425 // ---------------------------------------------------------------------
1426 // End of delegate methods
1427 // ---------------------------------------------------------------------
1428
1429 /**
1430 * Formats a message from the provided arguments, which is written to System.err. In addition,
1431 * captures the AUT's markup, screenshot, and a report to the output directory.
1432 *
1433 * @param message
1434 * @param arguments
1435 * @since 5.4
1436 */
1437 protected final void reportAndThrowAssertionError(String message, Object... arguments)
1438 {
1439 StringBuilder builder = new StringBuilder(5000);
1440
1441 String formatted = String.format(message, arguments);
1442
1443 builder.append(formatted);
1444
1445 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
1446
1447 StringBuilder buffer = new StringBuilder(5000);
1448
1449 boolean enabled = false;
1450
1451 for (StackTraceElement e : stackTrace)
1452 {
1453 if (enabled)
1454 {
1455 buffer.append("\n- ");
1456 buffer.append(e);
1457 continue;
1458 }
1459
1460 if (e.getMethodName().equals("reportAndThrowAssertionError"))
1461 {
1462 enabled = true;
1463 }
1464 }
1465
1466 writeErrorReport(builder.toString());
1467
1468 throw new AssertionError(formatted);
1469 }
1470
1471 protected final void unreachable()
1472 {
1473 reportAndThrowAssertionError("An unreachable statement was reached.");
1474 }
1475
1476 /**
1477 * Open the {@linkplain #getBaseURL()}, and waits for the page to load.
1478 */
1479 protected final void openBaseURL()
1480 {
1481 open(baseURL);
1482
1483 waitForPageToLoad();
1484 }
1485
1486 /**
1487 * Asserts the text of an element, identified by the locator.
1488 *
1489 * @param locator
1490 * identifies the element whose text value is to be asserted
1491 * @param expected
1492 * expected value for the element's text
1493 */
1494 protected final void assertText(String locator, String expected)
1495 {
1496 String actual = null;
1497
1498 try
1499 {
1500 actual = getText(locator);
1501 } catch (RuntimeException ex)
1502 {
1503 System.err.printf("Error accessing %s: %s, in:\n\n%s\n\n", locator, ex.getMessage(), getHtmlSource());
1504
1505 throw ex;
1506 }
1507
1508 if (actual.equals(expected))
1509 {
1510 return;
1511 }
1512
1513 reportAndThrowAssertionError("%s was '%s' not '%s'", locator, actual, expected);
1514 }
1515
1516 protected final void assertTextPresent(String... text)
1517 {
1518 for (String item : text)
1519 {
1520 if (isTextPresent(item))
1521 {
1522 continue;
1523 }
1524
1525 reportAndThrowAssertionError("Page did not contain '" + item + "'.");
1526 }
1527 }
1528
1529 /**
1530 * Assets that each string provided is present somewhere in the current document.
1531 *
1532 * @param expected
1533 * string expected to be present
1534 */
1535 protected final void assertSourcePresent(String... expected)
1536 {
1537 String source = getHtmlSource();
1538
1539 for (String snippet : expected)
1540 {
1541 if (source.contains(snippet))
1542 {
1543 continue;
1544 }
1545
1546 reportAndThrowAssertionError("Page did not contain source '" + snippet + "'.");
1547 }
1548 }
1549
1550 /**
1551 * Click a link identified by a locator, then wait for the resulting page to load.
1552 * This is not useful for Ajax updates, just normal full-page refreshes.
1553 *
1554 * @param locator
1555 * identifies the link to click
1556 */
1557 protected final void clickAndWait(String locator)
1558 {
1559 click(locator);
1560 waitForPageToLoad();
1561 }
1562
1563 /**
1564 * Waits for the page to load (up to 15 seconds). This is invoked after clicking on an element
1565 * that forces a full page refresh.
1566 */
1567 protected final void waitForPageToLoad()
1568 {
1569 waitForPageToLoad(PAGE_LOAD_TIMEOUT);
1570 }
1571
1572 /**
1573 * Used when the locator identifies an attribute, not an element.
1574 *
1575 * @param locator
1576 * identifies the attribute whose value is to be asserted
1577 * @param expected
1578 * expected value for the attribute
1579 */
1580 protected final void assertAttribute(String locator, String expected)
1581 {
1582 String actual = null;
1583
1584 try
1585 {
1586 actual = getAttribute(locator);
1587 } catch (RuntimeException ex)
1588 {
1589
1590 reportAndThrowAssertionError("Error accessing %s: %s", locator, ex.getMessage());
1591 }
1592
1593 if (actual.equals(expected))
1594 {
1595 return;
1596 }
1597
1598 reportAndThrowAssertionError("%s was '%s' not '%s'", locator, actual, expected);
1599 }
1600
1601 /**
1602 * Assets that the value in the field matches the expectation
1603 *
1604 * @param locator
1605 * identifies the field
1606 * @param expected
1607 * expected value for the field
1608 * @since 5.3
1609 */
1610 protected final void assertFieldValue(String locator, String expected)
1611 {
1612 try
1613 {
1614 assertEquals(getValue(locator), expected);
1615 } catch (AssertionError ex)
1616 {
1617 reportAndThrowAssertionError("Failure accessing %s: %s", locator, ex);
1618 }
1619 }
1620
1621 /**
1622 * Opens the base URL, then clicks through a series of links to get to a desired application
1623 * state.
1624 *
1625 * @since 5.3
1626 */
1627 protected final void openLinks(String... linkText)
1628 {
1629 openBaseURL();
1630
1631 for (String text : linkText)
1632 {
1633 clickAndWait("link=" + text);
1634 }
1635 }
1636
1637 /**
1638 * Sleeps for the indicated number of seconds.
1639 *
1640 * @since 5.3
1641 */
1642 protected final void sleep(long millis)
1643 {
1644 try
1645 {
1646 Thread.sleep(millis);
1647 } catch (InterruptedException ex)
1648 {
1649 // Ignore.
1650 }
1651 }
1652
1653 /**
1654 * Waits, up to the page load limit for an element (identified by a CSS rule) to exist
1655 * (it is not assured that the element will be visible).
1656 *
1657 * This implementation only works if the application provides a function onto the
1658 * window object: "testSupport.findCSSMatchCount()" which accepts a CSS rule and returns the number
1659 * of matching elements.
1660 *
1661 * @param cssSelector
1662 * used to locate the element
1663 * @since 5.3
1664 * @deprecated Deprecated in 5.4 with no replacement
1665 */
1666 protected void waitForCSSSelectedElementToAppear(String cssSelector)
1667 {
1668 String condition = String.format("window.testSupport.findCSSMatchCount(\"%s\") > 0", cssSelector);
1669
1670 waitForCondition(condition, PAGE_LOAD_TIMEOUT);
1671 }
1672
1673 /**
1674 * Waits for the element with the given client-side id to be present in the DOM (
1675 * does not assure that the element is visible).
1676 *
1677 * @param elementId
1678 * identifies the element
1679 * @since 5.3
1680 */
1681 protected final void waitForElementToAppear(String elementId)
1682 {
1683
1684 String condition = String.format("selenium.browserbot.getCurrentWindow().document.getElementById(\"%s\")", elementId);
1685
1686 waitForCondition(condition, PAGE_LOAD_TIMEOUT);
1687 }
1688
1689 /**
1690 * Waits for the element to be removed from the DOM.
1691 *
1692 *
1693 * This implementation depends on window being extended with testSupport.isNotVisible().
1694 *
1695 * @param elementId
1696 * client-side id of element
1697 * @since 5.3
1698 * @deprecated Deprecated in 5.4 with no replacement
1699 */
1700 protected final void waitForElementToDisappear(String elementId)
1701 {
1702 String condition = String.format("selenium.browserbot.getCurrentWindow().testSupport.doesNotExist(\"%s\")", elementId);
1703
1704 waitForCondition(condition, PAGE_LOAD_TIMEOUT);
1705 }
1706
1707 /**
1708 * Waits for the element specified by the selector to become visible
1709 * Note that waitForElementToAppear waits for the element to be present in the dom, visible or not. waitForVisible
1710 * waits for an element that already exists in the dom to become visible.
1711 *
1712 * @param selector
1713 * element selector
1714 * @since 5.3
1715 */
1716 protected final void waitForVisible(String selector)
1717 {
1718 waitForCondition(ExpectedConditions.visibilityOfElementLocated(convertLocator(selector)));
1719 }
1720
1721 /**
1722 * Waits for the element specified by the selector to become invisible
1723 * Note that waitForElementToDisappear waits for the element to be absent from the dom, visible or not. waitForInvisible
1724 * waits for an existing element to become invisible.
1725 *
1726 * @param selector
1727 * element selector
1728 * @since 5.3
1729 */
1730 protected final void waitForInvisible(String selector)
1731 {
1732 waitForCondition(ExpectedConditions.invisibilityOfElementLocated(convertLocator(selector)));
1733 }
1734
1735 /**
1736 * Asserts that the current page's title matches the expected value.
1737 *
1738 * @param expected
1739 * value for title
1740 * @since 5.3
1741 */
1742 protected final void assertTitle(String expected)
1743 {
1744 try
1745 {
1746 assertEquals(getTitle(), expected);
1747 } catch (AssertionError ex)
1748 {
1749 reportAndThrowAssertionError("Unexpected title: %s", ex);
1750
1751 throw ex;
1752 }
1753 }
1754
1755 /**
1756 * Waits until all active XHR requests are completed.
1757 *
1758 * @param timeout
1759 * timeout to wait for (no longer used)
1760 * @since 5.3
1761 * @deprecated Deprecated in 5.4 in favor of the version without a timeout
1762 */
1763 protected final void waitForAjaxRequestsToComplete(String timeout)
1764 {
1765 waitForAjaxRequestsToComplete();
1766 }
1767
1768
1769 /**
1770 * Waits until all active XHR requests (as noted by the t5/core/dom module)
1771 * have completed.
1772 *
1773 * @since 5.4
1774 */
1775 protected final void waitForAjaxRequestsToComplete()
1776 {
1777 // Ugly but necessary. Give the Ajax operation sufficient time to execute normally, then start
1778 // polling to see if it has complete.
1779 sleep(250);
1780
1781 // The t5/core/dom module tracks how many Ajax requests are active
1782 // and body[data-ajax-active] as appropriate.
1783
1784 for (int i = 0; i < 10; i++)
1785 {
1786 if (i > 0)
1787 {
1788 sleep(100);
1789 }
1790
1791 if (getCssCount("body[data-ajax-active='0']").equals(1))
1792 {
1793 return;
1794 }
1795 }
1796
1797 reportAndThrowAssertionError("Body 'data-ajax-active' attribute never reverted to '0'.");
1798 }
1799
1800 @Override
1801 public Number getCssCount(String str)
1802 {
1803 return selenium.getCssCount(str);
1804 }
1805
1806 protected static By convertLocator(String locator)
1807 {
1808 By by;
1809 if (locator.startsWith("link="))
1810 {
1811 return By.linkText(locator.substring(5));
1812 }
1813 else if (locator.startsWith("css="))
1814 {
1815 return By.cssSelector(locator.substring(4));
1816 }
1817 else if (locator.startsWith("xpath="))
1818 {
1819 return By.xpath(locator.substring(6));
1820 }
1821 else if (locator.startsWith("id="))
1822 {
1823 return By.id(locator.substring(3));
1824 }
1825 else if (locator.startsWith("//"))
1826 {
1827 return By.xpath(locator);
1828 }
1829 else
1830 {
1831 return By.id(locator);
1832 }
1833 }
1834 }