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