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