selenium-webdriver 0.0.17 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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("");