selenium-webdriver 0.0.17 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
  2. data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
  3. data/chrome/src/extension/background.js +64 -48
  4. data/chrome/src/extension/content_script.js +253 -132
  5. data/chrome/src/extension/manifest-nonwin.json +1 -1
  6. data/chrome/src/extension/manifest-win.json +1 -1
  7. data/chrome/src/extension/utils.js +8 -8
  8. data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +9 -0
  9. data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +38 -280
  10. data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +119 -117
  11. data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +36 -26
  12. data/common/src/js/abstractcommandprocessor.js +9 -11
  13. data/common/src/js/command.js +159 -83
  14. data/common/src/js/core/RemoteRunner.html +2 -2
  15. data/common/src/js/core/TestRunner-splash.html +3 -3
  16. data/common/src/js/core/TestRunner.html +5 -17
  17. data/common/src/js/core/scripts/htmlutils.js +4208 -2506
  18. data/common/src/js/core/scripts/selenium-api.js +2 -2
  19. data/common/src/js/core/scripts/selenium-browserbot.js +66 -58
  20. data/common/src/js/core/scripts/selenium-version.js +1 -1
  21. data/common/src/js/localcommandprocessor.js +5 -19
  22. data/common/src/js/testcase.js +2 -0
  23. data/common/src/js/webdriver.js +63 -93
  24. data/common/src/js/webelement.js +40 -42
  25. data/common/src/rb/lib/selenium/webdriver.rb +23 -14
  26. data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +8 -35
  27. data/common/src/rb/lib/selenium/webdriver/child_process.rb +2 -0
  28. data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +1 -0
  29. data/common/src/rb/lib/selenium/webdriver/core_ext/string.rb +5 -0
  30. data/common/src/rb/lib/selenium/webdriver/driver.rb +20 -15
  31. data/common/src/rb/lib/selenium/webdriver/driver_extensions/takes_screenshot.rb +7 -2
  32. data/common/src/rb/lib/selenium/webdriver/element.rb +11 -2
  33. data/common/src/rb/lib/selenium/webdriver/error.rb +9 -5
  34. data/common/src/rb/lib/selenium/webdriver/keys.rb +1 -2
  35. data/common/src/rb/lib/selenium/webdriver/navigation.rb +16 -0
  36. data/common/src/rb/lib/selenium/webdriver/options.rb +32 -0
  37. data/common/src/rb/lib/selenium/webdriver/platform.rb +17 -1
  38. data/firefox/prebuilt/Win32/Release/webdriver-firefox.dll +0 -0
  39. data/firefox/src/extension/components/dispatcher.js +492 -0
  40. data/firefox/src/extension/components/driver-component.js +4 -1
  41. data/firefox/src/extension/components/errorcode.js +70 -0
  42. data/firefox/src/extension/components/firefoxDriver.js +173 -154
  43. data/firefox/src/extension/components/nsCommandProcessor.js +171 -132
  44. data/firefox/src/extension/components/promptService.js +5 -5
  45. data/firefox/src/extension/components/request.js +219 -0
  46. data/firefox/src/extension/components/response.js +276 -0
  47. data/firefox/src/extension/components/session.js +281 -0
  48. data/firefox/src/extension/components/sessionstore.js +226 -0
  49. data/firefox/src/extension/components/socketListener.js +350 -100
  50. data/firefox/src/extension/components/utils.js +166 -98
  51. data/firefox/src/extension/components/webdriverserver.js +9 -5
  52. data/firefox/src/extension/components/wrappedElement.js +189 -166
  53. data/firefox/src/extension/install.rdf +1 -1
  54. data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +2 -0
  55. data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +39 -33
  56. data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +7 -421
  57. data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +7 -64
  58. data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +2 -3
  59. data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +54 -10
  60. data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +2 -0
  61. data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +6 -0
  62. data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
  63. data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
  64. data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +2 -0
  65. data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +38 -13
  66. data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +9 -2
  67. data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +5 -0
  68. data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +2 -0
  69. data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +42 -38
  70. data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +56 -47
  71. data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +26 -26
  72. data/remote/client/src/rb/lib/selenium/webdriver/remote/patron_http_client.rb +58 -0
  73. data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +10 -12
  74. data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +2 -17
  75. metadata +44 -23
  76. data/common/src/js/context.js +0 -58
  77. data/firefox/src/extension/components/context.js +0 -37
@@ -26,9 +26,12 @@ const CONTRACT_ID = "@googlecode.com/webdriver/fxdriver;1";
26
26
  // Its copyrights belong to its original author.
27
27
 
28
28
  var ExternalScripts = [
29
- "context.js",
29
+ "errorcode.js",
30
+ "dispatcher.js",
30
31
  "firefoxDriver.js",
31
32
  "socketListener.js",
33
+ "request.js",
34
+ "response.js",
32
35
  "utils.js",
33
36
  "webdriverserver.js",
34
37
  "webLoadingListener.js",
@@ -0,0 +1,70 @@
1
+ /*
2
+ Copyright 2007-2010 WebDriver committers
3
+ Copyright 2007-2010 Google Inc.
4
+ Portions copyright 2007 ThoughtWorks, Inc
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+
20
+ /**
21
+ * Error codes used by the remote wire protocol.
22
+ * @enum {number}
23
+ */
24
+ var ErrorCode = {
25
+ // Keep in sync with codes in org.openqa.selenium.remote.ErrorCodes
26
+
27
+ SUCCESS: 0,
28
+ NO_SUCH_ELEMENT: 7,
29
+ NO_SUCH_FRAME: 8,
30
+ UNKNOWN_COMMAND: 9,
31
+ STALE_ELEMENT_REFERENCE: 10,
32
+ ELEMENT_NOT_VISIBLE: 11,
33
+ INVALID_ELEMENT_STATE: 12,
34
+ UNHANDLED_ERROR: 13,
35
+ UNEXPECTED_JAVASCRIPT_ERROR: 17,
36
+ XPATH_LOOKUP_ERROR: 19,
37
+ NO_SUCH_WINDOW: 23,
38
+ INVALID_COOKIE_DOMAIN: 24,
39
+ UNABLE_TO_SET_COOKIE: 25
40
+ };
41
+
42
+
43
+ /**
44
+ * Converts an Error object to a JSON object compatible with WebDriver's remote
45
+ * wire protocol.
46
+ * @param {Error} ex The thrown error to convert.
47
+ * @return {Object} The converted object.
48
+ */
49
+ ErrorCode.toJSON = function(ex) {
50
+ var stackFrames = [];
51
+ var json = {
52
+ 'message': ex.message ? ex.message : ex.toString(),
53
+ 'stackTrace': stackFrames,
54
+ };
55
+
56
+ if (ex.stack) {
57
+ var stack = ex.stack.replace(/\s*$/, '').split('\n');
58
+
59
+ for (var frame = stack.shift(); frame; frame = stack.shift()) {
60
+ var match = frame.match(/^([a-zA-Z_$][\w]*)?(?:\(.*\))?@(.+)?:(\d*)$/);
61
+ stackFrames.push({
62
+ 'methodName': match[1],
63
+ 'fileName': match[2],
64
+ 'lineNumber': Number(match[3])
65
+ });
66
+ }
67
+ }
68
+
69
+ return json;
70
+ };
@@ -17,15 +17,27 @@
17
17
  */
18
18
 
19
19
 
20
- function FirefoxDriver(server, enableNativeEvents) {
20
+ function FirefoxDriver(server, enableNativeEvents, win) {
21
21
  this.server = server;
22
- this.mouseSpeed = 1;
23
22
  this.enableNativeEvents = enableNativeEvents;
23
+ this.window = win;
24
24
 
25
25
  this.currentX = 0;
26
26
  this.currentY = 0;
27
27
  }
28
28
 
29
+
30
+ /**
31
+ * Enumeration of supported speed values.
32
+ * @enum {number}
33
+ */
34
+ FirefoxDriver.Speed = {
35
+ SLOW: 1,
36
+ MEDIUM: 10,
37
+ FAST: 100
38
+ };
39
+
40
+
29
41
  FirefoxDriver.prototype.__defineGetter__("id", function() {
30
42
  if (!this.id_) {
31
43
  this.id_ = this.server.getNextId();
@@ -36,15 +48,16 @@ FirefoxDriver.prototype.__defineGetter__("id", function() {
36
48
 
37
49
 
38
50
  FirefoxDriver.prototype.getCurrentWindowHandle = function(respond) {
39
- respond.response = this.id;
51
+ respond.value = this.id;
40
52
  respond.send();
41
53
  };
42
54
 
43
55
 
44
- FirefoxDriver.prototype.get = function(respond, url) {
56
+ FirefoxDriver.prototype.get = function(respond, parameters) {
57
+ var url = parameters.url;
45
58
  // Check to see if the given url is the same as the current one, but
46
59
  // with a different anchor tag.
47
- var current = Utils.getBrowser(respond.context).contentWindow.location;
60
+ var current = respond.session.getWindow().location;
48
61
  var ioService =
49
62
  Utils.getService("@mozilla.org/network/io-service;1", "nsIIOService");
50
63
  var currentUri = ioService.newURI(current, "", null);
@@ -62,16 +75,17 @@ FirefoxDriver.prototype.get = function(respond, url) {
62
75
  }
63
76
 
64
77
  if (loadEventExpected) {
65
- new WebLoadingListener(Utils.getBrowser(respond.context), function() {
78
+ new WebLoadingListener(respond.session.getBrowser(), function() {
66
79
  // TODO: Rescue the URI and response code from the event
67
80
  var responseText = "";
68
- respond.context.frameId = "?";
69
- respond.response = responseText;
81
+ // Focus on the top window.
82
+ respond.session.setWindow(respond.session.getBrowser().contentWindow);
83
+ respond.value = responseText;
70
84
  respond.send();
71
85
  });
72
86
  }
73
87
 
74
- Utils.getBrowser(respond.context).loadURI(url);
88
+ respond.session.getBrowser().loadURI(url);
75
89
 
76
90
  if (!loadEventExpected) {
77
91
  respond.send();
@@ -89,13 +103,17 @@ FirefoxDriver.prototype.close = function(respond) {
89
103
 
90
104
  // Here we go!
91
105
  try {
92
- var browser = Utils.getBrowser(respond.context);
106
+ var browser = respond.session.getBrowser();
93
107
  createSwitchFile("close:" + browser.id);
94
108
  browser.contentWindow.close();
95
109
  } catch(e) {
96
110
  dump(e);
97
111
  }
98
112
 
113
+ // Send the response so the client doesn't get a connection refused socket
114
+ // error.
115
+ respond.send();
116
+
99
117
  // If we're on a Mac we might have closed all the windows but not quit, so
100
118
  // ensure that we do actually quit :)
101
119
  var allWindows = wm.getEnumerator("navigator:browser");
@@ -103,18 +121,13 @@ FirefoxDriver.prototype.close = function(respond) {
103
121
  appService.quit(forceQuit);
104
122
  return; // The client should catch the fact that the socket suddenly closes
105
123
  }
106
-
107
- // If we're still running, return
108
- respond.send();
109
124
  };
110
125
 
111
126
 
112
- FirefoxDriver.prototype.executeScript = function(respond, script) {
113
- var doc = Utils.getDocument(respond.context);
114
- var window = doc ? doc.defaultView :
115
- Utils.getBrowser(respond.context).contentWindow;
127
+ FirefoxDriver.prototype.executeScript = function(respond, parameters) {
128
+ var window = respond.session.getWindow();
129
+ var doc = window.document;
116
130
 
117
- var parameters = new Array();
118
131
  var runScript;
119
132
 
120
133
  // Pre 2.0.0.15
@@ -123,11 +136,11 @@ FirefoxDriver.prototype.executeScript = function(respond, script) {
123
136
  return window.eval(scriptSrc);
124
137
  };
125
138
  } else {
126
- runScript = function(scriptSrc) {
139
+ runScript = function(scriptSrc, args) {
127
140
  window = window.wrappedJSObject;
128
141
  var sandbox = new Components.utils.Sandbox(window);
129
142
  sandbox.window = window;
130
- sandbox.__webdriverParams = parameters;
143
+ sandbox.__webdriverParams = args;
131
144
  sandbox.document = window.document;
132
145
  sandbox.unsafeWindow = window;
133
146
  sandbox.__proto__ = window;
@@ -136,48 +149,44 @@ FirefoxDriver.prototype.executeScript = function(respond, script) {
136
149
  };
137
150
  }
138
151
 
152
+ var converted = Utils.unwrapParameters(
153
+ parameters.args, respond.session.getDocument());
154
+
139
155
  try {
140
- var scriptSrc = "var __webdriverFunc = function(){" + script.shift()
156
+ var scriptSrc = "var __webdriverFunc = function(){" + parameters.script
141
157
  + "}; __webdriverFunc.apply(window, __webdriverParams);";
142
-
143
- var convert = script.shift();
144
-
145
- Utils.unwrapParameters(convert, parameters, respond.context);
146
-
147
- var result = runScript(scriptSrc, parameters);
148
-
149
- respond.response = Utils.wrapResult(result, respond.context);
150
-
158
+ var result = runScript(scriptSrc, converted);
151
159
  } catch (e) {
152
- respond.isError = true;
153
- respond.response = e;
160
+ Utils.dumpn(JSON.stringify(e));
161
+ throw new WebDriverError(ErrorCode.UNEXPECTED_JAVASCRIPT_ERROR, e);
154
162
  }
163
+
164
+ respond.value = Utils.wrapResult(result, respond.session.getDocument());
155
165
  respond.send();
156
166
  };
157
167
 
158
168
 
159
169
  FirefoxDriver.prototype.getCurrentUrl = function(respond) {
160
- var url = Utils.getDocument(respond.context).defaultView.location;
170
+ var url = respond.session.getWindow().location;
161
171
  if (!url) {
162
- url = Utils.getBrowser(respond.context).contentWindow.location;
172
+ url = respond.session.getBrowser().contentWindow.location;
163
173
  }
164
- respond.response = "" + url;
174
+ respond.value = "" + url;
165
175
  respond.send();
166
176
  };
167
177
 
168
178
 
169
- FirefoxDriver.prototype.title = function(respond) {
170
- var browser = Utils.getBrowser(respond.context);
171
- respond.response = browser.contentTitle;
179
+ FirefoxDriver.prototype.getTitle = function(respond) {
180
+ respond.value = respond.session.getBrowser().contentTitle;
172
181
  respond.send();
173
182
  };
174
183
 
175
184
 
176
185
  FirefoxDriver.prototype.getPageSource = function(respond) {
177
- var source = Utils.getDocument(respond.context).
186
+ var source = respond.session.getDocument().
178
187
  getElementsByTagName("html")[0].innerHTML;
179
188
 
180
- respond.response = "<html>" + source + "</html>";
189
+ respond.value = "<html>" + source + "</html>";
181
190
  respond.send();
182
191
  };
183
192
 
@@ -278,9 +287,9 @@ FirefoxDriver.ElementLocator = {
278
287
  FirefoxDriver.prototype.findElementInternal_ = function(respond, method,
279
288
  selector,
280
289
  opt_parentElementId) {
281
- var theDocument = Utils.getDocument(respond.context);
290
+ var theDocument = respond.session.getDocument();
282
291
  var rootNode = typeof opt_parentElementId == 'string' ?
283
- Utils.getElementAt(opt_parentElementId, respond.context) : theDocument;
292
+ Utils.getElementAt(opt_parentElementId, theDocument) : theDocument;
284
293
 
285
294
  var element;
286
295
  switch (method) {
@@ -310,10 +319,9 @@ FirefoxDriver.prototype.findElementInternal_ = function(respond, method,
310
319
  if (rootNode['querySelector']) {
311
320
  element = rootNode.querySelector(selector);
312
321
  } else {
313
- respond.isError = true;
314
- respond.response = "CSS Selectors not supported natively";
315
- respond.send();
316
- }
322
+ throw new WebDriverError(ErrorCode.UNKNOWN_COMMAND,
323
+ "CSS Selectors not supported natively");
324
+ }
317
325
  break;
318
326
 
319
327
  case FirefoxDriver.ElementLocator.TAG_NAME:
@@ -340,22 +348,22 @@ FirefoxDriver.prototype.findElementInternal_ = function(respond, method,
340
348
  break;
341
349
 
342
350
  default:
343
- respond.response = 'Unsupported element locator method: ' + method;
344
- respond.isError = true;
345
- respond.send();
351
+ throw new WebDriverError(ErrorCode.UNKNOWN_COMMAND,
352
+ 'Unsupported element locator method: ' + method);
346
353
  return;
347
354
  }
348
355
 
349
356
  if (element) {
350
- respond.response = Utils.addToKnownElements(element, respond.context);
357
+ var id = Utils.addToKnownElements(element, respond.session.getDocument());
358
+ respond.value = {'ELEMENT': id};
359
+ respond.send();
351
360
  } else {
352
- respond.response = 'Unable to locate element: ' + JSON.stringify({
353
- method: method,
354
- selector: selector
355
- });
356
- respond.isError = true;
361
+ throw new WebDriverError(ErrorCode.NO_SUCH_ELEMENT,
362
+ 'Unable to locate element: ' + JSON.stringify({
363
+ method: method,
364
+ selector: selector
365
+ }));
357
366
  }
358
- respond.send();
359
367
  };
360
368
 
361
369
 
@@ -363,12 +371,14 @@ FirefoxDriver.prototype.findElementInternal_ = function(respond, method,
363
371
  * Finds an element on the current page. The response value will be the UUID of
364
372
  * the located element, or an error message if an element could not be found.
365
373
  * @param {Response} respond Object to send the command response with.
366
- * @param {Array.<string>} parameters A two-element array: the first element
367
- * should be a method listen in the {@code Firefox.ElementLocator} enum, and
368
- * the second should be what to search for.
374
+ * @param {{using: string, value: string}} parameters A JSON object
375
+ * specifying the search parameters:
376
+ * - using: A method to search with, as defined in the
377
+ * {@code Firefox.ElementLocator} enum.
378
+ * - value: What to search for.
369
379
  */
370
380
  FirefoxDriver.prototype.findElement = function(respond, parameters) {
371
- this.findElementInternal_(respond, parameters[0], parameters[1]);
381
+ this.findElementInternal_(respond, parameters.using, parameters.value);
372
382
  };
373
383
 
374
384
 
@@ -377,17 +387,15 @@ FirefoxDriver.prototype.findElement = function(respond, parameters) {
377
387
  * search parameter. The response value will be the UUID of the located element,
378
388
  * or an error message if an element could not be found.
379
389
  * @param {Response} respond Object to send the command response with.
380
- * @param {Array.<{id:string, using:string, value:string}>} parameters A single
381
- * element array. The array element should define what to search for with
382
- * the following fields:
390
+ * @param {{id: string, using: string, value: string}} parameters A JSON object
391
+ * specifying the search parameters:
383
392
  * - id: UUID of the element to base the search from.
384
393
  * - using: A method to search with, as defined in the
385
394
  * {@code Firefox.ElementLocator} enum.
386
395
  * - value: What to search for.
387
396
  */
388
397
  FirefoxDriver.prototype.findChildElement = function(respond, parameters) {
389
- var map = parameters[0];
390
- this.findElementInternal_(respond, map.using, map.value, map.id);
398
+ this.findElementInternal_(respond, parameters.using, parameters.value, parameters.id);
391
399
  };
392
400
 
393
401
 
@@ -405,9 +413,9 @@ FirefoxDriver.prototype.findChildElement = function(respond, parameters) {
405
413
  FirefoxDriver.prototype.findElementsInternal_ = function(respond, method,
406
414
  selector,
407
415
  opt_parentElementId) {
408
- var theDocument = Utils.getDocument(respond.context);
416
+ var theDocument = respond.session.getDocument();
409
417
  var rootNode = typeof opt_parentElementId == 'string' ?
410
- Utils.getElementAt(opt_parentElementId, respond.context) : theDocument;
418
+ Utils.getElementAt(opt_parentElementId, theDocument) : theDocument;
411
419
 
412
420
  var elements;
413
421
  switch (method) {
@@ -430,9 +438,8 @@ FirefoxDriver.prototype.findElementsInternal_ = function(respond, method,
430
438
  if (rootNode['querySelector']) {
431
439
  elements = rootNode.querySelectorAll(selector);
432
440
  } else {
433
- respond.isError = true;
434
- respond.response = "CSS Selectors not supported natively";
435
- respond.send();
441
+ throw new WebDriverError(ErrorCode.UNKNOWN_COMMAND,
442
+ "CSS Selectors not supported natively");
436
443
  }
437
444
  break;
438
445
 
@@ -462,19 +469,20 @@ FirefoxDriver.prototype.findElementsInternal_ = function(respond, method,
462
469
  break;
463
470
 
464
471
  default:
465
- respond.response = 'Unsupported element locator method: ' + method;
466
- respond.isError = true;
467
- respond.send();
472
+ throw new WebDriverError(ErrorCode.UNKNOWN_COMMAND,
473
+ 'Unsupported element locator method: ' + method);
468
474
  return;
469
475
  }
470
476
 
471
477
  var elementIds = [];
472
478
  for (var j = 0; j < elements.length; j++) {
473
479
  var element = elements[j];
474
- elementIds.push(Utils.addToKnownElements(element, respond.context));
480
+ var elementId = Utils.addToKnownElements(
481
+ element, respond.session.getDocument());
482
+ elementIds.push({'ELEMENT': elementId});
475
483
  }
476
484
 
477
- respond.response = elementIds;
485
+ respond.value = elementIds;
478
486
  respond.send();
479
487
  };
480
488
 
@@ -483,12 +491,14 @@ FirefoxDriver.prototype.findElementsInternal_ = function(respond, method,
483
491
  * Searches for multiple elements on the page. The response value will be an
484
492
  * array of UUIDs for the located elements.
485
493
  * @param {Response} respond Object to send the command response with.
486
- * @param {Array.<string>} parameters A two-element array: the first element
487
- * should be the type of locator strategy to use, the second is the target
488
- * of the search.
494
+ * @param {{using: string, value: string}} parameters A JSON object
495
+ * specifying the search parameters:
496
+ * - using: A method to search with, as defined in the
497
+ * {@code Firefox.ElementLocator} enum.
498
+ * - value: What to search for.
489
499
  */
490
500
  FirefoxDriver.prototype.findElements = function(respond, parameters) {
491
- this.findElementsInternal_(respond, parameters[0], parameters[1]);
501
+ this.findElementsInternal_(respond, parameters.using, parameters.value);
492
502
  };
493
503
 
494
504
 
@@ -496,51 +506,46 @@ FirefoxDriver.prototype.findElements = function(respond, parameters) {
496
506
  * Searches for multiple elements on the page that are children of the
497
507
  * corresponding search parameter. The response value will be an array of UUIDs
498
508
  * for the located elements.
499
- * @param {Array.<{id:string, using:string, value:string}>} parameters A single
500
- * element array. The array element should define what to search for with
501
- * the following fields:
509
+ * @param {{id: string, using: string, value: string}} parameters A JSON object
510
+ * specifying the search parameters:
502
511
  * - id: UUID of the element to base the search from.
503
512
  * - using: A method to search with, as defined in the
504
513
  * {@code Firefox.ElementLocator} enum.
505
514
  * - value: What to search for.
506
515
  */
507
516
  FirefoxDriver.prototype.findChildElements = function(respond, parameters) {
508
- var map = parameters[0];
509
- this.findElementsInternal_(respond, map.using, map.value, map.id);
517
+ this.findElementsInternal_(respond, parameters.using, parameters.value, parameters.id);
510
518
  };
511
519
 
512
520
 
513
- FirefoxDriver.prototype.switchToFrame = function(respond, frameId) {
514
- var browser = Utils.getBrowser(respond.context);
515
- var frameDoc = Utils.findDocumentInFrame(browser, frameId[0]);
516
-
517
- if (frameDoc) {
518
- respond.context = new Context(respond.context.windowId, frameId[0]);
519
- respond.send();
521
+ FirefoxDriver.prototype.switchToFrame = function(respond, parameters) {
522
+ var browser = respond.session.getBrowser();
523
+ if (parameters.id == null) {
524
+ respond.session.setWindow(respond.session.getBrowser().contentWindow);
520
525
  } else {
521
- respond.isError = true;
522
- respond.response = "Cannot find frame with id: " + frameId.toString();
523
- respond.send();
526
+ var frameDoc = Utils.findDocumentInFrame(browser, parameters.id);
527
+ if (frameDoc) {
528
+ respond.session.setWindow(frameDoc.defaultView);
529
+ } else {
530
+ throw new WebDriverError(ErrorCode.NO_SUCH_FRAME,
531
+ "Cannot find frame with id: " + parameters.id);
532
+ }
524
533
  }
525
- };
526
-
527
-
528
- FirefoxDriver.prototype.switchToDefaultContent = function(respond) {
529
- respond.context.frameId = "?";
530
534
  respond.send();
531
535
  };
532
536
 
533
537
 
534
- FirefoxDriver.prototype.switchToActiveElement = function(respond) {
535
- var element = Utils.getActiveElement(respond.context);
538
+ FirefoxDriver.prototype.getActiveElement = function(respond) {
539
+ var element = Utils.getActiveElement(respond.session.getDocument());
540
+ var id = Utils.addToKnownElements(element, respond.session.getDocument());
536
541
 
537
- respond.response = Utils.addToKnownElements(element, respond.context);
542
+ respond.value = {'ELEMENT':id};
538
543
  respond.send();
539
544
  };
540
545
 
541
546
 
542
547
  FirefoxDriver.prototype.goBack = function(respond) {
543
- var browser = Utils.getBrowser(respond.context);
548
+ var browser = respond.session.getBrowser();
544
549
 
545
550
  if (browser.canGoBack) {
546
551
  browser.goBack();
@@ -551,7 +556,7 @@ FirefoxDriver.prototype.goBack = function(respond) {
551
556
 
552
557
 
553
558
  FirefoxDriver.prototype.goForward = function(respond) {
554
- var browser = Utils.getBrowser(respond.context);
559
+ var browser = respond.session.getBrowser();
555
560
 
556
561
  if (browser.canGoForward) {
557
562
  browser.goForward();
@@ -562,19 +567,23 @@ FirefoxDriver.prototype.goForward = function(respond) {
562
567
 
563
568
 
564
569
  FirefoxDriver.prototype.refresh = function(respond) {
565
- var browser = Utils.getBrowser(respond.context);
570
+ var browser = respond.session.getBrowser();
566
571
  browser.contentWindow.location.reload(true);
567
-
568
- respond.send();
572
+ // Wait for the reload to finish before sending the response.
573
+ new WebLoadingListener(respond.session.getBrowser(), function() {
574
+ // Reset to the top window.
575
+ respond.session.setWindow(browser.contentWindow);
576
+ respond.send();
577
+ });
569
578
  };
570
579
 
571
580
 
572
- FirefoxDriver.prototype.addCookie = function(respond, cookieString) {
573
- var cookie;
574
- cookie = eval('(' + cookieString[0] + ')');
581
+ FirefoxDriver.prototype.addCookie = function(respond, parameters) {
582
+ var cookie = parameters.cookie;
575
583
 
576
584
  if (cookie.expiry) {
577
- cookie.expiry = new Date(cookie.expiry);
585
+ cookie.expiry = cookie.expiry.time ? new Date(cookie.expiry.time) :
586
+ new Date(cookie.expiry);
578
587
  } else {
579
588
  var date = new Date();
580
589
  date.setYear(2030);
@@ -584,16 +593,14 @@ FirefoxDriver.prototype.addCookie = function(respond, cookieString) {
584
593
  cookie.expiry = cookie.expiry.getTime() / 1000; // Stored in seconds
585
594
 
586
595
  if (!cookie.domain) {
587
- var location = Utils.getBrowser(respond.context).contentWindow.location;
596
+ var location = respond.session.getBrowser().contentWindow.location;
588
597
  cookie.domain = location.hostname;
589
598
  } else {
590
- var currLocation = Utils.getBrowser(respond.context).contentWindow.location;
599
+ var currLocation = respond.session.getBrowser().contentWindow.location;
591
600
  var currDomain = currLocation.host;
592
601
  if (currDomain.indexOf(cookie.domain) == -1) { // Not quite right, but close enough
593
- respond.isError = true;
594
- respond.response = "You may only set cookies for the current domain";
595
- respond.send();
596
- return;
602
+ throw new WebDriverError(ErrorCode.INVALID_COOKIE_DOMAIN,
603
+ "You may only set cookies for the current domain");
597
604
  }
598
605
  }
599
606
 
@@ -604,12 +611,10 @@ FirefoxDriver.prototype.addCookie = function(respond, cookieString) {
604
611
  cookie.domain = cookie.domain.replace(/:\d+$/, "");
605
612
  }
606
613
 
607
- var document = Utils.getDocument(respond.context);
614
+ var document = respond.session.getDocument();
608
615
  if (!document || !document.contentType.match(/html/i)) {
609
- respond.isError = true;
610
- respond.response = "You may only set cookies on html documents";
611
- respond.send();
612
- return;
616
+ throw new WebDriverError(ErrorCode.UNABLE_TO_SET_COOKIE,
617
+ "You may only set cookies on html documents");
613
618
  }
614
619
 
615
620
  var cookieManager =
@@ -657,37 +662,37 @@ function getVisibleCookies(location) {
657
662
  return results;
658
663
  };
659
664
 
660
- FirefoxDriver.prototype.getCookie = function(respond) {
661
- var cookieToString = function(c) {
662
- return c.name + "=" + c.value + ";" + "domain=" + c.host + ";"
663
- + "path=" + c.path + ";" + "expires=" + c.expires + ";"
664
- + (c.isSecure ? "secure ;" : "");
665
- };
666
-
665
+ FirefoxDriver.prototype.getCookies = function(respond) {
667
666
  var toReturn = [];
668
- var cookies = getVisibleCookies(Utils.getBrowser(respond.context).
667
+ var cookies = getVisibleCookies(respond.session.getBrowser().
669
668
  contentWindow.location);
670
669
  for (var i = 0; i < cookies.length; i++) {
671
- toReturn.push(cookieToString(cookies[i]));
670
+ var cookie = cookies[i];
671
+ toReturn.push({
672
+ 'name': cookie.name,
673
+ 'value': cookie.value,
674
+ 'path': cookie.path,
675
+ 'domain': cookie.host,
676
+ 'secure': cookie.isSecure
677
+ });
672
678
  }
673
679
 
674
- respond.response = toReturn;
680
+ respond.value = toReturn;
675
681
  respond.send();
676
682
  };
677
683
 
678
684
 
679
685
  // This is damn ugly, but it turns out that just deleting a cookie from the document
680
686
  // doesn't always do The Right Thing
681
- FirefoxDriver.prototype.deleteCookie = function(respond, cookieString) {
687
+ FirefoxDriver.prototype.deleteCookie = function(respond, parameters) {
688
+ var toDelete = parameters.name;
682
689
  var cm = Utils.getService("@mozilla.org/cookiemanager;1", "nsICookieManager");
683
- // TODO(simon): Well, this is dumb. Sorry
684
- var toDelete = eval('(' + cookieString + ')');
685
690
 
686
- var cookies = getVisibleCookies(Utils.getBrowser(respond.context).
691
+ var cookies = getVisibleCookies(respond.session.getBrowser().
687
692
  contentWindow.location);
688
693
  for (var i = 0; i < cookies.length; i++) {
689
694
  var cookie = cookies[i];
690
- if (cookie.name == toDelete.name) {
695
+ if (cookie.name == toDelete) {
691
696
  cm.remove(cookie.host, cookie.name, cookie.path, false);
692
697
  }
693
698
  }
@@ -698,7 +703,7 @@ FirefoxDriver.prototype.deleteCookie = function(respond, cookieString) {
698
703
 
699
704
  FirefoxDriver.prototype.deleteAllCookies = function(respond) {
700
705
  var cm = Utils.getService("@mozilla.org/cookiemanager;1", "nsICookieManager");
701
- var cookies = getVisibleCookies(Utils.getBrowser(respond.context).
706
+ var cookies = getVisibleCookies(respond.session.getBrowser().
702
707
  contentWindow.location);
703
708
 
704
709
  for (var i = 0; i < cookies.length; i++) {
@@ -710,50 +715,64 @@ FirefoxDriver.prototype.deleteAllCookies = function(respond) {
710
715
  };
711
716
 
712
717
 
713
- FirefoxDriver.prototype.setMouseSpeed = function(respond, speed) {
714
- this.mouseSpeed = speed.shift();
718
+ FirefoxDriver.prototype.setSpeed = function(respond, parameters) {
719
+ if (!(parameters.speed in FirefoxDriver.Speed)) {
720
+ var validSpeeds = [];
721
+ for (var prop in FirefoxDriver.Speed) {
722
+ validSpeeds.push(prop);
723
+ }
724
+ throw new WebDriverError(ErrorCode.UNHANDLED_ERROR,
725
+ 'Speed value expected to be one of ' + JSON.stringify(validSpeeds) +
726
+ ', but was "' + parameters.speed + '"');
727
+ }
728
+ respond.session.setInputSpeed(FirefoxDriver.Speed[parameters.speed]);
715
729
  respond.send();
716
730
  };
717
731
 
718
732
 
719
- FirefoxDriver.prototype.getMouseSpeed = function(respond) {
720
- respond.response = this.mouseSpeed;
733
+ FirefoxDriver.prototype.getSpeed = function(respond) {
734
+ var speed = respond.session.getInputSpeed();
735
+ for (var prop in FirefoxDriver.Speed) {
736
+ if (FirefoxDriver.Speed[prop] == speed) {
737
+ respond.value = prop;
738
+ }
739
+ }
721
740
  respond.send();
722
741
  };
723
742
 
724
743
 
725
744
  FirefoxDriver.prototype.saveScreenshot = function(respond, pngFile) {
726
- var window = Utils.getBrowser(respond.context).contentWindow;
745
+ var window = respond.session.getBrowser().contentWindow;
727
746
  try {
728
747
  var canvas = Screenshooter.grab(window);
729
748
  try {
730
749
  Screenshooter.save(canvas, pngFile);
731
750
  } catch(e) {
732
- respond.isError = true;
733
- respond.response = 'Could not save screenshot to ' + pngFile + ' - ' + e;
751
+ throw new WebDriverError(ErrorCode.UNHANDLED_ERROR,
752
+ 'Could not save screenshot to ' + pngFile + ' - ' + e);
734
753
  }
735
754
  } catch(e) {
736
- respond.isError = true;
737
- respond.response = 'Could not take screenshot of current page - ' + e;
755
+ throw new WebDriverError(ErrorCode.UNHANDLED_ERROR,
756
+ 'Could not take screenshot of current page - ' + e);
738
757
  }
739
758
  respond.send();
740
759
  };
741
760
 
742
761
 
743
- FirefoxDriver.prototype.getScreenshotAsBase64 = function(respond) {
744
- var window = Utils.getBrowser(respond.context).contentWindow;
762
+ FirefoxDriver.prototype.screenshot = function(respond) {
763
+ var window = respond.session.getBrowser().contentWindow;
745
764
  try {
746
765
  var canvas = Screenshooter.grab(window);
747
- respond.isError = false;
748
- respond.response = Screenshooter.toBase64(canvas);
766
+ respond.value = Screenshooter.toBase64(canvas);
749
767
  } catch (e) {
750
- respond.isError = true;
751
- respond.response = 'Could not take screenshot of current page - ' + e;
768
+ throw new WebDriverError(ErrorCode.UNHANDLED_ERROR,
769
+ 'Could not take screenshot of current page - ' + e);
752
770
  }
753
771
  respond.send();
754
772
  };
755
773
 
756
- FirefoxDriver.prototype.dismissAlert = function(respond, alertText) {
774
+ FirefoxDriver.prototype.dismissAlert = function(respond, parameters) {
775
+ var alertText = parameters.text;
757
776
  // TODO(simon): Is there a type for alerts?
758
777
  var wm = Utils.getService("@mozilla.org/appshell/window-mediator;1", "nsIWindowMediator");
759
778
  var allWindows = wm.getEnumerator("");