1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.aludratest.service.gui.web.selenium.selenium1;
17
18 import org.aludratest.exception.AutomationException;
19 import org.aludratest.exception.FunctionalFailure;
20 import org.aludratest.exception.PerformanceFailure;
21 import org.aludratest.exception.TechnicalException;
22 import org.aludratest.service.SystemConnector;
23 import org.aludratest.service.gui.component.impl.LinkImpl;
24 import org.aludratest.service.gui.web.selenium.ConditionCheck;
25 import org.aludratest.service.gui.web.selenium.ElementCommand;
26 import org.aludratest.service.gui.web.selenium.SeleniumResourceService;
27 import org.aludratest.service.gui.web.selenium.SeleniumWrapperConfiguration;
28 import org.aludratest.service.gui.web.selenium.WindowCommand;
29 import org.aludratest.service.locator.element.ElementLocators.ElementLocatorsGUI;
30 import org.aludratest.service.locator.element.GUIElementLocator;
31 import org.aludratest.service.locator.option.OptionLocator;
32 import org.aludratest.service.locator.window.TitleLocator;
33 import org.aludratest.service.locator.window.WindowLocator;
34 import org.aludratest.service.util.ServiceUtil;
35 import org.aludratest.service.util.TaskCompletionUtil;
36 import org.aludratest.testcase.event.attachment.Attachment;
37 import org.aludratest.testcase.event.attachment.BinaryAttachment;
38 import org.aludratest.testcase.event.attachment.StringAttachment;
39 import org.apache.commons.codec.binary.Base64;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import com.thoughtworks.selenium.Selenium;
44 import com.thoughtworks.selenium.SeleniumException;
45
46
47
48
49
50
51
52
53 public class SeleniumWrapper {
54
55 private static final Logger LOGGER = LoggerFactory.getLogger(SeleniumWrapper.class);
56
57 private SeleniumFacade selenium = null;
58
59 private final SeleniumWrapperConfiguration configuration;
60
61 private SeleniumResourceService seleniumResourceService;
62
63 private String usedSeleniumHost = null;
64
65 private SystemConnector systemConnector;
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public SeleniumWrapper(String moduleName, SeleniumResourceService seleniumResourceService,
80 SeleniumWrapperConfiguration configuration) {
81 this.configuration = configuration;
82 this.seleniumResourceService = seleniumResourceService;
83 init();
84 }
85
86 private void init() {
87 try {
88 usedSeleniumHost = seleniumResourceService.acquire();
89
90 String host = usedSeleniumHost;
91
92 selenium = new SeleniumFacade(configuration, host);
93 selenium.start();
94 } catch (Exception e) {
95 if (selenium != null) {
96 selenium.stop();
97 }
98 seleniumResourceService.release(usedSeleniumHost);
99 throw new TechnicalException(e.getMessage() + ". Used Host = " + usedSeleniumHost, e);
100 }
101 }
102
103
104
105
106
107 public SeleniumWrapperConfiguration getConfiguration() {
108 return configuration;
109 }
110
111
112 public int getHostCount() {
113 return seleniumResourceService.getHostCount();
114 }
115
116
117
118 public void setSystemConnector(SystemConnector systemConnector) {
119 this.systemConnector = systemConnector;
120 }
121
122
123 public void tearDown() {
124 closeApplicationUnderTest();
125
126 seleniumResourceService.release(usedSeleniumHost);
127 }
128
129
130
131 public void open(String url) {
132 selenium.open(url);
133 waitForPageToLoad();
134 }
135
136
137 public void waitForPageToLoad() {
138 selenium.waitForPageToLoad(getTimeout());
139 }
140
141
142 public void refresh() {
143 selenium.refresh();
144 waitForPageToLoad();
145 }
146
147
148 public String getUsedSeleniumHost() {
149 return usedSeleniumHost;
150 }
151
152
153
154 public void waitForElement(GUIElementLocator locator) {
155 waitForElement(locator, getTimeout());
156 }
157
158
159
160
161 public void waitForElement(final GUIElementLocator locator, long timeout) {
162 ConditionCheck elementPresenceCheck = new ConditionCheck() {
163 @Override
164 public boolean eval() {
165 return selenium.isElementPresent(locator);
166 }
167 };
168 if (!retryUntilTrueOrTimeout(elementPresenceCheck, timeout)) {
169 throw new AutomationException("Element not found: " + locator);
170 }
171 }
172
173
174
175 public void waitForElementNotPresent(GUIElementLocator locator) {
176 waitForElementNotPresent(locator, getTimeout());
177 }
178
179
180
181
182 public void waitForElementNotPresent(final GUIElementLocator locator, long timeout) {
183 boolean elementIsNotFound = retryUntilTrueOrTimeout(new ConditionCheck() {
184 @Override
185 public boolean eval() {
186 return !selenium.isElementPresent(locator);
187 }
188 }, timeout);
189 if (!elementIsNotFound) {
190 throw new AutomationException("An element was unexpectedly found");
191 }
192 }
193
194
195
196 public void waitForVisible(GUIElementLocator locator) {
197 waitForVisible(locator, getTimeout());
198 }
199
200
201
202
203 public void waitForVisible(final GUIElementLocator locator, long timeout) {
204 if (!isCalledByLink()) {
205 if ((locator instanceof ElementLocatorsGUI) && ((ElementLocatorsGUI) locator).getUsedOption() == null) {
206 throw new AutomationException("ElementLocatorsGUI must have usedOption set before waiting for visible");
207 }
208
209 ConditionCheck visibilityCheck = new ConditionCheck() {
210 @Override
211 public boolean eval() {
212 return selenium.isVisible(locator);
213 }
214 };
215 if (!retryUntilTrueOrTimeout(visibilityCheck, timeout)) {
216 throw new AutomationException("The element is not visible.");
217 }
218 }
219 }
220
221
222
223 public void waitForEnabled(GUIElementLocator locator) {
224 waitForEnabled(locator, getTimeout());
225 }
226
227
228
229
230 public void waitForEnabled(final GUIElementLocator locator, long timeout) {
231 if (!isCalledByLink()) {
232 boolean elementIsEnabled = retryUntilTrueOrTimeout(new ConditionCheck() {
233 @Override
234 public boolean eval() {
235 return selenium.isEnabled(locator);
236 }
237 }, timeout);
238 if (!elementIsEnabled) {
239 throw new AutomationException("Element not enabled");
240 }
241 }
242 }
243
244
245
246 public void waitForEditable(GUIElementLocator locator) {
247 waitForEditable(locator, getTimeout());
248 }
249
250
251
252
253 public void waitForEditable(final GUIElementLocator locator, long timeout) {
254 if (!isCalledByLink()) {
255 boolean elementIsEditable = retryUntilTrueOrTimeout(new ConditionCheck() {
256 @Override
257 public boolean eval() {
258 return selenium.isEditable(locator);
259 }
260 }, timeout);
261 if (!elementIsEditable) {
262 throw new AutomationException("Element not editable");
263 }
264 }
265 }
266
267
268
269 public void waitForInForeground(final GUIElementLocator locator) {
270 waitForInForeground(locator, getTimeout());
271 }
272
273
274
275
276 public void waitForInForeground(final GUIElementLocator locator, long timeout) {
277 ConditionCheck foregroundCheck = new ConditionCheck() {
278 @Override
279 public boolean eval() {
280 return selenium.isInForeground(locator);
281 }
282 };
283 if (!retryUntilTrueOrTimeout(foregroundCheck, timeout)) {
284 throw new AutomationException("Element not in foreground.");
285 }
286 }
287
288
289
290
291 public void click(GUIElementLocator locator, int taskCompletionTimeout) {
292 ElementCommand<Void> clickCommand = new ElementCommand<Void>("click", true) {
293 @Override
294 public Void call(GUIElementLocator locator) {
295 selenium.click(locator);
296 return null;
297 }
298 };
299 callElementCommand(locator, taskCompletionTimeout, true, false, clickCommand);
300 }
301
302
303
304
305 public boolean isElementPresent(GUIElementLocator locator) {
306 ElementCommand<Boolean> presenceCommand = new ElementCommand<Boolean>("isElementPresent", false) {
307 @Override
308 public Boolean call(GUIElementLocator locator) {
309
310
311 return true;
312 }
313 };
314 return callElementCommand(locator, -1, true, presenceCommand);
315 }
316
317
318
319
320 public boolean isEditable(GUIElementLocator locator) {
321 ElementCommand<Boolean> editableCheckCommand = new ElementCommand<Boolean>("isEditable", false) {
322 @Override
323 public Boolean call(GUIElementLocator locator) {
324 return selenium.isEditable(locator);
325 }
326 };
327 return callElementCommand(locator, -1, true, editableCheckCommand);
328 }
329
330
331
332
333 public boolean isEnabled(GUIElementLocator locator) {
334 ElementCommand<Boolean> enabledCheckCommand = new ElementCommand<Boolean>("isEnabled", false) {
335 @Override
336 public Boolean call(GUIElementLocator locator) {
337 return selenium.isEnabled(locator);
338 }
339 };
340 return callElementCommand(locator, -1, true, enabledCheckCommand);
341 }
342
343
344
345
346
347 public void select(final GUIElementLocator locator, final OptionLocator optionLocator, int taskCompletionTimeout) {
348 ElementCommand<Void> selectCommand = new ElementCommand<Void>("select", true) {
349 @Override
350 public Void call(GUIElementLocator locator) {
351 selenium.select(locator, optionLocator);
352 return null;
353 }
354 };
355 callElementCommand(locator, taskCompletionTimeout, true, true, selectCommand);
356 }
357
358
359
360
361
362 public void type(GUIElementLocator locator, final String value, int taskCompletionTimeout) {
363 ElementCommand<Void> typeCommand = new ElementCommand<Void>("type", true) {
364 @Override
365 public Void call(GUIElementLocator locator) {
366 selenium.type(locator, value);
367 return null;
368 }
369 };
370 callElementCommand(locator, taskCompletionTimeout, true, true, typeCommand);
371 }
372
373
374
375 public String getText(GUIElementLocator locator) {
376 return getText(locator, true);
377 }
378
379
380
381
382
383
384
385 public String getText(GUIElementLocator locator, boolean visible) {
386 ElementCommand<String> command = new ElementCommand<String>("getText", false) {
387 @Override
388 public String call(GUIElementLocator locator) {
389 return selenium.getText(locator);
390 }
391 };
392 return callElementCommand(locator, -1, visible, command);
393 }
394
395
396
397
398 public boolean isChecked(GUIElementLocator locator) {
399 ElementCommand<Boolean> isCheckedCommand = new ElementCommand<Boolean>("isChecked", false) {
400 @Override
401 public Boolean call(GUIElementLocator locator) {
402 return selenium.isChecked(locator);
403 }
404 };
405 return callElementCommand(locator, -1, true, isCheckedCommand);
406 }
407
408
409
410
411 public String[] getSelectOptions(GUIElementLocator locator) {
412 ElementCommand<String[]> selectOptionsCommand = new ElementCommand<String[]>("getSelectOptions", false) {
413 @Override
414 public String[] call(GUIElementLocator locator) {
415 return selenium.getSelectOptions(locator);
416 }
417 };
418 return callElementCommand(locator, -1, true, selectOptionsCommand);
419 }
420
421
422
423
424 public String getSelectedValue(GUIElementLocator locator) {
425 ElementCommand<String> selectedValueCommand = new ElementCommand<String>("getSelectedValue", false) {
426 @Override
427 public String call(GUIElementLocator locator) {
428 return selenium.getSelectedValue(locator);
429 }
430 };
431 return callElementCommand(locator, -1, true, selectedValueCommand);
432 }
433
434
435
436
437 public String getSelectedLabel(GUIElementLocator locator) {
438 ElementCommand<String> selectedLabelCommand = new ElementCommand<String>("getSelectedLabel", false) {
439 @Override
440 public String call(GUIElementLocator locator) {
441 return selenium.getSelectedLabel(locator);
442 }
443 };
444 return callElementCommand(locator, -1, true, selectedLabelCommand);
445 }
446
447
448
449
450 public String getValue(GUIElementLocator locator) {
451 ElementCommand<String> getValueCommand = new ElementCommand<String>("getValue", false) {
452 @Override
453 public String call(GUIElementLocator locator) {
454 return selenium.getValue(locator);
455 }
456 };
457 return callElementCommand(locator, -1, true, getValueCommand);
458 }
459
460
461
462 public void selectWindow(WindowLocator locator) {
463 callWindowCommand(locator, new WindowCommand() {
464 @Override
465 public void call(WindowLocator locator) {
466 selenium.selectWindow(locator);
467 }
468 });
469 }
470
471
472
473 public void selectWindowByTechnicalName(String locator) {
474 selenium.selectWindow(locator);
475 }
476
477
478
479 public String[] getAllWindowTitles() {
480 return selenium.getAllWindowTitles();
481 }
482
483
484
485 public String[] getAllWindowIDs() {
486 return selenium.getAllWindowIDs();
487 }
488
489
490
491 public String[] getAllWindowNames() {
492 return selenium.getAllWindowNames();
493 }
494
495
496
497 public String getTitle() {
498 return selenium.getTitle();
499 }
500
501
502 public void windowMaximize() {
503 selenium.windowMaximize();
504 }
505
506
507 public void windowFocus() {
508 selenium.windowFocus();
509 }
510
511
512
513 public void switchToIFrame(GUIElementLocator locator) {
514 selenium.switchToIFrame(locator);
515 }
516
517
518 public Attachment getPageSource() {
519 String pageSource = selenium.getHtmlSource();
520 return new StringAttachment("Source", pageSource, configuration.getPageSourceAttachmentExtension());
521 }
522
523
524 public Attachment getScreenshotOfTheWholeScreen() {
525 String base64Data = selenium.captureEntirePageScreenshotToString();
526 Attachment attachment = getScreenshotAttachment(base64Data);
527 return attachment;
528 }
529
530
531 public Attachment getScreenshotOfThePage() {
532 String base64Data = selenium.captureScreenshotToString();
533 Attachment attachment = getScreenshotAttachment(base64Data);
534 return attachment;
535 }
536
537
538
539 public boolean hasFocus(final GUIElementLocator locator) {
540 ElementCommand<Boolean> hasFocusCommand = new ElementCommand<Boolean>("hasFocus", false) {
541 @Override
542 public Boolean call(GUIElementLocator locators) {
543 return selenium.hasFocus(locator);
544 }
545 };
546 return callElementCommand(locator, -1, true, true, hasFocusCommand);
547 }
548
549
550
551 public String[] getLabels(GUIElementLocator locator) {
552 return selenium.getDropDownLabels(locator);
553 }
554
555
556
557 public String[] getValues(final GUIElementLocator locator) {
558 ElementCommand<String[]> getValuesCommand = new ElementCommand<String[]>("getValues", false) {
559 @Override
560 public String[] call(GUIElementLocator locators) {
561 return selenium.getDropDownValues(locator);
562 }
563 };
564 return callElementCommand(locator, -1, true, getValuesCommand);
565 }
566
567
568
569 public void focus(final GUIElementLocator locator) {
570 ElementCommand<Void> focusCommand = new ElementCommand<Void>("focus", false) {
571 @Override
572 public Void call(GUIElementLocator locators) {
573 selenium.focus(locator);
574 return null;
575 }
576 };
577 callElementCommand(locator, -1, true, true, focusCommand);
578 }
579
580
581
582
583
584 public String getAttributeValue(final GUIElementLocator elementLocator, final String attributeName) {
585 ElementCommand<String> getAttributeValueCommand = new ElementCommand<String>("getAttributeValue", false) {
586 @Override
587 public String call(GUIElementLocator locators) {
588 return selenium.getAttributeValue(elementLocator, attributeName);
589 }
590 };
591 return callElementCommand(elementLocator, -1, true, getAttributeValueCommand);
592 }
593
594
595
596 public void keyPress(int keycode) {
597 selenium.keyPress(keycode);
598 }
599
600
601
602
603 public void doubleClick(final GUIElementLocator locator, int taskCompletionTimeout) {
604 ElementCommand<Void> doubleClickCommand = new ElementCommand<Void>("doubleClick", true) {
605 @Override
606 public Void call(GUIElementLocator locators) {
607 selenium.doubleClick(locator);
608 return null;
609 }
610 };
611 callElementCommand(locator, -1, true, false, doubleClickCommand);
612 }
613
614
615 public void close() {
616 selenium.close();
617 }
618
619
620
621
622
623
624 public String getTableCellText(final GUIElementLocator locator, final int row, final int col) {
625 ElementCommand<String> getTableCellTextCommand = new ElementCommand<String>("getTableCellText", false) {
626 @Override
627 public String call(GUIElementLocator locator) {
628 return selenium.getTableCellText(locator, row, col);
629 }
630 };
631 return callElementCommand(locator, -1, true, false, getTableCellTextCommand);
632 }
633
634
635
636
637 public void addCustomRequestHeader(String key, String value) {
638 selenium.addCustomRequestHeader(key, value);
639 }
640
641
642 public int getPauseBetweenRetries() {
643 return configuration.getPauseBetweenRetries();
644 }
645
646
647 public int getTimeout() {
648 return configuration.getTimeout();
649 }
650
651
652
653
654
655
656
657
658
659
660
661
662 public boolean retryUntilTimeout(ConditionCheck condition) {
663 return retryUntilTrueOrTimeout(condition, getTimeout());
664 }
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679 private boolean retryUntilTrueOrTimeout(ConditionCheck condition, long timeout) {
680 long time = System.currentTimeMillis() + timeout;
681 while (System.currentTimeMillis() < time) {
682 if (condition.eval()) {
683 return true;
684 } else {
685 sleepBetweenRetries();
686 }
687 }
688 return false;
689 }
690
691
692
693
694 private void highlight(GUIElementLocator locator) {
695 if (configuration.getHighlightCommands()) {
696 try {
697 selenium.highlight(locator);
698 } catch (SeleniumException e) {
699
700
701
702 LOGGER.trace("Highlighting does not work.", e);
703 }
704 }
705 }
706
707 private <T> T callElementCommand(GUIElementLocator locator, int taskCompletionTimeout, boolean visible,
708 ElementCommand<T> command) {
709 return callElementCommand(locator, taskCompletionTimeout, visible, false, command);
710 }
711
712 private <T> T callElementCommand(GUIElementLocator locator, int taskCompletionTimeout, boolean visible, boolean enabled,
713 ElementCommand<T> command) {
714 doBeforeDelegate(locator, visible, enabled, command.isInteraction());
715 try {
716 T returnValue = command.call(locator);
717 doAfterDelegate(taskCompletionTimeout, command.toString());
718 return returnValue;
719 }
720 catch (SeleniumException e) {
721 String msg = e.getMessage();
722 if (msg != null && msg.matches("ERROR: Element .* not found")) {
723 throw new FunctionalFailure(msg);
724 }
725 throw e;
726 }
727 }
728
729 private void doBeforeDelegate(GUIElementLocator locator, boolean visible, boolean enabled, boolean actionPending) {
730 if (actionPending) {
731 waitUntilNotBusy();
732 }
733 waitForElement(locator);
734 waitForInForeground(locator);
735 if (visible) {
736 waitForVisible(locator);
737 }
738 if (enabled) {
739 waitForEnabled(locator);
740 }
741 highlight(locator);
742 }
743
744 private void doAfterDelegate(int taskCompletionTimeout, String failureMessage) {
745 if (taskCompletionTimeout >= 0) {
746 int timeout = (taskCompletionTimeout == 0 ? configuration.getTaskCompletionTimeout() : taskCompletionTimeout);
747 TaskCompletionUtil.waitForActivityAndCompletion(systemConnector, failureMessage,
748 configuration.getTaskStartTimeout(), timeout, configuration.getTaskPollingInterval());
749 }
750 }
751
752 private void waitUntilNotBusy() {
753 if (this.systemConnector != null) {
754 TaskCompletionUtil.waitUntilNotBusy(this.systemConnector, configuration.getTaskCompletionTimeout(),
755 configuration.getTaskPollingInterval(), "System not available");
756 }
757 }
758
759 private void sleepBetweenRetries() {
760 try {
761 Thread.sleep(configuration.getPauseBetweenRetries());
762 } catch (InterruptedException e) {
763 throw new TechnicalException("Interrupted while waiting", e);
764 }
765 }
766
767 private boolean isCalledBy(Class<?> klass) {
768 boolean calledBy = false;
769 String fullLinkClassName = klass.getName();
770 StackTraceElement[] traceElements = Thread.currentThread().getStackTrace();
771 for (int i = 0; i < traceElements.length && !calledBy; i++) {
772 String fullClassName = traceElements[i].getClassName();
773 if (fullLinkClassName.equals(fullClassName)) {
774 calledBy = true;
775 }
776 }
777 return calledBy;
778 }
779
780 private boolean isCalledByLink() {
781 return isCalledBy(LinkImpl.class);
782 }
783
784 private void waitForWindow(final WindowLocator windowLocator) {
785 boolean windowIsFound = retryUntilTimeout(new ConditionCheck() {
786 @Override
787 public boolean eval() {
788 if (windowLocator instanceof TitleLocator) {
789 String requestedTitle = ((TitleLocator) windowLocator).getTitle();
790 String[] titles = getAllWindowTitles();
791 for (String title : titles) {
792 if (title.equalsIgnoreCase(requestedTitle)) {
793 return true;
794 }
795 }
796 return false;
797 } else {
798 throw ServiceUtil.newUnsupportedLocatorException(windowLocator);
799 }
800 }
801 });
802 if (!windowIsFound) {
803 throw new AutomationException("Window not found");
804 }
805 }
806
807 public void waitForWindowToBeClosed(final WindowLocator windowLocator, int taskCompletionTimeout) {
808 ConditionCheck check = new ConditionCheck() {
809 @Override
810 public boolean eval() {
811 if (windowLocator instanceof TitleLocator) {
812 String requestedTitle = ((TitleLocator) windowLocator).getTitle();
813 String[] titles = getAllWindowTitles();
814 for (String title : titles) {
815 if (title.equalsIgnoreCase(requestedTitle)) {
816 return false;
817 }
818 }
819 return true;
820 }
821 else {
822 throw ServiceUtil.newUnsupportedLocatorException(windowLocator);
823 }
824 }
825 };
826 boolean windowIsGone;
827 if (taskCompletionTimeout > -1) {
828 windowIsGone = retryUntilTrueOrTimeout(check, taskCompletionTimeout);
829 }
830 else {
831 windowIsGone = retryUntilTimeout(check);
832 }
833 if (!windowIsGone) {
834 throw new PerformanceFailure("Window not closed within timeout");
835 }
836 }
837
838 private void callWindowCommand(WindowLocator locator, WindowCommand command) {
839 waitForWindow(locator);
840 command.call(locator);
841 }
842
843 private Attachment getScreenshotAttachment(String base64Data) {
844 Base64 base64 = new Base64();
845 byte[] decodedData = base64.decode(base64Data);
846 String suffix = configuration.getScreenshotAttachmentExtension();
847 return new BinaryAttachment("Screenshot", decodedData, suffix);
848 }
849
850
851
852 private void closeApplicationUnderTest() {
853 if (configuration.getCloseTestappAfterExecution()) {
854 selenium.stop();
855 }
856 }
857
858 }