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