001    // Copyright 2007, 2008 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.tapestry.test;
016    
017    import com.thoughtworks.selenium.CommandProcessor;
018    import com.thoughtworks.selenium.DefaultSelenium;
019    import com.thoughtworks.selenium.HttpCommandProcessor;
020    import com.thoughtworks.selenium.Selenium;
021    import org.openqa.selenium.server.SeleniumServer;
022    import org.testng.Assert;
023    import org.testng.annotations.AfterClass;
024    import org.testng.annotations.BeforeClass;
025    
026    /**
027     * A base class for creating integration tests. Ths encapsulates starting up an in-process copy of Jetty, and in-process
028     * copy of {@link SeleniumServer}, and a Selenium client.
029     * <p/>
030     * Unless you are <em>very, very clever</em>, you will want to run the tests sequentially. TestNG tends to run them in
031     * an arbitrary order unless you explicitly set the order. If you have managed to get TestNG to run tests in parallel,
032     * you may see further problems caused by a single client jumping all over your web application in an unpredictable
033     * order.
034     * <p/>
035     * This class implements the {@link Selenium} interface, and delegates all those methods to the {@link DefaultSelenium}
036     * instance it creates. It also extends the normal exception reporting for any failed command or query to produce a more
037     * detailed report to the main console.
038     *
039     * @see org.apache.tapestry.test.JettyRunner
040     */
041    public class AbstractIntegrationTestSuite extends Assert implements Selenium
042    {
043        /**
044         * Default directory containing the web application to be tested (this conforms to Maven's default folder).
045         */
046        public static final String DEFAULT_WEB_APP_ROOT = "src/main/webapp";
047    
048        /**
049         * Default browser in which to run tests - firefox
050         */
051        public static final String DEFAULT_WEB_BROWSER_COMMAND = "*firefox";
052    
053        /**
054         * 15 seconds
055         */
056        public static final String PAGE_LOAD_TIMEOUT = "15000";
057    
058        /**
059         * The port on which the internal copy of Jetty is executed.
060         */
061        public static final int JETTY_PORT = 9999;
062    
063        // This is likely to be a problem, since may want to test with a context path, rather than as
064        // root.
065        public static final String BASE_URL = String.format("http://localhost:%d/", JETTY_PORT);
066    
067        public static final String SUBMIT = "//input[@type='submit']";
068    
069        private final String _webappRoot;
070    
071        private final String _seleniumBrowserCommand;
072    
073        private JettyRunner _jettyRunner;
074    
075        private Selenium _selenium;
076    
077        private SeleniumServer _server;
078    
079        /**
080         * Initializes the suite using {@link #DEFAULT_WEB_APP_ROOT}.
081         */
082        public AbstractIntegrationTestSuite()
083        {
084            this(DEFAULT_WEB_APP_ROOT, DEFAULT_WEB_BROWSER_COMMAND);
085        }
086    
087        /**
088         * @param webAppRoot the directory containing the web application to be tested.
089         */
090        protected AbstractIntegrationTestSuite(String webAppRoot)
091        {
092            this(webAppRoot, DEFAULT_WEB_BROWSER_COMMAND);
093        }
094    
095        /**
096         * @param webAppRoot     web application root (default src/main/webapp)
097         * @param browserCommand browser command to pass to selenium. Default is *firefox, syntax for custom browsers is
098         *                       *custom &lt;path_to_browser&gt;, e.g. *custom /usr/lib/mozilla-firefox/firefox
099         */
100        protected AbstractIntegrationTestSuite(String webAppRoot, String browserCommand)
101        {
102            _webappRoot = webAppRoot;
103            _seleniumBrowserCommand = browserCommand;
104        }
105    
106        protected final void assertSourcePresent(String... expected)
107        {
108            String source = _selenium.getHtmlSource();
109    
110            for (String snippet : expected)
111            {
112                if (source.contains(snippet)) continue;
113    
114                System.err.printf("Source content '%s' not found in:\n%s\n\n", snippet, source);
115    
116                throw new AssertionError("Page did not contain source '" + snippet + "'.");
117            }
118        }
119    
120        /**
121         * Used when the locator identifies an attribute, not an element.
122         *
123         * @param locator  identifies the attribute whose value is to be asserted
124         * @param expected expected value for the attribute
125         */
126        protected final void assertAttribute(String locator, String expected)
127        {
128            String actual = null;
129    
130            try
131            {
132                actual = getAttribute(locator);
133            }
134            catch (RuntimeException ex)
135            {
136                System.err.printf("Error accessing %s: %s, in:\n\n%s\n\n", locator, ex.getMessage(),
137                                  _selenium.getHtmlSource());
138    
139                throw ex;
140            }
141    
142            if (actual.equals(expected)) return;
143    
144            System.err.printf("Text for attribute %s should be '%s' but is '%s', in:\n\n%s\n\n", locator, expected, actual,
145                              getHtmlSource());
146    
147            throw new AssertionError(String.format("%s was '%s' not '%s'", locator, actual, expected));
148        }
149    
150        /**
151         * Asserts the text of an element, identified by the locator.
152         *
153         * @param locator  identifies the element whose text value is to be asserted
154         * @param expected expected value for the element's text
155         */
156        protected final void assertText(String locator, String expected)
157        {
158            String actual = null;
159    
160            try
161            {
162                actual = getText(locator);
163            }
164            catch (RuntimeException ex)
165            {
166                System.err.printf("Error accessing %s: %s, in:\n\n%s\n\n", locator, ex.getMessage(),
167                                  _selenium.getHtmlSource());
168    
169                throw ex;
170            }
171    
172            if (actual.equals(expected)) return;
173    
174            System.err.printf("Text for %s should be '%s' but is '%s', in:\n\n%s\n\n", locator, expected, actual,
175                              getHtmlSource());
176    
177            throw new AssertionError(String.format("%s was '%s' not '%s'", locator, actual, expected));
178        }
179    
180        protected final void assertTextPresent(String... text)
181        {
182            for (String item : text)
183            {
184                if (isTextPresent(item)) return;
185    
186                System.err.printf("Text pattern '%s' not found in:\n%s\n\n", item, _selenium
187                        .getHtmlSource());
188    
189                throw new AssertionError("Page did not contain '" + item + "'.");
190            }
191        }
192    
193        protected final void assertFieldValue(String locator, String expected)
194        {
195            assertEquals(getValue(locator), expected);
196        }
197    
198        protected final void clickAndWait(String link)
199        {
200            click(link);
201            waitForPageToLoad(PAGE_LOAD_TIMEOUT);
202        }
203    
204        protected final void assertTextSeries(String idFormat, int startIndex, String... values)
205        {
206            for (int i = 0; i < values.length; i++)
207            {
208                String id = String.format(idFormat, startIndex + i);
209    
210                assertText(id, values[i]);
211            }
212        }
213    
214        protected final void assertAttributeSeries(String idFormat, int startIndex, String... values)
215          {
216              for (int i = 0; i < values.length; i++)
217              {
218                  String id = String.format(idFormat, startIndex + i);
219    
220                  assertAttribute(id, values[i]);
221              }
222          }
223    
224    
225        protected final void assertFieldValueSeries(String idFormat, int startIndex, String... values)
226        {
227            for (int i = 0; i < values.length; i++)
228            {
229                String id = String.format(idFormat, startIndex + i);
230    
231                assertFieldValue(id, values[i]);
232            }
233        }
234    
235        @AfterClass(alwaysRun = true)
236        public void cleanup() throws Exception
237        {
238            _selenium.stop();
239            _selenium = null;
240    
241            _server.stop();
242            _server = null;
243    
244            _jettyRunner.stop();
245            _jettyRunner = null;
246        }
247    
248        @BeforeClass(alwaysRun = true)
249        public void setup() throws Exception
250        {
251            _jettyRunner = new JettyRunner(TapestryTestConstants.MODULE_BASE_DIR, "/", JETTY_PORT, _webappRoot);
252    
253            _server = new SeleniumServer();
254    
255            _server.start();
256    
257            CommandProcessor cp = new HttpCommandProcessor("localhost", SeleniumServer.DEFAULT_PORT,
258                                                           _seleniumBrowserCommand, BASE_URL);
259    
260            _selenium = new DefaultSelenium(new ErrorReportingCommandProcessor(cp));
261    
262            _selenium.start();
263        }
264    
265        public void addSelection(String locator, String optionLocator)
266        {
267            _selenium.addSelection(locator, optionLocator);
268        }
269    
270        public void answerOnNextPrompt(String answer)
271        {
272            _selenium.answerOnNextPrompt(answer);
273        }
274    
275        public void check(String locator)
276        {
277            _selenium.check(locator);
278        }
279    
280        public void chooseCancelOnNextConfirmation()
281        {
282            _selenium.chooseCancelOnNextConfirmation();
283        }
284    
285        public void chooseOkOnNextConfirmation()
286        {
287            _selenium.chooseOkOnNextConfirmation();
288        }
289    
290        public void click(String locator)
291        {
292            _selenium.click(locator);
293        }
294    
295        public void doubleClick(String locator)
296        {
297            _selenium.doubleClick(locator);
298        }
299    
300        public void clickAt(String locator, String coordString)
301        {
302            _selenium.clickAt(locator, coordString);
303        }
304    
305        public void doubleClickAt(String locator, String coordString)
306        {
307            _selenium.doubleClickAt(locator, coordString);
308        }
309    
310        public void close()
311        {
312            _selenium.close();
313        }
314    
315        public void fireEvent(String locator, String eventName)
316        {
317            _selenium.fireEvent(locator, eventName);
318        }
319    
320        public String getAlert()
321        {
322            return _selenium.getAlert();
323        }
324    
325        public String[] getAllButtons()
326        {
327            return _selenium.getAllButtons();
328        }
329    
330        public String[] getAllFields()
331        {
332            return _selenium.getAllFields();
333        }
334    
335        public String[] getAttributeFromAllWindows(String attributeName)
336        {
337            return _selenium.getAttributeFromAllWindows(attributeName);
338        }
339    
340        public void dragdrop(String locator, String movementsString)
341        {
342            _selenium.dragdrop(locator, movementsString);
343        }
344    
345        public void setMouseSpeed(String pixels)
346        {
347            _selenium.setMouseSpeed(pixels);
348        }
349    
350        public Number getMouseSpeed()
351        {
352            return _selenium.getMouseSpeed();
353        }
354    
355        public void dragAndDrop(String locator, String movementsString)
356        {
357            _selenium.dragAndDrop(locator, movementsString);
358        }
359    
360        public void dragAndDropToObject(String locatorOfObjectToBeDragged, String locatorOfDragDestinationObject)
361        {
362            _selenium.dragAndDropToObject(locatorOfObjectToBeDragged, locatorOfDragDestinationObject);
363        }
364    
365        public void windowFocus()
366        {
367            _selenium.windowFocus();
368        }
369    
370        public void windowMaximize()
371        {
372            _selenium.windowMaximize();
373        }
374    
375        public String[] getAllWindowIds()
376        {
377            return _selenium.getAllWindowIds();
378        }
379    
380        public String[] getAllWindowNames()
381        {
382            return _selenium.getAllWindowNames();
383        }
384    
385        public String[] getAllWindowTitles()
386        {
387            return _selenium.getAllWindowTitles();
388        }
389    
390        public String[] getAllLinks()
391        {
392            return _selenium.getAllLinks();
393        }
394    
395        public String getAttribute(String attributeLocator)
396        {
397            return _selenium.getAttribute(attributeLocator);
398        }
399    
400        public String getBodyText()
401        {
402            return _selenium.getBodyText();
403        }
404    
405        public String getConfirmation()
406        {
407            return _selenium.getConfirmation();
408        }
409    
410        public Number getCursorPosition(String locator)
411        {
412            return _selenium.getCursorPosition(locator);
413        }
414    
415        public String getEval(String script)
416        {
417            return _selenium.getEval(script);
418        }
419    
420        public String getExpression(String expression)
421        {
422            return _selenium.getExpression(expression);
423        }
424    
425        public Number getXpathCount(String xpath)
426        {
427            return _selenium.getXpathCount(xpath);
428        }
429    
430        public void assignId(String locator, String identifier)
431        {
432            _selenium.assignId(locator, identifier);
433        }
434    
435        public void allowNativeXpath(String allow)
436        {
437            _selenium.allowNativeXpath(allow);
438        }
439    
440        public String getHtmlSource()
441        {
442            return _selenium.getHtmlSource();
443        }
444    
445        public String getLocation()
446        {
447            return _selenium.getLocation();
448        }
449    
450        public String getPrompt()
451        {
452            return _selenium.getPrompt();
453        }
454    
455        public String getSelectedId(String selectLocator)
456        {
457            return _selenium.getSelectedId(selectLocator);
458        }
459    
460        public String[] getSelectedIds(String selectLocator)
461        {
462            return _selenium.getSelectedIds(selectLocator);
463        }
464    
465        public String getSelectedIndex(String selectLocator)
466        {
467            return _selenium.getSelectedIndex(selectLocator);
468        }
469    
470        public String[] getSelectedIndexes(String selectLocator)
471        {
472            return _selenium.getSelectedIndexes(selectLocator);
473        }
474    
475        public String getSelectedLabel(String selectLocator)
476        {
477            return _selenium.getSelectedLabel(selectLocator);
478        }
479    
480        public String[] getSelectedLabels(String selectLocator)
481        {
482            return _selenium.getSelectedLabels(selectLocator);
483        }
484    
485        public String getSelectedValue(String selectLocator)
486        {
487            return _selenium.getSelectedValue(selectLocator);
488        }
489    
490        public String[] getSelectedValues(String selectLocator)
491        {
492            return _selenium.getSelectedValues(selectLocator);
493        }
494    
495        public String[] getSelectOptions(String selectLocator)
496        {
497            return _selenium.getSelectOptions(selectLocator);
498        }
499    
500        public String getTable(String tableCellAddress)
501        {
502            return _selenium.getTable(tableCellAddress);
503        }
504    
505        public String getText(String locator)
506        {
507            return _selenium.getText(locator);
508        }
509    
510        public void highlight(String locator)
511        {
512            _selenium.highlight(locator);
513        }
514    
515        public String getTitle()
516        {
517            return _selenium.getTitle();
518        }
519    
520        public String getValue(String locator)
521        {
522            return _selenium.getValue(locator);
523        }
524    
525        public void goBack()
526        {
527            _selenium.goBack();
528        }
529    
530        public boolean isAlertPresent()
531        {
532            return _selenium.isAlertPresent();
533        }
534    
535        public boolean isChecked(String locator)
536        {
537            return _selenium.isChecked(locator);
538        }
539    
540        public boolean isConfirmationPresent()
541        {
542            return _selenium.isConfirmationPresent();
543        }
544    
545        public boolean isEditable(String locator)
546        {
547            return _selenium.isEditable(locator);
548        }
549    
550        public boolean isElementPresent(String locator)
551        {
552            return _selenium.isElementPresent(locator);
553        }
554    
555        public boolean isPromptPresent()
556        {
557            return _selenium.isPromptPresent();
558        }
559    
560        public boolean isSomethingSelected(String selectLocator)
561        {
562            return _selenium.isSomethingSelected(selectLocator);
563        }
564    
565        public boolean isTextPresent(String pattern)
566        {
567            return _selenium.isTextPresent(pattern);
568        }
569    
570        public boolean isVisible(String locator)
571        {
572            return _selenium.isVisible(locator);
573        }
574    
575        public void keyDown(String locator, String keycode)
576        {
577            _selenium.keyDown(locator, keycode);
578        }
579    
580        public void keyPress(String locator, String keycode)
581        {
582            _selenium.keyPress(locator, keycode);
583        }
584    
585        public void shiftKeyDown()
586        {
587            _selenium.shiftKeyDown();
588        }
589    
590        public void shiftKeyUp()
591        {
592            _selenium.shiftKeyUp();
593        }
594    
595        public void metaKeyDown()
596        {
597            _selenium.metaKeyDown();
598        }
599    
600        public void metaKeyUp()
601        {
602            _selenium.metaKeyUp();
603        }
604    
605        public void altKeyDown()
606        {
607            _selenium.altKeyDown();
608        }
609    
610        public void altKeyUp()
611        {
612            _selenium.altKeyUp();
613        }
614    
615        public void controlKeyDown()
616        {
617            _selenium.controlKeyDown();
618        }
619    
620        public void controlKeyUp()
621        {
622            _selenium.controlKeyUp();
623        }
624    
625        public void keyUp(String locator, String keycode)
626        {
627            _selenium.keyUp(locator, keycode);
628        }
629    
630        public void mouseDown(String locator)
631        {
632            _selenium.mouseDown(locator);
633        }
634    
635        public void mouseDownAt(String locator, String coordString)
636        {
637            _selenium.mouseDownAt(locator, coordString);
638        }
639    
640        public void mouseUp(String locator)
641        {
642            _selenium.mouseUp(locator);
643        }
644    
645        public void mouseUpAt(String locator, String coordString)
646        {
647            _selenium.mouseUpAt(locator, coordString);
648        }
649    
650        public void mouseMove(String locator)
651        {
652            _selenium.mouseMove(locator);
653        }
654    
655        public void mouseMoveAt(String locator, String coordString)
656        {
657            _selenium.mouseMoveAt(locator, coordString);
658        }
659    
660        public void mouseOver(String locator)
661        {
662            _selenium.mouseOver(locator);
663        }
664    
665        public void mouseOut(String locator)
666        {
667            _selenium.mouseOut(locator);
668        }
669    
670        public void open(String url)
671        {
672            _selenium.open(url);
673    
674            waitForPageToLoad(PAGE_LOAD_TIMEOUT);
675        }
676    
677        public void openWindow(String url, String windowID)
678        {
679            _selenium.openWindow(url, windowID);
680        }
681    
682        public void refresh()
683        {
684            _selenium.refresh();
685        }
686    
687        public void removeSelection(String locator, String optionLocator)
688        {
689            _selenium.removeSelection(locator, optionLocator);
690        }
691    
692        public void removeAllSelections(String locator)
693        {
694            _selenium.removeAllSelections(locator);
695        }
696    
697        public void select(String selectLocator, String optionLocator)
698        {
699            _selenium.select(selectLocator, optionLocator);
700        }
701    
702        public void selectWindow(String windowID)
703        {
704            _selenium.selectWindow(windowID);
705        }
706    
707        public void selectFrame(String locator)
708        {
709            _selenium.selectFrame(locator);
710        }
711    
712        public boolean getWhetherThisFrameMatchFrameExpression(String currentFrameString, String target)
713        {
714            return _selenium.getWhetherThisFrameMatchFrameExpression(currentFrameString, target);
715        }
716    
717        public boolean getWhetherThisWindowMatchWindowExpression(String currentWindowString, String target)
718        {
719            return _selenium.getWhetherThisWindowMatchWindowExpression(currentWindowString, target);
720        }
721    
722        public void setCursorPosition(String locator, String position)
723        {
724            _selenium.setCursorPosition(locator, position);
725        }
726    
727        public Number getElementIndex(String locator)
728        {
729            return _selenium.getElementIndex(locator);
730        }
731    
732        public boolean isOrdered(String locator1, String locator2)
733        {
734            return _selenium.isOrdered(locator1, locator2);
735        }
736    
737        public Number getElementPositionLeft(String locator)
738        {
739            return _selenium.getElementPositionLeft(locator);
740        }
741    
742        public Number getElementPositionTop(String locator)
743        {
744            return _selenium.getElementPositionTop(locator);
745        }
746    
747        public Number getElementWidth(String locator)
748        {
749            return _selenium.getElementWidth(locator);
750        }
751    
752        public Number getElementHeight(String locator)
753        {
754            return _selenium.getElementHeight(locator);
755        }
756    
757        public void setTimeout(String timeout)
758        {
759            _selenium.setTimeout(timeout);
760        }
761    
762        public void start()
763        {
764            _selenium.start();
765        }
766    
767        public void stop()
768        {
769            _selenium.stop();
770        }
771    
772        public void submit(String formLocator)
773        {
774            _selenium.submit(formLocator);
775        }
776    
777        public void type(String locator, String value)
778        {
779            _selenium.type(locator, value);
780        }
781    
782        public void typeKeys(String locator, String value)
783        {
784            _selenium.typeKeys(locator, value);
785        }
786    
787        public void setSpeed(String value)
788        {
789            _selenium.setSpeed(value);
790        }
791    
792        public void getSpeed()
793        {
794            _selenium.getSpeed();
795        }
796    
797        public void uncheck(String locator)
798        {
799            _selenium.uncheck(locator);
800        }
801    
802        public void waitForCondition(String script, String timeout)
803        {
804            _selenium.waitForCondition(script, timeout);
805        }
806    
807        public void waitForPageToLoad(String timeout)
808        {
809            _selenium.waitForPageToLoad(timeout);
810        }
811    
812        public void waitForFrameToLoad(String frameAddress, String timeout)
813        {
814            _selenium.waitForFrameToLoad(frameAddress, timeout);
815        }
816    
817        public String getCookie()
818        {
819            return _selenium.getCookie();
820        }
821    
822        public void createCookie(String nameValuePair, String optionsString)
823        {
824            _selenium.createCookie(nameValuePair, optionsString);
825        }
826    
827        public void deleteCookie(String name, String path)
828        {
829            _selenium.deleteCookie(name, path);
830        }
831    
832        public void setBrowserLogLevel(String logLevel)
833        {
834            _selenium.setBrowserLogLevel(logLevel);
835        }
836    
837        public void runScript(String script)
838        {
839            _selenium.runScript(script);
840        }
841    
842        public void addLocationStrategy(String strategyName, String functionDefinition)
843        {
844            _selenium.addLocationStrategy(strategyName, functionDefinition);
845        }
846    
847        public void setContext(String context)
848        {
849            _selenium.setContext(context);
850        }
851    
852        public void captureScreenshot(String filename)
853        {
854            _selenium.captureScreenshot(filename);
855        }
856    
857    
858        /**
859         * Waits the default time for the page to load.
860         */
861        public void waitForPageToLoad()
862        {
863            waitForPageToLoad(PAGE_LOAD_TIMEOUT);
864        }
865    
866        public void waitForPopUp(String windowID, String timeout)
867        {
868            _selenium.waitForPopUp(windowID, timeout);
869        }
870    
871        /**
872         * Used to start a typical test, by opening to the base URL and clicking through a series of links.
873         */
874        protected final void start(String... linkText)
875        {
876            open(BASE_URL);
877    
878            for (String s : linkText)
879                clickAndWait(String.format("link=%s", s));
880        }
881    
882    }