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 <path_to_browser>, 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 }