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