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
@@ -16,10 +16,55 @@
16
16
  limitations under the License.
17
17
  */
18
18
 
19
- function StaleElementError() {
20
- this.isStaleElementError = true;
19
+
20
+ /**
21
+ * A WebDriver error.
22
+ * @param {!number} code The error code.
23
+ * @param {!string|Error} messageOrError The error message, or another Error to
24
+ * propagate.
25
+ * @constructor
26
+ */
27
+ function WebDriverError(code, messageOrError) {
28
+
29
+ var message;
30
+ var stack;
31
+ if (messageOrError instanceof Error) {
32
+ message = messageOrError.message;
33
+ stack = messageOrError.stack;
34
+ } else {
35
+ message = messageOrError.toString();
36
+ stack = Error(message).stack.split('\n');
37
+ stack.shift();
38
+ stack = stack.join('\n');
39
+ }
40
+
41
+ /**
42
+ * This error's status code.
43
+ * @type {!number}
44
+ */
45
+ this.code = code;
46
+
47
+ /**
48
+ * This error's message.
49
+ * @type {string}
50
+ */
51
+ this.message = message;
52
+
53
+ /**
54
+ * Captures a stack trace for when this error was thrown.
55
+ * @type {string}
56
+ */
57
+ this.stack = stack;
58
+
59
+ /**
60
+ * Used to identify this class since instanceof will not work across
61
+ * component boundaries.
62
+ * @type {!boolean}
63
+ */
64
+ this.isWebDriverError = true;
21
65
  }
22
66
 
67
+
23
68
  function createSwitchFile(file_content) {
24
69
  var filename = "/tmp/switch_window_started";
25
70
  var cc = Components.classes;
@@ -94,39 +139,25 @@ Utils.getServer = function() {
94
139
  };
95
140
 
96
141
 
97
- Utils.getBrowser = function(context) {
98
- return context.fxbrowser;
99
- };
100
-
101
-
102
- Utils.getDocument = function(context) {
103
- if (context.frame) {
104
- return context.frame.document;
105
- }
106
- return context.fxbrowser.contentDocument;
107
- };
108
-
109
-
110
- Utils.getActiveElement = function(context) {
111
- var doc = Utils.getDocument(context);
142
+ Utils.getActiveElement = function(doc) {
112
143
 
113
144
  var element;
114
145
  if (doc["activeElement"]) {
115
146
  element = doc.activeElement;
116
147
  } else {
117
- var commandDispatcher = Utils.getBrowser(context).ownerDocument.
148
+ var topWindow = doc.defaultView.top;
149
+ var commandDispatcher = topWindow.getBrowser().ownerDocument.
118
150
  commandDispatcher;
119
151
 
120
- doc = Utils.getDocument(context);
121
152
  element = commandDispatcher.focusedElement;
122
153
 
123
- if (element && Utils.getDocument(context) != element.ownerDocument)
154
+ if (element && doc != element.ownerDocument)
124
155
  element = null;
125
156
  }
126
157
 
127
158
  // Default to the body
128
159
  if (!element) {
129
- element = Utils.getDocument(context).body;
160
+ element = doc.body;
130
161
  }
131
162
 
132
163
  return element;
@@ -321,8 +352,7 @@ Utils.getText = function(element) {
321
352
  };
322
353
 
323
354
 
324
- Utils.addToKnownElements = function(element, context) {
325
- var doc = Utils.getDocument(context);
355
+ Utils.addToKnownElements = function(element, doc) {
326
356
  if (!doc.fxdriver_elements) {
327
357
  doc.fxdriver_elements = {};
328
358
  }
@@ -340,8 +370,7 @@ Utils.addToKnownElements = function(element, context) {
340
370
  };
341
371
 
342
372
 
343
- Utils.getElementAt = function(index, context) {
344
- var doc = Utils.getDocument(context);
373
+ Utils.getElementAt = function(index, doc) {
345
374
  var e = doc.fxdriver_elements ? doc.fxdriver_elements[index] : undefined;
346
375
  if (e) {
347
376
  // Is this a stale reference?
@@ -353,29 +382,21 @@ Utils.getElementAt = function(index, context) {
353
382
  if (parent !== e.ownerDocument.documentElement) {
354
383
  // Remove from the cache
355
384
  delete doc.fxdriver_elements[index];
356
-
357
- throw new StaleElementError();
385
+ throw new WebDriverError(ErrorCode.STALE_ELEMENT_REFERENCE,
386
+ 'Element is no longer attached to the DOM');
358
387
  }
359
388
  } else {
360
- throw new StaleElementError();
389
+ throw new WebDriverError(ErrorCode.STALE_ELEMENT_REFERENCE,
390
+ 'Element not found in the cache');
361
391
  }
362
392
 
363
393
  return e;
364
394
  };
365
395
 
366
396
 
367
- Utils.currentDocument = function(context) {
368
- if (context) {
369
- return Utils.getDocument(context);
370
- } else {
371
- return document;
372
- }
373
- };
374
-
375
-
376
- Utils.platform = function(context) {
397
+ Utils.platform = function(doc) {
377
398
  if (!this.userAgentPlatformLowercase) {
378
- var currentWindow = Utils.currentDocument(context).defaultView;
399
+ var currentWindow = doc.defaultView;
379
400
  this.userAgentPlatformLowercase =
380
401
  currentWindow.navigator.platform.toLowerCase();
381
402
  }
@@ -417,7 +438,7 @@ Utils.getNodeForNativeEvents = function(element) {
417
438
  };
418
439
 
419
440
 
420
- Utils.type = function(context, element, text, opt_useNativeEvents) {
441
+ Utils.type = function(doc, element, text, opt_useNativeEvents) {
421
442
 
422
443
  // For consistency between native and synthesized events, convert common
423
444
  // escape sequences to their Key enum aliases.
@@ -430,7 +451,7 @@ Utils.type = function(context, element, text, opt_useNativeEvents) {
430
451
  var inputtype = element.getAttribute("type");
431
452
  if (inputtype && inputtype.toLowerCase() == "file") {
432
453
  element.value = text;
433
- Utils.fireHtmlEvent(context, element, "change");
454
+ Utils.fireHtmlEvent(element, "change");
434
455
  return;
435
456
  }
436
457
  }
@@ -545,25 +566,25 @@ Utils.type = function(context, element, text, opt_useNativeEvents) {
545
566
  if (c == '\uE000') {
546
567
  if (controlKey) {
547
568
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL;
548
- Utils.keyEvent(context, element, "keyup", kCode, 0,
569
+ Utils.keyEvent(doc, element, "keyup", kCode, 0,
549
570
  controlKey = false, shiftKey, altKey, metaKey);
550
571
  }
551
572
 
552
573
  if (shiftKey) {
553
574
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
554
- Utils.keyEvent(context, element, "keyup", kCode, 0,
575
+ Utils.keyEvent(doc, element, "keyup", kCode, 0,
555
576
  controlKey, shiftKey = false, altKey, metaKey);
556
577
  }
557
578
 
558
579
  if (altKey) {
559
580
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ALT;
560
- Utils.keyEvent(context, element, "keyup", kCode, 0,
581
+ Utils.keyEvent(doc, element, "keyup", kCode, 0,
561
582
  controlKey, shiftKey, altKey = false, metaKey);
562
583
  }
563
584
 
564
585
  if (metaKey) {
565
586
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_META;
566
- Utils.keyEvent(context, element, "keyup", kCode, 0,
587
+ Utils.keyEvent(doc, element, "keyup", kCode, 0,
567
588
  controlKey, shiftKey, altKey, metaKey = false);
568
589
  }
569
590
 
@@ -743,7 +764,7 @@ Utils.type = function(context, element, text, opt_useNativeEvents) {
743
764
  // generate modifier key event if needed, and continue
744
765
 
745
766
  if (modifierEvent) {
746
- Utils.keyEvent(context, element, modifierEvent, keyCode, 0,
767
+ Utils.keyEvent(doc, element, modifierEvent, keyCode, 0,
747
768
  controlKey, shiftKey, altKey, metaKey);
748
769
  continue;
749
770
  }
@@ -757,7 +778,7 @@ Utils.type = function(context, element, text, opt_useNativeEvents) {
757
778
 
758
779
  if (needsShift && !shiftKey) {
759
780
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
760
- Utils.keyEvent(context, element, "keydown", kCode, 0,
781
+ Utils.keyEvent(doc, element, "keydown", kCode, 0,
761
782
  controlKey, true, altKey, metaKey);
762
783
  Utils.shiftCount += 1;
763
784
  }
@@ -788,20 +809,20 @@ Utils.type = function(context, element, text, opt_useNativeEvents) {
788
809
  }
789
810
 
790
811
  var accepted =
791
- Utils.keyEvent(context, element, "keydown", keyCode, 0,
812
+ Utils.keyEvent(doc, element, "keydown", keyCode, 0,
792
813
  controlKey, needsShift || shiftKey, altKey, metaKey);
793
814
 
794
- Utils.keyEvent(context, element, "keypress", pressCode, charCode,
815
+ Utils.keyEvent(doc, element, "keypress", pressCode, charCode,
795
816
  controlKey, needsShift || shiftKey, altKey, metaKey, !accepted);
796
817
 
797
- Utils.keyEvent(context, element, "keyup", keyCode, 0,
818
+ Utils.keyEvent(doc, element, "keyup", keyCode, 0,
798
819
  controlKey, needsShift || shiftKey, altKey, metaKey);
799
820
 
800
821
  // shift up if needed
801
822
 
802
823
  if (needsShift && !shiftKey) {
803
824
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
804
- Utils.keyEvent(context, element, "keyup", kCode, 0,
825
+ Utils.keyEvent(doc, element, "keyup", kCode, 0,
805
826
  controlKey, false, altKey, metaKey);
806
827
  }
807
828
  }
@@ -810,40 +831,38 @@ Utils.type = function(context, element, text, opt_useNativeEvents) {
810
831
 
811
832
  if (controlKey) {
812
833
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL;
813
- Utils.keyEvent(context, element, "keyup", kCode, 0,
834
+ Utils.keyEvent(doc, element, "keyup", kCode, 0,
814
835
  controlKey = false, shiftKey, altKey, metaKey);
815
836
  }
816
837
 
817
838
  if (shiftKey) {
818
839
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
819
- Utils.keyEvent(context, element, "keyup", kCode, 0,
840
+ Utils.keyEvent(doc, element, "keyup", kCode, 0,
820
841
  controlKey, shiftKey = false, altKey, metaKey);
821
842
  }
822
843
 
823
844
  if (altKey) {
824
845
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ALT;
825
- Utils.keyEvent(context, element, "keyup", kCode, 0,
846
+ Utils.keyEvent(doc, element, "keyup", kCode, 0,
826
847
  controlKey, shiftKey, altKey = false, metaKey);
827
848
  }
828
849
 
829
850
  if (metaKey) {
830
851
  var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_META;
831
- Utils.keyEvent(context, element, "keyup", kCode, 0,
852
+ Utils.keyEvent(doc, element, "keyup", kCode, 0,
832
853
  controlKey, shiftKey, altKey, metaKey = false);
833
854
  }
834
855
  };
835
856
 
836
857
 
837
- Utils.keyEvent = function(context, element, type, keyCode, charCode,
858
+ Utils.keyEvent = function(doc, element, type, keyCode, charCode,
838
859
  controlState, shiftState, altState, metaState,
839
860
  shouldPreventDefault) {
840
861
  var preventDefault = shouldPreventDefault == undefined ? false
841
862
  : shouldPreventDefault;
842
863
 
843
- var keyboardEvent =
844
- Utils.currentDocument(context).createEvent("KeyEvents");
845
- var currentView =
846
- Utils.currentDocument(context).defaultView;
864
+ var keyboardEvent = doc.createEvent("KeyEvents");
865
+ var currentView = doc.defaultView;
847
866
 
848
867
  keyboardEvent.initKeyEvent(
849
868
  type, // in DOMString typeArg,
@@ -865,7 +884,7 @@ Utils.keyEvent = function(context, element, type, keyCode, charCode,
865
884
  };
866
885
 
867
886
 
868
- Utils.fireHtmlEvent = function(context, element, eventName) {
887
+ Utils.fireHtmlEvent = function(element, eventName) {
869
888
  var doc = element.ownerDocument;
870
889
  var e = doc.createEvent("HTMLEvents");
871
890
  e.initEvent(eventName, true, true);
@@ -899,7 +918,7 @@ Utils.findForm = function(element) {
899
918
  };
900
919
 
901
920
 
902
- Utils.fireMouseEventOn = function(context, element, eventName) {
921
+ Utils.fireMouseEventOn = function(element, eventName) {
903
922
  Utils.triggerMouseEvent(element, eventName, 0, 0);
904
923
  };
905
924
 
@@ -955,12 +974,24 @@ Utils.findFrame = function(browser, frameId) {
955
974
 
956
975
 
957
976
  Utils.dumpText = function(text) {
977
+ if (!Utils.dumpText.isLoggingInit_) {
978
+ var prefs =
979
+ Utils.getService("@mozilla.org/preferences-service;1", "nsIPrefBranch");
980
+ Utils.dumpText.isLoggingInit_ = true;
981
+ Utils.dumpText.logToConsole_ =
982
+ prefs.prefHasUserValue("webdriver_log_to_console") &&
983
+ prefs.getBoolPref("webdriver_log_to_console");
984
+ }
958
985
  var consoleService = Utils.getService(
959
986
  "@mozilla.org/consoleservice;1", "nsIConsoleService");
960
- if (consoleService)
987
+ if (consoleService) {
961
988
  consoleService.logStringMessage(text);
962
- else
989
+ if (Utils.dumpText.logToConsole_) {
990
+ dump(text);
991
+ }
992
+ } else {
963
993
  dump(text);
994
+ }
964
995
  };
965
996
 
966
997
 
@@ -1032,7 +1063,7 @@ Utils.stackTrace = function() {
1032
1063
  };
1033
1064
 
1034
1065
 
1035
- Utils.getElementLocation = function(element, context) {
1066
+ Utils.getElementLocation = function(element) {
1036
1067
  var x = element.offsetLeft;
1037
1068
  var y = element.offsetTop;
1038
1069
  var elementParent = element.offsetParent;
@@ -1074,14 +1105,13 @@ Utils.getElementLocation = function(element, context) {
1074
1105
  };
1075
1106
 
1076
1107
 
1077
- Utils.findElementsByXPath = function (xpath, contextNode, context) {
1078
- var doc = Utils.getDocument(context);
1108
+ Utils.findElementsByXPath = function (xpath, contextNode, doc) {
1079
1109
  var result = doc.evaluate(xpath, contextNode, null,
1080
1110
  Components.interfaces.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
1081
1111
  var indices = [];
1082
1112
  var element = result.iterateNext();
1083
1113
  while (element) {
1084
- var index = Utils.addToKnownElements(element, context);
1114
+ var index = Utils.addToKnownElements(element, doc);
1085
1115
  indices.push(index);
1086
1116
  element = result.iterateNext();
1087
1117
  }
@@ -1185,25 +1215,37 @@ Utils.getLocationOnceScrolledIntoView = function(element) {
1185
1215
  };
1186
1216
 
1187
1217
 
1188
- Utils.unwrapParameters = function(wrappedParameters, resultArray, context) {
1218
+ Utils.unwrapParameters = function(wrappedParameters, doc) {
1219
+ var converted = [];
1189
1220
  while (wrappedParameters && wrappedParameters.length > 0) {
1190
1221
  var t = wrappedParameters.shift();
1191
-
1192
- if (t != null && t.length !== undefined && t.length != null && (t['type']
1193
- === undefined || t['type'] == null)) {
1194
- var innerArray = [];
1195
- Utils.unwrapParameters(t, innerArray);
1196
- resultArray.push(innerArray);
1197
- return;
1198
- }
1199
-
1200
- if (t['type'] == "ELEMENT") {
1201
- var element = Utils.getElementAt(t['value'], context);
1202
- t['value'] = element.wrappedJSObject ? element.wrappedJSObject : element;
1222
+ switch (typeof t) {
1223
+ case 'number':
1224
+ case 'string':
1225
+ case 'boolean':
1226
+ converted.push(t);
1227
+ break;
1228
+ case 'object':
1229
+ if (t == null) {
1230
+ converted.push(null);
1231
+ } else if (typeof t.length === 'number' &&
1232
+ !(t.propertyIsEnumerable('length'))) {
1233
+ converted.push(Utils.unwrapParameters(t, doc));
1234
+ } else if (typeof t['ELEMENT'] === 'string') {
1235
+ var element = Utils.getElementAt(t['ELEMENT'], doc);
1236
+ element = element.wrappedJSObject ? element.wrappedJSObject : element;
1237
+ converted.push(element);
1238
+ } else {
1239
+ var convertedObj = {};
1240
+ for (var prop in t) {
1241
+ convertedObj[prop] = Utils.unwrapParameters(t[prop], doc);
1242
+ }
1243
+ converted.push(convertedObj);
1244
+ }
1245
+ break;
1203
1246
  }
1204
-
1205
- resultArray.push(t['value']);
1206
1247
  }
1248
+ return converted;
1207
1249
  };
1208
1250
 
1209
1251
 
@@ -1219,23 +1261,49 @@ Utils.isHtmlCollection_ = function(obj) {
1219
1261
  }
1220
1262
 
1221
1263
 
1222
- Utils.wrapResult = function(result, context) {
1264
+ Utils.wrapResult = function(result, doc) {
1223
1265
  // Sophisticated.
1224
- if (null === result || undefined === result) {
1225
- return {type: "NULL", value: null};
1226
- } else if (result['tagName']) {
1227
- return {type: "ELEMENT",
1228
- value: Utils.addToKnownElements(result, context)};
1229
- } else if (Utils.isArray_(result) || Utils.isHtmlCollection_(result)) {
1230
- var array = [];
1231
- for (var i = 0; i < result.length; i++) {
1232
- array.push(Utils.wrapResult(result[i], context));
1233
- }
1234
- return {type: "ARRAY", value: array};
1235
- } else {
1236
- return {type: "OTHER", value: result};
1266
+ switch (typeof result) {
1267
+ case 'string':
1268
+ case 'number':
1269
+ case 'boolean':
1270
+ return result;
1271
+
1272
+ case 'function':
1273
+ return result.toString();
1274
+
1275
+ case 'undefined':
1276
+ return null;
1277
+
1278
+ case 'object':
1279
+ if (result == null) {
1280
+ return null;
1281
+ }
1282
+
1283
+ // There's got to be a more intelligent way of detecting this.
1284
+ if (result['tagName']) {
1285
+ return {'ELEMENT': Utils.addToKnownElements(result, doc)};
1286
+ }
1287
+
1288
+ if (typeof result.length === 'number' &&
1289
+ !(result.propertyIsEnumerable('length'))) {
1290
+ var array = [];
1291
+ for (var i = 0; i < result.length; i++) {
1292
+ array.push(Utils.wrapResult(result[i], doc));
1293
+ }
1294
+ return array;
1295
+ }
1296
+
1297
+ var convertedObj = {};
1298
+ for (var prop in result) {
1299
+ convertedObj[prop] = Utils.wrapResult(result[prop], doc);
1300
+ }
1301
+ return convertedObj;
1302
+
1303
+ default:
1304
+ return result;
1237
1305
  }
1238
- }
1306
+ };
1239
1307
 
1240
1308
  /**
1241
1309
  * Gets canonical xpath of the passed element, e.g. /HTML[1]/BODY[1]/P[1]