001 // Copyright 2009, 2010, 2012 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry5.test; 016 017 import java.io.File; 018 import java.lang.reflect.Method; 019 020 import org.openqa.selenium.server.RemoteControlConfiguration; 021 import org.openqa.selenium.server.SeleniumServer; 022 import org.testng.Assert; 023 import org.testng.ITestContext; 024 import org.testng.annotations.AfterClass; 025 import org.testng.annotations.AfterMethod; 026 import org.testng.annotations.AfterTest; 027 import org.testng.annotations.BeforeClass; 028 import org.testng.annotations.BeforeMethod; 029 import org.testng.annotations.BeforeTest; 030 import org.testng.xml.XmlTest; 031 032 import com.thoughtworks.selenium.CommandProcessor; 033 import com.thoughtworks.selenium.DefaultSelenium; 034 import com.thoughtworks.selenium.HttpCommandProcessor; 035 import com.thoughtworks.selenium.Selenium; 036 037 /** 038 * Base class for creating Selenium-based integration test cases. This class implements all the 039 * methods of {@link Selenium} and delegates to an instance (setup once per test by 040 * {@link #testStartup(org.testng.ITestContext, org.testng.xml.XmlTest)}. 041 * 042 * @since 5.2.0 043 */ 044 public abstract class SeleniumTestCase extends Assert implements Selenium 045 { 046 /** 047 * 15 seconds 048 */ 049 public static final String PAGE_LOAD_TIMEOUT = "15000"; 050 051 public static final String TOMCAT_6 = "tomcat6"; 052 053 public static final String JETTY_7 = "jetty7"; 054 055 /** 056 * An XPath expression for locating a submit element (very commonly used 057 * with {@link #clickAndWait(String)}. 058 * 059 * @since 5.3 060 */ 061 public static final String SUBMIT = "//input[@type='submit']"; 062 063 /** 064 * The underlying {@link Selenium} instance that all the methods of this class delegate to; 065 * this can be useful when attempting to use SeleniumTestCase with a newer version of Selenium which 066 * has added some methods to the interface. This field will not be set until the test case instance 067 * has gone through its full initialization. 068 * 069 * @since 5.3 070 */ 071 protected Selenium selenium; 072 073 private String baseURL; 074 075 private ErrorReporter errorReporter; 076 077 private ITestContext testContext; 078 079 /** 080 * Starts up the servers for the entire test (i.e., for multiple TestCases). By placing <parameter> elements 081 * inside the appropriate <test> (of your testng.xml configuration 082 * file), you can change the configuration or behavior of the servers. It is common to have two 083 * or more identical tests that differ only in terms of the <code>tapestry.browser-start-command</code> parameter, 084 * to run tests against multiple browsers. 085 * <table> 086 * <tr> 087 * <th>Parameter</th> 088 * <th>Name</th> 089 * <th>Default</th> 090 * <th>Description</th> 091 * </tr> 092 * <tr> 093 * <td>container</td> 094 * <td>tapestry.servlet-container</td> 095 * <td>JETTY_7</td> 096 * <td>The Servlet container to use for the tests. Currently {@link #JETTY_7} or {@link #TOMCAT_6}</td> 097 * </tr> 098 * <tr> 099 * <td>webAppFolder</td> 100 * <td>tapestry.web-app-folder</td> 101 * <td>src/main/webapp</td> 102 * <td>Location of web application context</td> 103 * </tr> 104 * <tr> 105 * <td>contextPath</td> 106 * <td>tapestry.context-path</td> 107 * <td><em>empty string</em></td> 108 * <td>Context path (defaults to root). As elsewhere, the context path should be blank, or start with a slash (but 109 * not end with one).</td> 110 * </tr> 111 * <tr> 112 * <td>port</td> 113 * <td>tapestry.port</td> 114 * <td>9090</td> 115 * <td>Port number for web server to listen to</td> 116 * </tr> 117 * <tr> 118 * <td>sslPort</td> 119 * <td>tapestry.ssl-port</td> 120 * <td>8443</td> 121 * <td>Port number for web server to listen to for secure requests</td> 122 * </tr> 123 * <tr> 124 * <td>browserStartCommand</td> 125 * <td>tapestry.browser-start-command</td> 126 * <td>*firefox</td> 127 * <td>Command string used to launch the browser, as defined by Selenium</td> 128 * </tr> 129 * </table> 130 * <p/> 131 * Tests in the <em>beforeStartup</em> group will be run before the start of Selenium. This can be used to 132 * programmatically override the above parameter values. 133 * <p/> 134 * This method will be invoked in <em>each</em> subclass, but is set up to only startup the servers once (it checks 135 * the {@link ITestContext} to see if the necessary keys are already present). 136 * 137 * @param testContext 138 * Used to share objects between the launcher and the test suites 139 * @throws Exception 140 */ 141 @BeforeTest(dependsOnGroups = 142 {"beforeStartup"}) 143 public void testStartup(final ITestContext testContext, XmlTest xmlTest) throws Exception 144 { 145 // This is not actually necessary, because TestNG will only invoke this method once 146 // even when multiple test cases within the test extend from SeleniumTestCase. TestNG 147 // just invokes it on the "first" TestCase instance it has test methods for. 148 149 if (testContext.getAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE) != null) 150 { 151 return; 152 } 153 154 // If a parameter is overridden in another test method, TestNG won't pass the 155 // updated value via a parameter, but still passes the original (coming from testng.xml or the default). 156 // Seems like a TestNG bug. 157 158 // Map<String, String> testParameters = xmlTest.getParameters(); 159 160 TapestryTestConfiguration annotation = this.getClass().getAnnotation(TapestryTestConfiguration.class); 161 if (annotation == null) 162 { 163 @TapestryTestConfiguration 164 final class EmptyInnerClass 165 { 166 } 167 168 annotation = EmptyInnerClass.class.getAnnotation(TapestryTestConfiguration.class); 169 } 170 171 String webAppFolder = getParameter(xmlTest, TapestryTestConstants.WEB_APP_FOLDER_PARAMETER, 172 annotation.webAppFolder()); 173 String container = getParameter(xmlTest, TapestryTestConstants.SERVLET_CONTAINER_PARAMETER, 174 annotation.container()); 175 String contextPath = getParameter(xmlTest, TapestryTestConstants.CONTEXT_PATH_PARAMETER, 176 annotation.contextPath()); 177 int port = getIntParameter(xmlTest, TapestryTestConstants.PORT_PARAMETER, annotation.port()); 178 int sslPort = getIntParameter(xmlTest, TapestryTestConstants.SSL_PORT_PARAMETER, annotation.sslPort()); 179 String browserStartCommand = getParameter(xmlTest, TapestryTestConstants.BROWSER_START_COMMAND_PARAMETER, 180 annotation.browserStartCommand()); 181 182 String baseURL = String.format("http://localhost:%d%s/", port, contextPath); 183 184 System.err.println("Starting SeleniumTestCase:"); 185 System.err.println(" currentDir: " + System.getProperty("user.dir")); 186 System.err.println(" webAppFolder: " + webAppFolder); 187 System.err.println(" container: " + container); 188 System.err.println(" contextPath: " + contextPath); 189 System.err.printf(" ports: %d / %d%n", port, sslPort); 190 System.err.println(" browserStart: " + browserStartCommand); 191 System.err.println(" baseURL: " + baseURL); 192 193 final Runnable stopWebServer = launchWebServer(container, webAppFolder, contextPath, port, sslPort); 194 195 final SeleniumServer seleniumServer = new SeleniumServer(); 196 197 File ffProfileTemplate = new File(TapestryTestConstants.MODULE_BASE_DIR, "src/test/conf/ff_profile_template"); 198 199 if (ffProfileTemplate.isDirectory()) 200 { 201 seleniumServer.getConfiguration().setFirefoxProfileTemplate(ffProfileTemplate); 202 } 203 204 seleniumServer.start(); 205 206 207 CommandProcessor httpCommandProcessor = new HttpCommandProcessor("localhost", 208 RemoteControlConfiguration.DEFAULT_PORT, browserStartCommand, baseURL); 209 210 final ErrorReporterImpl errorReporter = new ErrorReporterImpl(httpCommandProcessor, testContext); 211 212 ErrorReportingCommandProcessor commandProcessor = new ErrorReportingCommandProcessor(httpCommandProcessor, 213 errorReporter); 214 215 final Selenium selenium = new DefaultSelenium(commandProcessor); 216 217 selenium.start(); 218 219 testContext.setAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE, baseURL); 220 testContext.setAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE, selenium); 221 testContext.setAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE, errorReporter); 222 testContext.setAttribute(TapestryTestConstants.COMMAND_PROCESSOR_ATTRIBUTE, commandProcessor); 223 224 testContext.setAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE, new Runnable() 225 { 226 public void run() 227 { 228 try 229 { 230 selenium.stop(); 231 seleniumServer.stop(); 232 stopWebServer.run(); 233 234 // Output, at the end of the Test, any html capture or screen shots (this makes it much easier 235 // to locate them at the end of the run; there's such a variance on where they end up based 236 // on whether the tests are running from inside an IDE or via one of the command line 237 // builds. 238 239 errorReporter.writeOutputPaths(); 240 } finally 241 { 242 testContext.removeAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE); 243 testContext.removeAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE); 244 testContext.removeAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE); 245 testContext.removeAttribute(TapestryTestConstants.COMMAND_PROCESSOR_ATTRIBUTE); 246 testContext.removeAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE); 247 } 248 } 249 }); 250 } 251 252 private final String getParameter(XmlTest xmlTest, String key, String defaultValue) 253 { 254 String value = xmlTest.getParameter(key); 255 256 return value != null ? value : defaultValue; 257 } 258 259 private final int getIntParameter(XmlTest xmlTest, String key, int defaultValue) 260 { 261 String value = xmlTest.getParameter(key); 262 263 return value != null ? Integer.parseInt(value) : defaultValue; 264 } 265 266 /** 267 * Like {@link #testStartup(org.testng.ITestContext, org.testng.xml.XmlTest)} , this may 268 * be called multiple times against multiple instances, but only does work the first time. 269 */ 270 @AfterTest 271 public void testShutdown(ITestContext context) 272 { 273 // Likewise, this method should only be invoked once. 274 Runnable r = (Runnable) context.getAttribute(TapestryTestConstants.SHUTDOWN_ATTRIBUTE); 275 276 // This test is still useful, however, because testStartup() may not have completed properly, 277 // and the runnable is the last thing it puts into the test context. 278 279 if (r != null) 280 { 281 r.run(); 282 } 283 } 284 285 /** 286 * Invoked from {@link #testStartup(org.testng.ITestContext, org.testng.xml.XmlTest)} to launch the web 287 * server to be tested. The return value is a Runnable that can be invoked later to cleanly shut down the launched 288 * server at the end of the test. 289 * 290 * @param container 291 * identifies which web server should be launched 292 * @param webAppFolder 293 * path to the web application context 294 * @param contextPath 295 * the path the context is mapped to, usually the empty string 296 * @param port 297 * the port number the server should handle 298 * @param sslPort 299 * the port number on which the server should handle secure requests 300 * @return Runnable used to shut down the server 301 * @throws Exception 302 */ 303 protected Runnable launchWebServer(String container, String webAppFolder, String contextPath, int port, int sslPort) 304 throws Exception 305 { 306 final ServletContainerRunner runner = createWebServer(container, webAppFolder, contextPath, port, sslPort); 307 308 return new Runnable() 309 { 310 public void run() 311 { 312 runner.stop(); 313 } 314 }; 315 } 316 317 private ServletContainerRunner createWebServer(String container, String webAppFolder, String contextPath, int port, int sslPort) throws Exception 318 { 319 if (TOMCAT_6.equals(container)) 320 { 321 return new Tomcat6Runner(webAppFolder, contextPath, port, sslPort); 322 } 323 324 if (JETTY_7.equals(container)) 325 { 326 return new Jetty7Runner(webAppFolder, contextPath, port, sslPort); 327 } 328 329 throw new RuntimeException("Unknown servlet container: " + container); 330 } 331 332 @BeforeClass 333 public void setup(ITestContext context) 334 { 335 this.testContext = context; 336 337 selenium = (Selenium) context.getAttribute(TapestryTestConstants.SELENIUM_ATTRIBUTE); 338 baseURL = (String) context.getAttribute(TapestryTestConstants.BASE_URL_ATTRIBUTE); 339 errorReporter = (ErrorReporter) context.getAttribute(TapestryTestConstants.ERROR_REPORTER_ATTRIBUTE); 340 } 341 342 @AfterClass 343 public void cleanup() 344 { 345 selenium = null; 346 baseURL = null; 347 errorReporter = null; 348 testContext = null; 349 } 350 351 /** 352 * Delegates to {@link ErrorReporter#writeErrorReport(String)} to capture the current page markup in a 353 * file for later analysis. 354 */ 355 protected void writeErrorReport(String reportText) 356 { 357 errorReporter.writeErrorReport(); 358 } 359 360 /** 361 * Returns the base URL for the application. This is of the typically <code>http://localhost:9999/</code> (i.e., it 362 * includes a trailing slash). 363 * <p/> 364 * Generally, you should use {@link #openLinks(String...)} to start from your application's home page. 365 */ 366 public String getBaseURL() 367 { 368 return baseURL; 369 } 370 371 @BeforeMethod 372 public void indicateTestMethodName(Method testMethod) 373 { 374 testContext.setAttribute(TapestryTestConstants.CURRENT_TEST_METHOD_ATTRIBUTE, testMethod); 375 376 String className = testMethod.getDeclaringClass().getSimpleName(); 377 String testName = testMethod.getName().replace("_", " "); 378 379 selenium.setContext(className + ": " + testName); 380 } 381 382 @AfterMethod 383 public void cleanupTestMethod() 384 { 385 testContext.setAttribute(TapestryTestConstants.CURRENT_TEST_METHOD_ATTRIBUTE, null); 386 } 387 388 // --------------------------------------------------------------------- 389 // Start of delegate methods 390 // 391 // When upgrading to a new version of Selenium, it is probably easiest 392 // to delete all these methods and use the Generate Delegate Methods 393 // refactoring. 394 // --------------------------------------------------------------------- 395 396 public void addCustomRequestHeader(String key, String value) 397 { 398 selenium.addCustomRequestHeader(key, value); 399 } 400 401 public void addLocationStrategy(String strategyName, String functionDefinition) 402 { 403 selenium.addLocationStrategy(strategyName, functionDefinition); 404 } 405 406 public void addScript(String scriptContent, String scriptTagId) 407 { 408 selenium.addScript(scriptContent, scriptTagId); 409 } 410 411 public void addSelection(String locator, String optionLocator) 412 { 413 selenium.addSelection(locator, optionLocator); 414 } 415 416 public void allowNativeXpath(String allow) 417 { 418 selenium.allowNativeXpath(allow); 419 } 420 421 public void altKeyDown() 422 { 423 selenium.altKeyDown(); 424 } 425 426 public void altKeyUp() 427 { 428 selenium.altKeyUp(); 429 } 430 431 public void answerOnNextPrompt(String answer) 432 { 433 selenium.answerOnNextPrompt(answer); 434 } 435 436 public void assignId(String locator, String identifier) 437 { 438 selenium.assignId(locator, identifier); 439 } 440 441 public void attachFile(String fieldLocator, String fileLocator) 442 { 443 selenium.attachFile(fieldLocator, fileLocator); 444 } 445 446 public void captureEntirePageScreenshot(String filename, String kwargs) 447 { 448 selenium.captureEntirePageScreenshot(filename, kwargs); 449 } 450 451 public String captureEntirePageScreenshotToString(String kwargs) 452 { 453 return selenium.captureEntirePageScreenshotToString(kwargs); 454 } 455 456 public String captureNetworkTraffic(String type) 457 { 458 return selenium.captureNetworkTraffic(type); 459 } 460 461 public void captureScreenshot(String filename) 462 { 463 selenium.captureScreenshot(filename); 464 } 465 466 public String captureScreenshotToString() 467 { 468 return selenium.captureScreenshotToString(); 469 } 470 471 public void check(String locator) 472 { 473 selenium.check(locator); 474 } 475 476 public void chooseCancelOnNextConfirmation() 477 { 478 selenium.chooseCancelOnNextConfirmation(); 479 } 480 481 public void chooseOkOnNextConfirmation() 482 { 483 selenium.chooseOkOnNextConfirmation(); 484 } 485 486 public void click(String locator) 487 { 488 selenium.click(locator); 489 } 490 491 public void clickAt(String locator, String coordString) 492 { 493 selenium.clickAt(locator, coordString); 494 } 495 496 public void close() 497 { 498 selenium.close(); 499 } 500 501 public void contextMenu(String locator) 502 { 503 selenium.contextMenu(locator); 504 } 505 506 public void contextMenuAt(String locator, String coordString) 507 { 508 selenium.contextMenuAt(locator, coordString); 509 } 510 511 public void controlKeyDown() 512 { 513 selenium.controlKeyDown(); 514 } 515 516 public void controlKeyUp() 517 { 518 selenium.controlKeyUp(); 519 } 520 521 public void createCookie(String nameValuePair, String optionsString) 522 { 523 selenium.createCookie(nameValuePair, optionsString); 524 } 525 526 public void deleteAllVisibleCookies() 527 { 528 selenium.deleteAllVisibleCookies(); 529 } 530 531 public void deleteCookie(String name, String optionsString) 532 { 533 selenium.deleteCookie(name, optionsString); 534 } 535 536 public void deselectPopUp() 537 { 538 selenium.deselectPopUp(); 539 } 540 541 public void doubleClick(String locator) 542 { 543 selenium.doubleClick(locator); 544 } 545 546 public void doubleClickAt(String locator, String coordString) 547 { 548 selenium.doubleClickAt(locator, coordString); 549 } 550 551 public void dragAndDrop(String locator, String movementsString) 552 { 553 selenium.dragAndDrop(locator, movementsString); 554 } 555 556 public void dragAndDropToObject(String locatorOfObjectToBeDragged, String locatorOfDragDestinationObject) 557 { 558 selenium.dragAndDropToObject(locatorOfObjectToBeDragged, locatorOfDragDestinationObject); 559 } 560 561 public void dragdrop(String locator, String movementsString) 562 { 563 selenium.dragdrop(locator, movementsString); 564 } 565 566 public void fireEvent(String locator, String eventName) 567 { 568 selenium.fireEvent(locator, eventName); 569 } 570 571 public void focus(String locator) 572 { 573 selenium.focus(locator); 574 } 575 576 public String getAlert() 577 { 578 return selenium.getAlert(); 579 } 580 581 public String[] getAllButtons() 582 { 583 return selenium.getAllButtons(); 584 } 585 586 public String[] getAllFields() 587 { 588 return selenium.getAllFields(); 589 } 590 591 public String[] getAllLinks() 592 { 593 return selenium.getAllLinks(); 594 } 595 596 public String[] getAllWindowIds() 597 { 598 return selenium.getAllWindowIds(); 599 } 600 601 public String[] getAllWindowNames() 602 { 603 return selenium.getAllWindowNames(); 604 } 605 606 public String[] getAllWindowTitles() 607 { 608 return selenium.getAllWindowTitles(); 609 } 610 611 public String getAttribute(String attributeLocator) 612 { 613 return selenium.getAttribute(attributeLocator); 614 } 615 616 public String[] getAttributeFromAllWindows(String attributeName) 617 { 618 return selenium.getAttributeFromAllWindows(attributeName); 619 } 620 621 public String getBodyText() 622 { 623 return selenium.getBodyText(); 624 } 625 626 public String getConfirmation() 627 { 628 return selenium.getConfirmation(); 629 } 630 631 public String getCookie() 632 { 633 return selenium.getCookie(); 634 } 635 636 public String getCookieByName(String name) 637 { 638 return selenium.getCookieByName(name); 639 } 640 641 public Number getCursorPosition(String locator) 642 { 643 return selenium.getCursorPosition(locator); 644 } 645 646 public Number getElementHeight(String locator) 647 { 648 return selenium.getElementHeight(locator); 649 } 650 651 public Number getElementIndex(String locator) 652 { 653 return selenium.getElementIndex(locator); 654 } 655 656 public Number getElementPositionLeft(String locator) 657 { 658 return selenium.getElementPositionLeft(locator); 659 } 660 661 public Number getElementPositionTop(String locator) 662 { 663 return selenium.getElementPositionTop(locator); 664 } 665 666 public Number getElementWidth(String locator) 667 { 668 return selenium.getElementWidth(locator); 669 } 670 671 public String getEval(String script) 672 { 673 return selenium.getEval(script); 674 } 675 676 public String getExpression(String expression) 677 { 678 return selenium.getExpression(expression); 679 } 680 681 public String getHtmlSource() 682 { 683 return selenium.getHtmlSource(); 684 } 685 686 public String getLocation() 687 { 688 return selenium.getLocation(); 689 } 690 691 public String getLog() 692 { 693 return selenium.getLog(); 694 } 695 696 public Number getMouseSpeed() 697 { 698 return selenium.getMouseSpeed(); 699 } 700 701 public String getPrompt() 702 { 703 return selenium.getPrompt(); 704 } 705 706 public String getSelectedId(String selectLocator) 707 { 708 return selenium.getSelectedId(selectLocator); 709 } 710 711 public String[] getSelectedIds(String selectLocator) 712 { 713 return selenium.getSelectedIds(selectLocator); 714 } 715 716 public String getSelectedIndex(String selectLocator) 717 { 718 return selenium.getSelectedIndex(selectLocator); 719 } 720 721 public String[] getSelectedIndexes(String selectLocator) 722 { 723 return selenium.getSelectedIndexes(selectLocator); 724 } 725 726 public String getSelectedLabel(String selectLocator) 727 { 728 return selenium.getSelectedLabel(selectLocator); 729 } 730 731 public String[] getSelectedLabels(String selectLocator) 732 { 733 return selenium.getSelectedLabels(selectLocator); 734 } 735 736 public String getSelectedValue(String selectLocator) 737 { 738 return selenium.getSelectedValue(selectLocator); 739 } 740 741 public String[] getSelectedValues(String selectLocator) 742 { 743 return selenium.getSelectedValues(selectLocator); 744 } 745 746 public String[] getSelectOptions(String selectLocator) 747 { 748 return selenium.getSelectOptions(selectLocator); 749 } 750 751 public String getSpeed() 752 { 753 return selenium.getSpeed(); 754 } 755 756 public String getTable(String tableCellAddress) 757 { 758 return selenium.getTable(tableCellAddress); 759 } 760 761 public String getText(String locator) 762 { 763 return selenium.getText(locator); 764 } 765 766 public String getTitle() 767 { 768 return selenium.getTitle(); 769 } 770 771 public String getValue(String locator) 772 { 773 return selenium.getValue(locator); 774 } 775 776 public boolean getWhetherThisFrameMatchFrameExpression(String currentFrameString, String target) 777 { 778 return selenium.getWhetherThisFrameMatchFrameExpression(currentFrameString, target); 779 } 780 781 public boolean getWhetherThisWindowMatchWindowExpression(String currentWindowString, String target) 782 { 783 return selenium.getWhetherThisWindowMatchWindowExpression(currentWindowString, target); 784 } 785 786 public Number getXpathCount(String xpath) 787 { 788 return selenium.getXpathCount(xpath); 789 } 790 791 public void goBack() 792 { 793 selenium.goBack(); 794 } 795 796 public void highlight(String locator) 797 { 798 selenium.highlight(locator); 799 } 800 801 public void ignoreAttributesWithoutValue(String ignore) 802 { 803 selenium.ignoreAttributesWithoutValue(ignore); 804 } 805 806 public boolean isAlertPresent() 807 { 808 return selenium.isAlertPresent(); 809 } 810 811 public boolean isChecked(String locator) 812 { 813 return selenium.isChecked(locator); 814 } 815 816 public boolean isConfirmationPresent() 817 { 818 return selenium.isConfirmationPresent(); 819 } 820 821 public boolean isCookiePresent(String name) 822 { 823 return selenium.isCookiePresent(name); 824 } 825 826 public boolean isEditable(String locator) 827 { 828 return selenium.isEditable(locator); 829 } 830 831 public boolean isElementPresent(String locator) 832 { 833 return selenium.isElementPresent(locator); 834 } 835 836 public boolean isOrdered(String locator1, String locator2) 837 { 838 return selenium.isOrdered(locator1, locator2); 839 } 840 841 public boolean isPromptPresent() 842 { 843 return selenium.isPromptPresent(); 844 } 845 846 public boolean isSomethingSelected(String selectLocator) 847 { 848 return selenium.isSomethingSelected(selectLocator); 849 } 850 851 public boolean isTextPresent(String pattern) 852 { 853 return selenium.isTextPresent(pattern); 854 } 855 856 public boolean isVisible(String locator) 857 { 858 return selenium.isVisible(locator); 859 } 860 861 public void keyDown(String locator, String keySequence) 862 { 863 selenium.keyDown(locator, keySequence); 864 } 865 866 public void keyDownNative(String keycode) 867 { 868 selenium.keyDownNative(keycode); 869 } 870 871 public void keyPress(String locator, String keySequence) 872 { 873 selenium.keyPress(locator, keySequence); 874 } 875 876 public void keyPressNative(String keycode) 877 { 878 selenium.keyPressNative(keycode); 879 } 880 881 public void keyUp(String locator, String keySequence) 882 { 883 selenium.keyUp(locator, keySequence); 884 } 885 886 public void keyUpNative(String keycode) 887 { 888 selenium.keyUpNative(keycode); 889 } 890 891 public void metaKeyDown() 892 { 893 selenium.metaKeyDown(); 894 } 895 896 public void metaKeyUp() 897 { 898 selenium.metaKeyUp(); 899 } 900 901 public void mouseDown(String locator) 902 { 903 selenium.mouseDown(locator); 904 } 905 906 public void mouseDownAt(String locator, String coordString) 907 { 908 selenium.mouseDownAt(locator, coordString); 909 } 910 911 public void mouseDownRight(String locator) 912 { 913 selenium.mouseDownRight(locator); 914 } 915 916 public void mouseDownRightAt(String locator, String coordString) 917 { 918 selenium.mouseDownRightAt(locator, coordString); 919 } 920 921 public void mouseMove(String locator) 922 { 923 selenium.mouseMove(locator); 924 } 925 926 public void mouseMoveAt(String locator, String coordString) 927 { 928 selenium.mouseMoveAt(locator, coordString); 929 } 930 931 public void mouseOut(String locator) 932 { 933 selenium.mouseOut(locator); 934 } 935 936 public void mouseOver(String locator) 937 { 938 selenium.mouseOver(locator); 939 } 940 941 public void mouseUp(String locator) 942 { 943 selenium.mouseUp(locator); 944 } 945 946 public void mouseUpAt(String locator, String coordString) 947 { 948 selenium.mouseUpAt(locator, coordString); 949 } 950 951 public void mouseUpRight(String locator) 952 { 953 selenium.mouseUpRight(locator); 954 } 955 956 public void mouseUpRightAt(String locator, String coordString) 957 { 958 selenium.mouseUpRightAt(locator, coordString); 959 } 960 961 public void open(String url) 962 { 963 selenium.open(url); 964 } 965 966 public void open(String url, String ignoreResponseCode) 967 { 968 selenium.open(url, ignoreResponseCode); 969 } 970 971 public void openWindow(String url, String windowID) 972 { 973 selenium.openWindow(url, windowID); 974 } 975 976 public void refresh() 977 { 978 selenium.refresh(); 979 } 980 981 public void removeAllSelections(String locator) 982 { 983 selenium.removeAllSelections(locator); 984 } 985 986 public void removeScript(String scriptTagId) 987 { 988 selenium.removeScript(scriptTagId); 989 } 990 991 public void removeSelection(String locator, String optionLocator) 992 { 993 selenium.removeSelection(locator, optionLocator); 994 } 995 996 public String retrieveLastRemoteControlLogs() 997 { 998 return selenium.retrieveLastRemoteControlLogs(); 999 } 1000 1001 public void rollup(String rollupName, String kwargs) 1002 { 1003 selenium.rollup(rollupName, kwargs); 1004 } 1005 1006 public void runScript(String script) 1007 { 1008 selenium.runScript(script); 1009 } 1010 1011 public void select(String selectLocator, String optionLocator) 1012 { 1013 selenium.select(selectLocator, optionLocator); 1014 } 1015 1016 public void selectFrame(String locator) 1017 { 1018 selenium.selectFrame(locator); 1019 } 1020 1021 public void selectPopUp(String windowID) 1022 { 1023 selenium.selectPopUp(windowID); 1024 } 1025 1026 public void selectWindow(String windowID) 1027 { 1028 selenium.selectWindow(windowID); 1029 } 1030 1031 public void setBrowserLogLevel(String logLevel) 1032 { 1033 selenium.setBrowserLogLevel(logLevel); 1034 } 1035 1036 public void setContext(String context) 1037 { 1038 selenium.setContext(context); 1039 } 1040 1041 public void setCursorPosition(String locator, String position) 1042 { 1043 selenium.setCursorPosition(locator, position); 1044 } 1045 1046 public void setExtensionJs(String extensionJs) 1047 { 1048 selenium.setExtensionJs(extensionJs); 1049 } 1050 1051 public void setMouseSpeed(String pixels) 1052 { 1053 selenium.setMouseSpeed(pixels); 1054 } 1055 1056 public void setSpeed(String value) 1057 { 1058 selenium.setSpeed(value); 1059 } 1060 1061 public void setTimeout(String timeout) 1062 { 1063 selenium.setTimeout(timeout); 1064 } 1065 1066 public void shiftKeyDown() 1067 { 1068 selenium.shiftKeyDown(); 1069 } 1070 1071 public void shiftKeyUp() 1072 { 1073 selenium.shiftKeyUp(); 1074 } 1075 1076 public void showContextualBanner() 1077 { 1078 selenium.showContextualBanner(); 1079 } 1080 1081 public void showContextualBanner(String className, String methodName) 1082 { 1083 selenium.showContextualBanner(className, methodName); 1084 } 1085 1086 public void shutDownSeleniumServer() 1087 { 1088 selenium.shutDownSeleniumServer(); 1089 } 1090 1091 public void start() 1092 { 1093 selenium.start(); 1094 } 1095 1096 public void start(Object optionsObject) 1097 { 1098 selenium.start(optionsObject); 1099 } 1100 1101 public void start(String optionsString) 1102 { 1103 selenium.start(optionsString); 1104 } 1105 1106 public void stop() 1107 { 1108 selenium.stop(); 1109 } 1110 1111 public void submit(String formLocator) 1112 { 1113 selenium.submit(formLocator); 1114 } 1115 1116 public void type(String locator, String value) 1117 { 1118 selenium.type(locator, value); 1119 } 1120 1121 public void typeKeys(String locator, String value) 1122 { 1123 selenium.typeKeys(locator, value); 1124 } 1125 1126 public void uncheck(String locator) 1127 { 1128 selenium.uncheck(locator); 1129 } 1130 1131 public void useXpathLibrary(String libraryName) 1132 { 1133 selenium.useXpathLibrary(libraryName); 1134 } 1135 1136 public void waitForCondition(String script, String timeout) 1137 { 1138 selenium.waitForCondition(script, timeout); 1139 } 1140 1141 public void waitForFrameToLoad(String frameAddress, String timeout) 1142 { 1143 selenium.waitForFrameToLoad(frameAddress, timeout); 1144 } 1145 1146 public void waitForPageToLoad(String timeout) 1147 { 1148 selenium.waitForPageToLoad(timeout); 1149 } 1150 1151 public void waitForPopUp(String windowID, String timeout) 1152 { 1153 selenium.waitForPopUp(windowID, timeout); 1154 } 1155 1156 public void windowFocus() 1157 { 1158 selenium.windowFocus(); 1159 } 1160 1161 public void windowMaximize() 1162 { 1163 selenium.windowMaximize(); 1164 } 1165 1166 // --------------------------------------------------------------------- 1167 // End of delegate methods 1168 // --------------------------------------------------------------------- 1169 1170 /** 1171 * Formats a message from the provided arguments, which is written to System.err. In addition, 1172 * captures the AUT's markup, screenshot, and a report to the output directory. 1173 * 1174 * @param message 1175 * @param arguments 1176 * @since 5.4 1177 */ 1178 protected final void reportAndThrowAssertionError(String message, Object... arguments) 1179 { 1180 StringBuilder builder = new StringBuilder(5000); 1181 1182 String formatted = String.format(message, arguments); 1183 1184 builder.append(formatted); 1185 1186 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 1187 1188 StringBuilder buffer = new StringBuilder(5000); 1189 1190 boolean enabled = false; 1191 1192 for (StackTraceElement e : stackTrace) 1193 { 1194 if (enabled) 1195 { 1196 buffer.append("\n- "); 1197 buffer.append(e); 1198 continue; 1199 } 1200 1201 if (e.getMethodName().equals("reportAndThrowAssertionError")) 1202 { 1203 enabled = true; 1204 } 1205 } 1206 1207 writeErrorReport(builder.toString()); 1208 1209 throw new AssertionError(formatted); 1210 } 1211 1212 protected final void unreachable() 1213 { 1214 reportAndThrowAssertionError("An unreachable statement was reached."); 1215 } 1216 1217 /** 1218 * Open the {@linkplain #getBaseURL()}, and waits for the page to load. 1219 */ 1220 protected final void openBaseURL() 1221 { 1222 open(baseURL); 1223 1224 waitForPageToLoad(); 1225 } 1226 1227 /** 1228 * Asserts the text of an element, identified by the locator. 1229 * 1230 * @param locator 1231 * identifies the element whose text value is to be asserted 1232 * @param expected 1233 * expected value for the element's text 1234 */ 1235 protected final void assertText(String locator, String expected) 1236 { 1237 String actual = null; 1238 1239 try 1240 { 1241 actual = getText(locator); 1242 } catch (RuntimeException ex) 1243 { 1244 System.err.printf("Error accessing %s: %s, in:\n\n%s\n\n", locator, ex.getMessage(), getHtmlSource()); 1245 1246 throw ex; 1247 } 1248 1249 if (actual.equals(expected)) 1250 { 1251 return; 1252 } 1253 1254 reportAndThrowAssertionError("%s was '%s' not '%s'", locator, actual, expected); 1255 } 1256 1257 protected final void assertTextPresent(String... text) 1258 { 1259 for (String item : text) 1260 { 1261 if (isTextPresent(item)) 1262 { 1263 continue; 1264 } 1265 1266 reportAndThrowAssertionError("Page did not contain '" + item + "'."); 1267 } 1268 } 1269 1270 /** 1271 * Assets that each string provided is present somewhere in the current document. 1272 * 1273 * @param expected 1274 * string expected to be present 1275 */ 1276 protected final void assertSourcePresent(String... expected) 1277 { 1278 String source = getHtmlSource(); 1279 1280 for (String snippet : expected) 1281 { 1282 if (source.contains(snippet)) 1283 { 1284 continue; 1285 } 1286 1287 reportAndThrowAssertionError("Page did not contain source '" + snippet + "'."); 1288 } 1289 } 1290 1291 /** 1292 * Click a link identified by a locator, then wait for the resulting page to load. 1293 * This is not useful for Ajax updates, just normal full-page refreshes. 1294 * 1295 * @param locator 1296 * identifies the link to click 1297 */ 1298 protected final void clickAndWait(String locator) 1299 { 1300 click(locator); 1301 1302 waitForPageToLoad(); 1303 } 1304 1305 /** 1306 * Waits for the page to load (up to 15 seconds). This is invoked after clicking on an element 1307 * that forces a full page refresh. 1308 */ 1309 protected final void waitForPageToLoad() 1310 { 1311 waitForPageToLoad(PAGE_LOAD_TIMEOUT); 1312 } 1313 1314 /** 1315 * Used when the locator identifies an attribute, not an element. 1316 * 1317 * @param locator 1318 * identifies the attribute whose value is to be asserted 1319 * @param expected 1320 * expected value for the attribute 1321 */ 1322 protected final void assertAttribute(String locator, String expected) 1323 { 1324 String actual = null; 1325 1326 try 1327 { 1328 actual = getAttribute(locator); 1329 } catch (RuntimeException ex) 1330 { 1331 1332 reportAndThrowAssertionError("Error accessing %s: %s", locator, ex.getMessage()); 1333 } 1334 1335 if (actual.equals(expected)) 1336 { 1337 return; 1338 } 1339 1340 reportAndThrowAssertionError("%s was '%s' not '%s'", locator, actual, expected); 1341 } 1342 1343 /** 1344 * Assets that the value in the field matches the expectation 1345 * 1346 * @param locator 1347 * identifies the field 1348 * @param expected 1349 * expected value for the field 1350 * @since 5.3 1351 */ 1352 protected final void assertFieldValue(String locator, String expected) 1353 { 1354 try 1355 { 1356 assertEquals(getValue(locator), expected); 1357 } catch (AssertionError ex) 1358 { 1359 reportAndThrowAssertionError("Failure accessing %s: %s", locator, ex); 1360 } 1361 } 1362 1363 /** 1364 * Opens the base URL, then clicks through a series of links to get to a desired application 1365 * state. 1366 * 1367 * @since 5.3 1368 */ 1369 protected final void openLinks(String... linkText) 1370 { 1371 openBaseURL(); 1372 1373 for (String text : linkText) 1374 { 1375 clickAndWait("link=" + text); 1376 } 1377 } 1378 1379 /** 1380 * Sleeps for the indicated number of seconds. 1381 * 1382 * @since 5.3 1383 */ 1384 protected final void sleep(long millis) 1385 { 1386 try 1387 { 1388 Thread.sleep(millis); 1389 } catch (InterruptedException ex) 1390 { 1391 // Ignore. 1392 } 1393 } 1394 1395 /** 1396 * Waits, up to the page load limit for an element (identified by a CSS rule) to exist 1397 * (it is not assured that the element will be visible). 1398 * 1399 * @param cssRule 1400 * used to locate the element 1401 * @since 5.3 1402 */ 1403 protected void waitForCSSSelectedElementToAppear(String cssRule) 1404 { 1405 String condition = String.format("window.$$ && window.$$(\"%s\").size() > 0", cssRule); 1406 1407 waitForCondition(condition, PAGE_LOAD_TIMEOUT); 1408 } 1409 1410 /** 1411 * Waits for the element with the given client-side id to be present in the DOM ( 1412 * does not assure that the element is visible). 1413 * 1414 * @param elementId 1415 * identifies the element 1416 * @since 5.3 1417 */ 1418 protected final void waitForElementToAppear(String elementId) 1419 { 1420 1421 String condition = String.format("window.$(\"%s\")", elementId); 1422 1423 waitForCondition(condition, PAGE_LOAD_TIMEOUT); 1424 } 1425 1426 /** 1427 * Waits for the element to be removed from the DOM. 1428 * 1429 * @param elementId 1430 * client-side id of element 1431 * @since 5.3 1432 */ 1433 protected final void waitForElementToDisappear(String elementId) 1434 { 1435 String condition = String.format("window.$(\"%s\").hide()", elementId); 1436 1437 waitForCondition(condition, PAGE_LOAD_TIMEOUT); 1438 } 1439 1440 /** 1441 * Waits for the element specified by the selector to become visible 1442 * Note that waitForElementToAppear waits for the element to be present in the dom, visible or not. waitForVisible 1443 * waits for an element that already exists in the dom to become visible. 1444 * 1445 * @param selector 1446 * element selector 1447 * @since 5.3 1448 */ 1449 protected final void waitForVisible(String selector) 1450 { 1451 String condition = String.format("selenium.isVisible(\"%s\")", selector); 1452 1453 waitForCondition(condition, PAGE_LOAD_TIMEOUT); 1454 } 1455 1456 /** 1457 * Waits for the element specified by the selector to become invisible 1458 * Note that waitForElementToDisappear waits for the element to be absent from the dom, visible or not. waitForInvisible 1459 * waits for an existing element to become invisible. 1460 * 1461 * @param selector 1462 * element selector 1463 * @since 5.3 1464 */ 1465 protected final void waitForInvisible(String selector) 1466 { 1467 String condition = String.format("!selenium.isVisible(\"%s\")", selector); 1468 1469 waitForCondition(condition, PAGE_LOAD_TIMEOUT); 1470 } 1471 1472 /** 1473 * Asserts that the current page's title matches the expected value. 1474 * 1475 * @param expected 1476 * value for title 1477 * @since 5.3 1478 */ 1479 protected final void assertTitle(String expected) 1480 { 1481 try 1482 { 1483 assertEquals(getTitle(), expected); 1484 } catch (AssertionError ex) 1485 { 1486 reportAndThrowAssertionError("Unexpected title: %s", ex); 1487 1488 throw ex; 1489 } 1490 } 1491 1492 /** 1493 * Waits until all active XHR requests are completed. However, this is Prototype-based. 1494 * 1495 * @param timeout 1496 * timeout to wait for 1497 * @since 5.3 1498 * @deprecated Deprecated in 5.4 as it is tied to Prototype. 1499 */ 1500 protected final void waitForAjaxRequestsToComplete(String timeout) 1501 { 1502 waitForCondition("selenium.browserbot.getCurrentWindow().Ajax.activeRequestCount == 0", timeout); 1503 } 1504 1505 public Number getCssCount(String str) 1506 { 1507 return selenium.getCssCount(str); 1508 } 1509 1510 /** 1511 * Waits for page initialization to finish, which is recognized by the {@code data-page-initialized} attribute 1512 * being added to the HTML element. Polls at 20ms intervals for 200ms. 1513 * 1514 * @since 5.4 1515 */ 1516 protected final void waitForPageInitialized() 1517 { 1518 for (int i = 0; i < 10; i++) 1519 { 1520 if (isElementPresent("css=html[data-page-initialized]")) 1521 { 1522 return; 1523 } 1524 1525 sleep(20); 1526 } 1527 1528 reportAndThrowAssertionError("Page did not finish initializing."); 1529 } 1530 }