1
2
3 package com.atlassian.selenium;
4
5 import com.atlassian.selenium.keyboard.KeyEvent;
6 import com.atlassian.selenium.keyboard.KeyEventSequence;
7 import com.atlassian.selenium.visualcomparison.ScreenElement;
8 import com.atlassian.selenium.visualcomparison.utils.ScreenResolution;
9 import com.atlassian.webtest.ui.keys.KeyEventType;
10 import com.google.gson.Gson;
11 import com.google.gson.GsonBuilder;
12 import com.google.gson.reflect.TypeToken;
13 import com.thoughtworks.selenium.DefaultSelenium;
14
15 import java.io.BufferedReader;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.InputStreamReader;
19 import java.lang.reflect.Type;
20 import java.util.Collection;
21 import java.util.EnumSet;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.Set;
25
26
27
28
29
30 public class SingleBrowserSeleniumClient extends DefaultSelenium implements SeleniumClient
31 {
32
33 private Browser browser;
34
35 private Map<String, KeyEventSequence> characterKeySequenceMap = new HashMap<String, KeyEventSequence>();
36
37 private static final Set<KeyEventType> ALL_EVENTS = EnumSet.allOf(KeyEventType.class);
38
39
40
41
42
43 protected final long PAGE_LOAD_WAIT;
44
45
46
47
48
49 protected final long ACTION_WAIT;
50
51 public SingleBrowserSeleniumClient(SeleniumConfiguration config)
52 {
53 super(new HtmlDumpingHttpCommandProcessor(config.getServerLocation(), config.getServerPort(), config.getBrowserStartString(), config.getBaseUrl()));
54
55 this.PAGE_LOAD_WAIT = config.getPageLoadWait();
56 this.ACTION_WAIT = config.getActionWait();
57
58 browser = Browser.typeOf(config.getBrowserStartString());
59 }
60
61 public Browser getBrowser()
62 {
63 return browser;
64 }
65
66 public void seleniumKeyPress(String locator, String key) {
67 super.keyPress(locator, key);
68 }
69
70
71
72
73
74 public void open(String url)
75 {
76 open(url, PAGE_LOAD_WAIT);
77 }
78
79
80
81
82
83
84 public void openNoWait(String url)
85 {
86 super.open(url);
87 }
88
89
90
91
92 public void open(String url, long timeoutMillis)
93 {
94 super.open(url);
95 super.waitForPageToLoad(String.valueOf(timeoutMillis));
96 }
97
98
99
100
101 public void waitForPageToLoad(long timeoutMillis)
102 {
103 super.waitForPageToLoad(String.valueOf(timeoutMillis));
104 }
105
106
107
108
109 public void waitForPageToLoad()
110 {
111 waitForPageToLoad(PAGE_LOAD_WAIT);
112 }
113
114
115
116
117
118
119 public void waitForCondition(String javascript)
120 {
121 waitForCondition(javascript, ACTION_WAIT);
122 }
123
124
125
126
127
128 public void waitForCondition(String javascript, long timeoutMillis)
129 {
130 waitForCondition(javascript, Long.toString(timeoutMillis));
131 }
132
133
134
135
136
137
138 public void waitForAjaxWithJquery()
139 {
140 waitForAjaxWithJquery(ACTION_WAIT);
141 }
142
143
144
145
146
147 public void waitForAjaxWithJquery(long timeoutMillis)
148 {
149 if (!hasJquery())
150 {
151 throw new UnsupportedOperationException("This operation requires jQuery.");
152 }
153 waitForCondition("selenium.browserbot.getCurrentWindow().jQuery.active == 0;", Long.toString(timeoutMillis));
154 }
155
156
157
158
159
160
161
162
163
164 public void click(String locator, boolean waitForPageToLoad)
165 {
166 super.click(locator);
167 if (waitForPageToLoad)
168 super.waitForPageToLoad(String.valueOf(PAGE_LOAD_WAIT));
169 }
170
171
172
173
174
175
176
177
178
179 public void submit(String form, boolean waitForPageToLoad)
180 {
181 super.submit(form);
182 if (waitForPageToLoad)
183 super.waitForPageToLoad(String.valueOf(PAGE_LOAD_WAIT));
184 }
185
186
187
188
189
190
191
192
193
194
195
196 public void click(String locator, long timeoutMillis)
197 {
198 super.click(locator);
199 super.waitForPageToLoad(Long.toString(timeoutMillis));
200 }
201
202
203
204
205
206
207 public void clickAndWaitForAjaxWithJquery(String locator)
208 {
209 super.click(locator);
210 waitForAjaxWithJquery();
211 }
212
213
214
215
216
217
218
219
220 public void clickAndWaitForAjaxWithJquery(String locator, long timeoutMillis)
221 {
222 super.click(locator);
223 waitForAjaxWithJquery(timeoutMillis);
224 }
225
226
227
228
229
230
231
232
233
234
235
236 public void submit(String form, long timeoutMillis)
237 {
238 super.submit(form);
239 super.waitForPageToLoad(Long.toString(timeoutMillis));
240 }
241
242
243
244
245
246
247 public void keyPress(String locator, String key)
248 {
249 super.keyDown(locator, key);
250 super.keyPress(locator, key);
251 super.keyUp(locator, key);
252 }
253
254
255
256
257
258
259
260
261
262 public void typeWithFullKeyEvents(String locator, String string, boolean reset)
263 {
264 new SeleniumKeyHandler(this, locator, ALL_EVENTS, reset).typeWithFullKeyEvents(string);
265 }
266
267
268
269
270
271
272
273
274 public void typeWithFullKeyEvents(String locator, String string)
275 {
276 typeWithFullKeyEvents(locator, string, true);
277 }
278
279 public void simulateKeyPressForCharacter(final String locator, final Character character)
280 {
281 simulateKeyPressForCharacter(locator,character, ALL_EVENTS);
282 }
283
284 public void simulateKeyPressForCharacter(final String locator, final Character character, Collection<KeyEventType> eventsToFire)
285 {
286 simulateKeyPressForIdentifier(locator,character.toString(), eventsToFire);
287 }
288
289 public void simulateKeyPressForSpecialKey(final String locator, final int keyCode)
290 {
291 simulateKeyPressForSpecialKey(locator,keyCode, ALL_EVENTS);
292 }
293
294 public void simulateKeyPressForSpecialKey(final String locator, final int keyCode, Collection<KeyEventType> eventsToFire)
295 {
296 simulateKeyPressForIdentifier(locator,String.format("0x%x",keyCode), eventsToFire);
297 }
298
299 public void generateKeyEvent(final String locator, final KeyEventType eventType, final int keyCode, final int characterCode,
300 final boolean shiftKey, final boolean altKey, final boolean controlKey, final boolean metaKey)
301 {
302 getEval("selenium.generateKeyEvent(\""+locator+"\",'"
303 +eventType.getEventString()+"',"
304 +Integer.toString(keyCode)+","
305 +Integer.toString(characterCode)+","
306 +Boolean.TRUE.toString()+","
307 +Boolean.toString(shiftKey)+","
308 +Boolean.toString(altKey)+","
309 +Boolean.toString(controlKey)+","
310 +Boolean.toString(metaKey)+")");
311 }
312
313 private void simulateKeyPressForIdentifier(final String locator, final String identifier, Collection<KeyEventType> eventsToFire)
314 {
315 if (characterKeySequenceMap.containsKey(identifier))
316 {
317 for (KeyEvent ke : characterKeySequenceMap.get(identifier).getKeyEvents())
318 {
319 if (!ke.getBrowsers().contains(this.browser))
320 {
321 continue;
322 }
323 if (!eventsToFire.contains(ke.getEventType()))
324 {
325 continue;
326 }
327 int keyCode = 0;
328 int characterCode = 0;
329 if (ke.isToCharacterCode())
330 {
331 characterCode = ke.getCode();
332 }
333 if (ke.isToKeyCode())
334 {
335 keyCode = ke.getCode();
336 }
337 generateKeyEvent(locator,ke.getEventType(),keyCode,characterCode, ke.isCtrlKeyDown(),ke.isAltKeyDown(),
338 ke.isShiftKeyDown(),ke.isMetaKey());
339 }
340 }
341 }
342
343 private void toggleShiftKey(boolean keyIsPressed)
344 {
345 if (keyIsPressed)
346 {
347 super.shiftKeyDown();
348 }
349 else
350 {
351 super.shiftKeyUp();
352 }
353 }
354
355 private void toggleAltKey(boolean keyIsPressed)
356 {
357 if (keyIsPressed)
358 {
359 super.altKeyDown();
360 }
361 else
362 {
363 super.altKeyUp();
364 }
365 }
366
367 private void toggleControlKey(boolean keyIsPressed)
368 {
369 if (keyIsPressed)
370 {
371 super.controlKeyDown();
372 }
373 else
374 {
375 super.controlKeyUp();
376 }
377 }
378
379 private void toggleMetaKey(boolean keyIsPressed)
380 {
381 if (keyIsPressed)
382 {
383 super.metaKeyDown();
384 }
385 else
386 {
387 super.metaKeyUp();
388 }
389
390 }
391
392 public void toggleToKeyCode(boolean toKeyCode)
393 {
394 super.getEval("this.browserbot.toKeyCode = "+toKeyCode+";");
395 }
396
397 public void toggleToCharacterCode(boolean toCharacterCode)
398 {
399 super.getEval("this.browserbot.toCharacterCode = "+toCharacterCode+";");
400 }
401
402
403
404
405
406
407
408 public void selectOption(String selectName, String label)
409 {
410
411
412
413 String[] options = super.getSelectOptions(selectName);
414 int i = 0;
415 for(; i < options.length; i++)
416 {
417 if(options[i].trim().equals(label))
418 {
419 break;
420 }
421 }
422 if(i < options.length)
423 {
424 super.select(selectName, options[i]);
425 }
426 }
427
428
429
430
431
432
433
434
435 public void selectOptionAndWaitForAjaxWithJquery(String selectName, String label)
436 {
437 this.selectOption(selectName, label);
438 this.waitForAjaxWithJquery();
439 }
440
441
442
443
444 public void check(String name, String value)
445 {
446 check("name=" + name + " value=" + value);
447 }
448
449 public void clickLinkWithText(String text, boolean waitForPageToLoad)
450 {
451 super.click("link=" + text);
452 if (waitForPageToLoad) waitForPageToLoad();
453 }
454
455 public void clickButton(String buttonText, boolean waitForPageToLoad)
456 {
457 clickElementWithXpath("//input[@value = '" + buttonText + "']");
458 if (waitForPageToLoad) waitForPageToLoad();
459 }
460
461 public void clickButtonAndWaitForAjaxWithJquery(String buttonText)
462 {
463 this.clickButton(buttonText, false);
464 waitForAjaxWithJquery();
465 }
466
467 public void clickButtonWithName(String buttonName, boolean waitForPageToLoad)
468 {
469 clickElementWithXpath("//input[@name = '" + buttonName + "']");
470 if (waitForPageToLoad) waitForPageToLoad();
471 }
472
473 public void clickButtonWithNameAndWaitForAjaxWithJquery(String buttonName)
474 {
475 this.clickButtonWithName(buttonName, false);
476 waitForAjaxWithJquery();
477 }
478
479 public void clickElementWithTitle(String title)
480 {
481 super.click("xpath=//*[@title='" + title + "']");
482 }
483
484 public void clickElementWithTitleAndWaitForAjaxWithJquery(String title)
485 {
486 this.clickElementWithTitle(title);
487 waitForAjaxWithJquery();
488 }
489
490 public void clickElementWithClass(String className)
491 {
492 super.click("css=." + className);
493 }
494
495 public void clickElementWithClassAndWaitForAjaxWithJquery(String className)
496 {
497 this.clickElementWithClass(className);
498 waitForAjaxWithJquery();
499 }
500
501 public void clickElementWithCss(String cssSelector)
502 {
503 super.click("css=" + cssSelector);
504 }
505
506 public void clickElementWithCssAndWaitForAjaxWithJquery(String cssSelector)
507 {
508 this.clickElementWithCss(cssSelector);
509 waitForAjaxWithJquery();
510 }
511
512 public void clickElementWithXpath(String xpath)
513 {
514 super.click("xpath=" + xpath);
515 }
516
517 public void clickElementWithXpathAndWaitForAjaxWithJquery(String xpath)
518 {
519 this.clickElementWithXpath(xpath);
520 waitForAjaxWithJquery();
521 }
522
523 public void typeInElementWithName(String elementName, String text)
524 {
525 super.type("name=" + elementName, text);
526 }
527
528 public void typeInElementWithCss(String cssSelector, String text)
529 {
530 super.type("css=" + cssSelector, text);
531 }
532
533 public boolean hasJquery()
534 {
535 String evalJquery = getEval("selenium.browserbot.getCurrentWindow().jQuery");
536 return evalJquery != null && !"null".equals(evalJquery) && !"undefined".equals(evalJquery);
537 }
538
539 private void addJqueryLocator() throws IOException
540 {
541 String jqueryImpl = readFile("jquery-1.4.2.min.js");
542 String jqueryLocStrategy = readFile("jquery-locationStrategy.js");
543
544 addScript(jqueryImpl, "jquery");
545 addLocationStrategy("jquery", jqueryLocStrategy );
546 }
547
548 private void addKeyPressJSCorrections() throws IOException
549 {
550 String keyPressCorrectionsImpl = readFile("KeyPressCorrected.js");
551 String generateKeyPressImpl = readFile("generateKeyEvent.js");
552 addScript(keyPressCorrectionsImpl, "KeyPressCorrected");
553 addScript(generateKeyPressImpl, "generateKeyEvent");
554 }
555
556 private void loadCharacterKeyEventMap() throws IOException
557 {
558 Gson gson = new GsonBuilder().create();
559 String characterArrayJSON = readFile("charactersKeySequences.json");
560
561 Type collectionType = new TypeToken<HashMap<String, KeyEventSequence>>(){}.getType();
562 characterKeySequenceMap = gson.fromJson(characterArrayJSON,collectionType);
563 characterKeySequenceMap.put(" ",characterKeySequenceMap.get(String.format("0x%x",java.awt.event.KeyEvent.VK_SPACE)));
564 characterKeySequenceMap.put("\n",characterKeySequenceMap.get(String.format("0x%x",java.awt.event.KeyEvent.VK_ENTER)));
565 }
566
567 private void addTagNameScripts() throws IOException
568 {
569 String tagNames = readFile("tag-name.js");
570 addScript(tagNames, "seleniumTagNames");
571 }
572
573 private static String readFile(String file) throws IOException
574 {
575 InputStream stream = SingleBrowserSeleniumClient.class.getClassLoader().getResourceAsStream(file);
576 BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
577
578 String line = reader.readLine();
579 StringBuffer contents = new StringBuffer();
580
581 while(line != null)
582 {
583 contents.append(line).append("\n");
584 line = reader.readLine();
585 }
586
587 return contents.toString();
588 }
589
590 public void start()
591 {
592 super.start();
593 try
594 {
595 addJqueryLocator();
596 loadCharacterKeyEventMap();
597 addKeyPressJSCorrections();
598 addTagNameScripts();
599 }
600 catch (IOException ioe)
601 {
602 System.err.println("Unable to load JQuery locator strategy: " + ioe);
603 ioe.printStackTrace(System.err);
604 }
605
606 }
607
608 public void evaluate (String command)
609 {
610 execute(command);
611 }
612
613
614
615
616
617
618
619 public Object execute(String command, Object... arguments)
620 {
621
622 return this.getEval(command);
623 }
624
625 public void captureEntirePageScreenshot (String filePath)
626 {
627
628 this.captureEntirePageScreenshot(filePath, "");
629 }
630
631 public boolean resizeScreen(ScreenResolution resolution, boolean refreshAfterResize)
632 {
633 final String result = this.getEval("selenium.browserbot.getCurrentWindow().resizeTo(" + resolution.width + ", " + resolution.height + ");");
634 if (refreshAfterResize) refreshAndWait();
635 return true;
636 }
637
638 public void refreshAndWait ()
639 {
640
641 this.refresh();
642 this.waitForPageToLoad();
643 }
644
645
646
647
648
649
650 public boolean waitForJQuery (long waitTimeMillis)
651 {
652 try
653 {
654 this.waitForCondition("selenium.browserbot.getCurrentWindow().jQuery.active == 0;", Long.toString(waitTimeMillis));
655 Thread.sleep(400);
656 }
657 catch (InterruptedException e)
658 {
659 return false;
660 }
661 return true;
662 }
663
664 @Override
665 public ScreenElement getElementAtPoint(int x, int y)
666 {
667 throw new UnsupportedOperationException("Not implemented");
668 }
669 }