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
@@ -297,7 +297,7 @@ chrome.extension.onConnect.addListener(function(port) {
297
297
  }
298
298
  if (ChromeDriver.isClosingTab) {
299
299
  //We are actively closing the tab, and expect a response to this
300
- sendResponseToParsedRequest({statusCode: 0}, false)
300
+ sendResponseToParsedRequest({status: 0}, false)
301
301
  ChromeDriver.isClosingTab = false;
302
302
  if (ChromeDriver.tabs.length == 0) {
303
303
  chrome.windows.getAll({}, function(windows) {
@@ -365,6 +365,7 @@ function sendResponseToParsedRequest(toSend, wait) {
365
365
  ChromeDriver.isBlockedWaitingForResponse = false;
366
366
  ChromeDriver.lastRequestToBeSentWhichHasntBeenAnsweredYet = null;
367
367
  console.log("SENDING RESPOND TO PARSED REQUEST");
368
+ toSend['sessionId'] = 'static_session_id';
368
369
  sendResponseByXHR(JSON.stringify(toSend), wait);
369
370
  setExtensionBusyIndicator(false);
370
371
  }
@@ -383,7 +384,7 @@ function handleXmlHttpRequestReadyStateChange() {
383
384
  if (request.request == "quit") {
384
385
  //We're only allowed to send a response if we're blocked waiting for one, so pretend
385
386
  console.log("SENDING QUIT XHR");
386
- sendResponseByXHR(JSON.stringify({statusCode: 0}), false);
387
+ sendResponseByXHR(JSON.stringify({status: 0}), false);
387
388
  } else {
388
389
  console.log("Got request to execute from XHR: " + this.responseText);
389
390
  parseRequest(request);
@@ -408,6 +409,17 @@ function parseRequest(request) {
408
409
  setExtensionBusyIndicator(true);
409
410
 
410
411
  switch (request.request) {
412
+ case "newSession":
413
+ sendResponseToParsedRequest({
414
+ status: 0,
415
+ value: {
416
+ 'browserName': 'chrome',
417
+ 'version': navigator.appVersion.replace(/.*Chrome\/(\d(\.\d+)*\b).*/, "$1"),
418
+ 'platform': navigator.platform,
419
+ 'javascriptEnabled': true,
420
+ }
421
+ });
422
+ break;
411
423
  case "get":
412
424
  getUrl(request.url);
413
425
  break;
@@ -424,7 +436,7 @@ function parseRequest(request) {
424
436
  var len = ChromeDriver.tabs.length;
425
437
  for (var i = 0; i < len; i++) {
426
438
  if (ChromeDriver.tabs[i].selected) {
427
- sendResponseToParsedRequest({statusCode: 0, value: ChromeDriver.tabs[i].windowName}, false);
439
+ sendResponseToParsedRequest({status: 0, value: ChromeDriver.tabs[i].id}, false);
428
440
  }
429
441
  }
430
442
 
@@ -434,7 +446,7 @@ function parseRequest(request) {
434
446
  var len = ChromeDriver.tabs.length;
435
447
  for (var i = 0; i < len; i++) {
436
448
  if (ChromeDriver.tabs[i].tabId == tab.id) {
437
- sendResponseToParsedRequest({statusCode: 0, value: ChromeDriver.tabs[i].windowName}, false);
449
+ sendResponseToParsedRequest({status: 0, value: ChromeDriver.tabs[i].tabId}, false);
438
450
  return;
439
451
  }
440
452
  }
@@ -443,28 +455,30 @@ function parseRequest(request) {
443
455
  } else {
444
456
  // Wow. I can't see this being error prone in the slightest
445
457
  var handle = ChromeDriver.windowHandlePrefix + "_" + ChromeDriver.activePort.sender.tab.id;
446
- sendResponseToParsedRequest({statusCode: 0, value: handle}, false);
458
+ sendResponseToParsedRequest({status: 0, value: handle}, false);
447
459
  };
448
460
  break;
449
461
  case "getWindowHandles":
450
462
  sendResponseToParsedRequest(getWindowHandles(), false);
451
463
  break;
452
- case "switchToDefaultContent":
453
- switchToDefaultContent();
464
+ case "switchToFrame":
465
+ if (request.id === undefined || request.id === null) {
466
+ switchToDefaultContent();
467
+ } else {
468
+ switchToFrame(request.id);
469
+ }
454
470
  break;
455
471
  case "switchToFrameByIndex":
456
- switchToFrame(null, request.index);
457
- break;
458
472
  case "switchToFrameByName":
459
- switchToFrame(request.name, null);
473
+ switchToFrame(request.id);
460
474
  break;
461
475
  case "switchToWindow":
462
476
  ChromeDriver.hasHwnd = false;
463
- if (request.windowName !== undefined) {
464
- setActivePortByWindowName(request.windowName);
477
+ if (request.name !== undefined) {
478
+ setActivePortByWindowName(request.name);
465
479
  } else {
466
480
  sendResponseToParsedRequest({
467
- statusCode: 3,
481
+ status: 23,
468
482
  value: {
469
483
  message: 'Window to switch to was not given'
470
484
  }
@@ -488,7 +502,7 @@ function parseRequest(request) {
488
502
  case "getTitle":
489
503
  if (hasNoPage()) {
490
504
  console.log("Not got a page, but asked for string, so sending empty string");
491
- sendResponseToParsedRequest({statusCode: 0, value: ''});
505
+ sendResponseToParsedRequest({status: 0, value: ''});
492
506
  break;
493
507
  }
494
508
  // Falling through, as if we do have a page, we want to treat this like a
@@ -497,7 +511,7 @@ function parseRequest(request) {
497
511
  case "findChildElement":
498
512
  if (hasNoPage()) {
499
513
  console.log("Not got a page, but asked for element, so throwing NoSuchElementException");
500
- sendResponseToParsedRequest({statusCode: 7, value: {message: 'Was not on a page, so could not find elements'}});
514
+ sendResponseToParsedRequest({status: 7, value: {message: 'Was not on a page, so could not find elements'}});
501
515
  break;
502
516
  }
503
517
  // Falling through, as if we do have a page, we want to treat this like a
@@ -506,7 +520,7 @@ function parseRequest(request) {
506
520
  case "findChildElements":
507
521
  if (hasNoPage()) {
508
522
  console.log("Not got a page, but asked for elements, so returning no elements");
509
- sendResponseToParsedRequest({statusCode: 0, value: []});
523
+ sendResponseToParsedRequest({status: 0, value: []});
510
524
  break;
511
525
  }
512
526
  // Falling through, as if we do have a page, we want to treat this like a
@@ -515,7 +529,7 @@ function parseRequest(request) {
515
529
  case "deleteCookie":
516
530
  if (hasNoPage()) {
517
531
  console.log("Not got a page, but asked to delete cookies, so returning ok");
518
- sendResponseToParsedRequest({statusCode: 0});
532
+ sendResponseToParsedRequest({status: 0});
519
533
  break;
520
534
  }
521
535
  // Falling through, as if we do have a page, we want to treat this like a
@@ -523,7 +537,7 @@ function parseRequest(request) {
523
537
  case "executeScript":
524
538
  if (hasNoPage()) {
525
539
  console.log("Not got a page, but asked to execute script, so sending error 17");
526
- sendResponseToParsedRequest({statusCode: 17, value: {message: 'Was not on a page, so could not execute javascript'}});
540
+ sendResponseToParsedRequest({status: 17, value: {message: 'Was not on a page, so could not execute javascript'}});
527
541
  break;
528
542
  }
529
543
  // Falling through, as if we do have a page, we want to treat this like a
@@ -546,11 +560,11 @@ function getScreenshot() {
546
560
  function getScreenshotResult(snapshotDataUrl) {
547
561
  var index = snapshotDataUrl.indexOf('base64,');
548
562
  if (index == -1) {
549
- sendResponseToParsedRequest({statusCode: 99}, false);
563
+ sendResponseToParsedRequest({status: 99}, false);
550
564
  return;
551
565
  }
552
566
  var base64 = snapshotDataUrl.substring(index + 'base64,'.length);
553
- sendResponseToParsedRequest({statusCode: 0, value: base64}, false);
567
+ sendResponseToParsedRequest({status: 0, value: base64}, false);
554
568
  }
555
569
 
556
570
  function sendMessageOnActivePortAndAlsoKeepTrackOfIt(message) {
@@ -582,14 +596,12 @@ function parsePortMessage(message) {
582
596
  console.log("Got invalid response from the content script.");
583
597
  return;
584
598
  }
585
- var toSend = {statusCode: 12};
599
+ var toSend = {status: 12};
586
600
  ChromeDriver.lastRequestToBeSentWhichHasntBeenAnsweredYet = null;
587
601
  switch (message.response.value.statusCode) {
588
602
  // Error codes are loosely based on native exception codes, see
589
603
  // common/src/cpp/webdriver-interactions/errorcodes.h
590
604
  case 0:
591
- case 2: //org.openqa.selenium.WebDriverException [Cookies]
592
- case 3: //org.openqa.selenium.NoSuchWindowException
593
605
  case 7: //org.openqa.selenium.NoSuchElementException
594
606
  case 8: //org.openqa.selenium.NoSuchFrameException
595
607
  case 9: //java.lang.UnsupportedOperationException [Unknown command]
@@ -599,8 +611,11 @@ function parsePortMessage(message) {
599
611
  case 13: //org.openqa.selenium.WebDriverException [Unhandled error]
600
612
  case 17: //org.openqa.selenium.WebDriverException [Bad javascript]
601
613
  case 19: //org.openqa.selenium.XPathLookupException
614
+ case 23: //org.openqa.selenium.NoSuchWindowException
615
+ case 24: //org.openqa.selenium.InvalidCookieDomainException
616
+ case 25: //org.openqa.selenium.UnableToSetCookieException
602
617
  case 99: //org.openqa.selenium.WebDriverException [Native event]
603
- toSend = {statusCode: message.response.value.statusCode, value: null};
618
+ toSend = {status: message.response.value.statusCode, value: null};
604
619
  if (message.response.value !== undefined && message.response.value !== null &&
605
620
  message.response.value.value !== undefined) {
606
621
  toSend.value = message.response.value.value;
@@ -613,16 +628,16 @@ function parsePortMessage(message) {
613
628
  case "clickElement":
614
629
  try {
615
630
  if (document.embeds[0].clickAt(message.response.value.x, message.response.value.y)) {
616
- sendResponseToParsedRequest({statusCode: 0}, true);
631
+ sendResponseToParsedRequest({status: 0}, true);
617
632
  } else {
618
- sendResponseToParsedRequest({statusCode: 99}, true);
633
+ sendResponseToParsedRequest({status: 99}, true);
619
634
  }
620
635
  } catch(e) {
621
636
  console.log("Error natively clicking. Trying non-native.");
622
637
  ChromeDriver.isBlockedWaitingForResponse = false;
623
638
  parseRequest({
624
639
  request: 'nonNativeClickElement',
625
- elementId: message.response.value.elementId
640
+ id: message.response.value.id
626
641
  });
627
642
  }
628
643
  break;
@@ -630,27 +645,27 @@ function parsePortMessage(message) {
630
645
  try {
631
646
  var points = message.response.value;
632
647
  if (document.embeds[0].mouseMoveTo(15, points.oldX, points.oldY, points.newX, points.newY)) {
633
- sendResponseToParsedRequest({statusCode: 0}, true);
648
+ sendResponseToParsedRequest({status: 0}, true);
634
649
  } else {
635
- sendResponseToParsedRequest({statusCode: 99}, true);
650
+ sendResponseToParsedRequest({status: 99}, true);
636
651
  }
637
652
  } catch(e) {
638
- sendResponseToParsedRequest({statusCode: 99}, true);
653
+ sendResponseToParsedRequest({status: 99}, true);
639
654
  }
640
655
  break;
641
656
  case "sendKeysToElement":
642
657
  try {
643
658
  if (document.embeds[0].sendKeys(message.response.value.keys)) {
644
- sendResponseToParsedRequest({statusCode: 0}, true);
659
+ sendResponseToParsedRequest({status: 0}, true);
645
660
  } else {
646
- sendResponseToParsedRequest({statusCode: 99}, true);
661
+ sendResponseToParsedRequest({status: 99}, true);
647
662
  }
648
663
  } catch(e) {
649
664
  console.log("Error natively sending keys. Trying non-native.");
650
665
  ChromeDriver.isBlockedWaitingForResponse = false;
651
666
  parseRequest({
652
667
  request: 'sendElementNonNativeKeys',
653
- elementId: message.response.value.elementId,
668
+ id: message.response.value.id,
654
669
  keys: message.response.value.keys
655
670
  });
656
671
  }
@@ -733,7 +748,7 @@ function getWindowHandles() {
733
748
  for (var tab in ChromeDriver.tabs) {
734
749
  windowHandles.push(ChromeDriver.tabs[tab].windowName);
735
750
  }
736
- return {statusCode: 0, value: windowHandles}
751
+ return {status: 0, value: windowHandles}
737
752
  }
738
753
 
739
754
  function resetActiveTabDetails() {
@@ -761,17 +776,17 @@ function switchToDefaultContent() {
761
776
  if (ChromeDriver.tabs[tab].tabId == ChromeDriver.activeTabId) {
762
777
  if (ChromeDriver.tabs[tab].isFrameset) {
763
778
  ChromeDriver.isBlockedWaitingForResponse = false;
764
- parseRequest({request: 'switchToFrameByIndex', index: 0});
779
+ parseRequest({request: 'switchToFrame', id: 0});
765
780
  } else {
766
781
  ChromeDriver.activePort = ChromeDriver.tabs[tab].mainPort;
767
- sendResponseToParsedRequest({statusCode: 0}, false);
782
+ sendResponseToParsedRequest({status: 0}, false);
768
783
  }
769
784
  return;
770
785
  }
771
786
  }
772
787
  }
773
788
 
774
- function switchToFrame(name, index) {
789
+ function switchToFrame(id) {
775
790
  ChromeDriver.hasHwnd = false;
776
791
  for (var tab in ChromeDriver.tabs) {
777
792
  if (ChromeDriver.tabs[tab].tabId == ChromeDriver.activeTabId) {
@@ -779,13 +794,13 @@ function switchToFrame(name, index) {
779
794
  break;
780
795
  }
781
796
  }
782
- if (name !== undefined && name !== null) {
783
- switchToFrameByName(name);
784
- } else if (index !== undefined && index !== null) {
785
- getFrameNameFromIndex(index);
797
+ if (typeof id == 'string') {
798
+ switchToFrameByName(id);
799
+ } else if (typeof id == 'number') {
800
+ getFrameNameFromIndex(id);
786
801
  } else {
787
802
  sendResponseToParsedRequest({
788
- statusCode: 9,
803
+ status: 9,
789
804
  value: {
790
805
  message: "Switching frames other than by name or id is unsupported"
791
806
  }
@@ -806,7 +821,7 @@ function switchToFrameByName(name) {
806
821
  ChromeDriver.activePort =
807
822
  ChromeDriver.tabs[tab].frames[frame].framePort;
808
823
  ChromeDriver.restOfCurrentFramePath = [];
809
- sendResponseToParsedRequest({statusCode: 0}, false);
824
+ sendResponseToParsedRequest({status: 0}, false);
810
825
  return;
811
826
  }
812
827
  }
@@ -819,7 +834,7 @@ function switchToFrameByName(name) {
819
834
  names.shift();
820
835
  ChromeDriver.restOfCurrentFramePath = names;
821
836
  if (names.length == 0) {
822
- sendResponseToParsedRequest({statusCode: 0}, false);
837
+ sendResponseToParsedRequest({status: 0}, false);
823
838
  return;
824
839
  } else {
825
840
  switchToFrameByName(names.join("."));
@@ -930,7 +945,7 @@ function getUrlCallback(tab) {
930
945
  if (ChromeDriver.isGettingUrlButOnlyChangingByFragment) {
931
946
  ChromeDriver.urlBeingLoaded = null;
932
947
  resetCurrentlyWaitingOnContentScriptTime();
933
- sendResponseToParsedRequest({statusCode: 0}, false);
948
+ sendResponseToParsedRequest({status: 0}, false);
934
949
  ChromeDriver.isGettingUrlButOnlyChangingByFragment = false;
935
950
  }
936
951
  }
@@ -947,7 +962,7 @@ function sendEmptyResponseWhenTabIsLoaded(tab) {
947
962
  } else {
948
963
  if (!ChromeDriver.hasSentResponseToThisPageLoading) {
949
964
  ChromeDriver.urlBeingLoaded = null;
950
- sendResponseToParsedRequest({statusCode: 0}, false);
965
+ sendResponseToParsedRequest({status: 0}, false);
951
966
  }
952
967
  }
953
968
  } else {
@@ -972,11 +987,11 @@ function setActivePortByWindowName(handle) {
972
987
  ChromeDriver.activePort = ChromeDriver.tabs[tab].mainPort;
973
988
  chrome.tabs.get(ChromeDriver.tabs[tab].tabId, setActiveTabDetails);
974
989
  chrome.tabs.update(ChromeDriver.tabs[tab].tabId, {selected: true});
975
- sendResponseToParsedRequest({statusCode: 0}, false);
990
+ sendResponseToParsedRequest({status: 0}, false);
976
991
  return;
977
992
  }
978
993
  }
979
- sendResponseToParsedRequest({statusCode: 3, value: {message: 'Could not find window to switch to by handle: ' + handle}}, false);
994
+ sendResponseToParsedRequest({status: 23, value: {message: 'Could not find window to switch to by handle: ' + handle}}, false);
980
995
  }
981
996
 
982
997
 
@@ -990,6 +1005,7 @@ function hasNoPage() {
990
1005
  }
991
1006
 
992
1007
  function resetCurrentlyWaitingOnContentScriptTime() {
1008
+ console.log('resetting current content script wait time');
993
1009
  ChromeDriver.currentlyWaitingUntilGiveUpOnContentScriptLoading =
994
1010
  ChromeDriver.timeoutUntilGiveUpOnContentScriptLoading;
995
1011
  }
@@ -51,10 +51,10 @@ function parsePortMessage(message) {
51
51
  console.log("Received request: " + JSON.stringify(message) + " (" + window.name + ")");
52
52
  //wait indicates whether this is a potentially page-changing change (see background.js's sendResponseByXHR)
53
53
  var response = {response: message.request.request, value: null, wait: true};
54
- if (message.request.elementId !== undefined && message.request.elementId != null) {
55
- //If it seems an elementId has been passed, try to resolve that to an element
54
+ if (message.request.id !== undefined && message.request.id != null) {
55
+ //If it seems an id has been passed, try to resolve that to an element
56
56
  try {
57
- var element = internalGetElement(message.request.elementId);
57
+ var element = internalGetElement(message.request.id);
58
58
  } catch(e) {
59
59
  response.value = e;
60
60
  ChromeDriverContentScript.port.postMessage({response: response, sequenceNumber: message.sequenceNumber});
@@ -71,7 +71,7 @@ function parsePortMessage(message) {
71
71
  response.value = clearElement(element);
72
72
  break;
73
73
  case "clickElement":
74
- response.value = clickElement(element, message.request.elementId);
74
+ response.value = clickElement(element, message.request.id);
75
75
  break;
76
76
  case "nonNativeClickElement":
77
77
  //TODO(danielwh): Focus/blur events for non-native clicking
@@ -87,7 +87,9 @@ function parsePortMessage(message) {
87
87
 
88
88
  if (element.click) {
89
89
  console.log("click");
90
- execute("try { arguments[0].click(); } catch(e){}", {type: "ELEMENT", value: addElementToInternalArray(element)});
90
+ execute("try { arguments[0].click(); } catch(e){}", [{
91
+ type: "ELEMENT", value: addElementToInternalArray(element)
92
+ }]);
91
93
  }
92
94
  response.value = {statusCode: 0};
93
95
  break;
@@ -128,11 +130,11 @@ function parsePortMessage(message) {
128
130
  response.wait = false;
129
131
  break;
130
132
  case "getElementAttribute":
131
- response.value = getElementAttribute(element, message.request.attribute);
133
+ response.value = getElementAttribute(element, message.request.name);
132
134
  response.wait = false;
133
135
  break;
134
136
  case "getElementValueOfCssProperty":
135
- response.value = {statusCode: 0, value: getStyle(element, message.request.css)};
137
+ response.value = {statusCode: 0, value: getStyle(element, message.request.propertyName)};
136
138
  response.wait = false;
137
139
  break;
138
140
  case "getElementLocation":
@@ -186,7 +188,7 @@ function parsePortMessage(message) {
186
188
  response.value = {statusCode: 0};
187
189
  break;
188
190
  case "hoverOverElement":
189
- response.value = hoverElement(element, message.request.elementId);
191
+ response.value = hoverElement(element, message.request.id);
190
192
  break;
191
193
  case "injectEmbed":
192
194
  injectEmbed();
@@ -208,7 +210,12 @@ function parsePortMessage(message) {
208
210
  response.value = {statusCode: 0};
209
211
  break;
210
212
  case "sendKeysToElement":
211
- response.value = sendElementKeys(element, message.request.keys, message.request.elementId);
213
+ if (typeof message.request.value.splice == 'function' &&
214
+ typeof message.request.value.join == 'function') {
215
+ // Looks like we were given an array of strings. Join them together.
216
+ message.request.value = message.request.value.join('');
217
+ }
218
+ response.value = sendElementKeys(element, message.request.value, message.request.id);
212
219
  response.wait = false;
213
220
  break;
214
221
  case "sendElementNonNativeKeys":
@@ -219,7 +226,7 @@ function parsePortMessage(message) {
219
226
  response.value = selectElement(element);
220
227
  break;
221
228
  case "getActiveElement":
222
- response.value = {statusCode: 0, value: [addElementToInternalArray(ChromeDriverContentScript.currentDocument.activeElement).toString()]};
229
+ response.value = {statusCode: 0, value: {'ELEMENT':addElementToInternalArray(ChromeDriverContentScript.currentDocument.activeElement).toString()}};
223
230
  response.wait = false;
224
231
  break;
225
232
  case "switchToNamedIFrameIfOneExists":
@@ -284,7 +291,7 @@ function deleteCookie(cookieName) {
284
291
  var fullpath = cookieDocument.location.pathname;
285
292
  }
286
293
  var hostParts = cookieDocument.location.hostname.split(".");
287
-
294
+
288
295
  fullpath = fullpath.split('/');
289
296
  fullpath.pop(); //Get rid of the file
290
297
  //TODO(danielwh): Tidy up these loops and this repeated code
@@ -297,17 +304,17 @@ function deleteCookie(cookieName) {
297
304
  cookieDocument.cookie = cookieName + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/' + path;
298
305
  //Delete cookie without trailing /
299
306
  cookieDocument.cookie = cookieName + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/' + path.substring(0, path.length - 1);
300
-
307
+
301
308
  var domain = "";
302
309
  for (var i = hostParts.length - 1; i >= 0; --i) {
303
310
  domain = "." + hostParts[i] + domain;
304
311
  //Delete cookie with trailing /
305
312
  cookieDocument.cookie = cookieName + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/' + path + ";domain=" + domain;
306
-
313
+
307
314
  cookieDocument.cookie = cookieName + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/' + path + ";domain=" + domain;
308
315
  //Delete cookie without trailing /
309
316
  cookieDocument.cookie = cookieName + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/' + path.substring(0, path.length - 1) + ";domain=" + domain;
310
-
317
+
311
318
  cookieDocument.cookie = cookieName + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/' + path.substring(0, path.length - 1) + ";domain=" + domain.substring(1);
312
319
  }
313
320
  }
@@ -392,15 +399,15 @@ function setCookie(cookie) {
392
399
  var currLocation = ChromeDriverContentScript.currentDocument.location;
393
400
  var currDomain = currLocation.host;
394
401
  }
395
-
402
+
396
403
  if (currLocation.port != 80) { currDomain += ":" + currLocation.port; }
397
404
  if (cookie.domain != null && cookie.domain !== undefined &&
398
405
  currDomain.indexOf(cookie.domain) == -1) {
399
406
  // Not quite right, but close enough. (See r783)
400
- return {statusCode: 2, value: {
407
+ return {statusCode: 24, value: {
401
408
  message: "You may only set cookies for the current domain"}};
402
409
  } else if (guessPageType() != "html") {
403
- return {statusCode: 2, value: {
410
+ return {statusCode: 25, value: {
404
411
  message: "You may only set cookies on html documents"}};
405
412
  } else {
406
413
  cookieDocument.cookie = cookie.name + '=' + escape(cookie.value) +
@@ -486,12 +493,15 @@ function getElement(plural, lookupBy, lookupValue, id) {
486
493
  message: "Unable to find element with " + lookupBy + " " + lookupValue}};
487
494
  }
488
495
  } else {
489
- var elementsToReturnArray = [];
496
+ var toReturn;
490
497
  if (plural) {
498
+ toReturn = [];
491
499
  //Add all found elements to the page's elements, and push each to the array to return
492
500
  var addedElements = addElementsToInternalArray(elements);
493
501
  for (var addedElement in addedElements) {
494
- elementsToReturnArray.push(addedElements[addedElement].toString());
502
+ toReturn.push({
503
+ 'ELEMENT': addedElements[addedElement].toString()
504
+ });
495
505
  }
496
506
  } else {
497
507
  if (!elements[0]) {
@@ -499,9 +509,11 @@ function getElement(plural, lookupBy, lookupValue, id) {
499
509
  message: "Unable to find element with " + lookupBy + " " + lookupValue}};
500
510
  }
501
511
  //Add the first found elements to the page's elements, and push it to the array to return
502
- elementsToReturnArray.push(addElementToInternalArray(elements[0]).toString());
512
+ toReturn = {
513
+ 'ELEMENT': addElementToInternalArray(elements[0]).toString()
514
+ };
503
515
  }
504
- return {statusCode: 0, value: elementsToReturnArray};
516
+ return {statusCode: 0, value: toReturn};
505
517
  }
506
518
  }
507
519
 
@@ -565,7 +577,7 @@ function clickElement(element, elementId) {
565
577
  element.scrollIntoView(true);
566
578
  var size = getOffsetSizeFromSubElements(element);
567
579
  var coords = getElementCoords(element);
568
- return {statusCode: "no-op", elementId: elementId,
580
+ return {statusCode: "no-op", id: elementId,
569
581
  x: parseInt(coords[0] - ChromeDriverContentScript.currentDocument.body.scrollLeft + (size.width ? size.width / 2 : 0)),
570
582
  y: parseInt(coords[1] - ChromeDriverContentScript.currentDocument.body.scrollTop + (size.height ? size.height / 2 : 0))};
571
583
  }
@@ -584,7 +596,7 @@ function hoverElement(element, elementId) {
584
596
  var size = getOffsetSizeFromSubElements(element)
585
597
  var coords = getElementCoords(element);
586
598
  console.log("element.clientX: " + element.clientX);
587
- return {statusCode: "no-op", elementId: elementId,
599
+ return {statusCode: "no-op", id: elementId,
588
600
  oldX: 0,
589
601
  oldY: 0,
590
602
  newX: coords[0] - ChromeDriverContentScript.currentDocument.body.scrollLeft + (size.width ? size.width / 2 : 0),
@@ -722,7 +734,7 @@ function sendElementKeys(element, keys, elementId) {
722
734
  Utils.fireHtmlEventAndConditionallyPerformAction(oldFocusedElement, "blur", function() {oldFocusedElement.blur();});
723
735
  Utils.fireHtmlEventAndConditionallyPerformAction(element, "focus", function() {element.focus();});
724
736
  }
725
- return {statusCode: "no-op", keys: keys, elementId: elementId};
737
+ return {statusCode: "no-op", keys: keys, id: elementId};
726
738
  }
727
739
 
728
740
  /**
@@ -791,7 +803,7 @@ function toggleElement(element) {
791
803
  return e;
792
804
  }
793
805
  console.log("New value: " + newValue);
794
-
806
+
795
807
  if (changed) {
796
808
  //TODO: Work out a way of firing events,
797
809
  //now that synthesising them gives appendMessage errors
@@ -830,38 +842,60 @@ function sniffForMetaRedirects() {
830
842
  return {statusCode: "no-op", value: false};
831
843
  }
832
844
 
833
- function parseWrappedArguments(argument) {
834
- //Parse the arguments into actual values (which are wrapped up in JSON)
835
- if (argument.length !== undefined) {
836
- var array = [];
837
- for (var i = 0; i < argument.length; ++i) {
838
- array.push(parseWrappedArguments(argument[i]));
839
- }
840
- return {success: true, value: array};
841
- }
842
- switch (argument.type) {
843
- case "ELEMENT":
844
- //Wrap up as a special object with the element's canonical xpath, which the page can work out
845
- var element_id = argument.value;
846
- var element = null;
847
- try {
848
- element = internalGetElement(element_id);
849
- } catch (e) {
850
- return {success: false, value: {response: "execute", value:
851
- {statusCode: 10,
852
- message: "Tried use obsolete element as argument when executing javascript."}}};
845
+ function parseWrappedArguments(wrappedArguments) {
846
+ var converted = [];
847
+ while (wrappedArguments && wrappedArguments.length > 0) {
848
+ var t = wrappedArguments.shift();
849
+ switch (typeof t) {
850
+ case 'number':
851
+ case 'string':
852
+ case 'boolean':
853
+ converted.push(t);
854
+ break;
855
+
856
+ case 'object':
857
+ if (t == null) {
858
+ converted.push(null);
859
+
860
+ } else if (typeof t.length === 'number' &&
861
+ !(t.propertyIsEnumerable('length'))) {
862
+ converted.push(parseWrappedArguments(t));
863
+
864
+ } else if (typeof t['ELEMENT'] === 'string' ||
865
+ typeof t['ELEMENT'] === 'number') {
866
+ //Wrap up as a special object with the element's canonical xpath,
867
+ // which the page can work out
868
+ var element_id = t['ELEMENT'];
869
+ var element = null;
870
+ try {
871
+ element = internalGetElement(element_id);
872
+ } catch (e) {
873
+ throw {
874
+ statusCode: 10,
875
+ message:'Tried to use obsolete element as a JavaScript argument.'
876
+ };
877
+ }
878
+ converted.push({
879
+ webdriverElementXPath: getXPathOfElement(element)
880
+ });
881
+
882
+ } else {
883
+ var convertedObj = {};
884
+ for (var prop in t) {
885
+ convertedObj[prop] = parseWrappedArguments(t[prop]);
886
+ }
887
+ converted.push(convertedObj);
888
+ }
889
+ break;
890
+
891
+ default:
892
+ throw {
893
+ statusCode: 17,
894
+ message: 'Bad javascript argument: ' + (typeof t)
895
+ };
853
896
  }
854
- return {success: true, value: {webdriverElementXPath: getXPathOfElement(element)}};
855
- break;
856
- //Intentional falling through because Javascript will parse things properly
857
- case "STRING":
858
- case "BOOLEAN":
859
- case "NUMBER":
860
- return {success: true, value: argument.value};
861
- break;
862
897
  }
863
- return {success: false, value: {statusCode: 17,
864
- message: "Bad argument to javascript."}}
898
+ return converted;
865
899
  }
866
900
 
867
901
  /**
@@ -869,70 +903,137 @@ function parseWrappedArguments(argument) {
869
903
  * Returns by callback to returnFromJavascriptInPage.
870
904
  * Yes, this is *horribly* hacky.
871
905
  * We can't share objects between content script and page, so have to wrap up arguments as JSON
872
- * @param script script to execute as a string
873
- * @param passedArgs array of arguments to pass to the script
906
+ * @param {string} script The javascript snippet to execute in the current page.
907
+ * @param {Array.<*>} passedArgs An array of JSON arguments to pass to the
908
+ * injected script. DOMElements should be specified as JSON objects of the
909
+ * form {ELEMENT: string}.
874
910
  * @param callback function to call when the result is returned. Passed a DOMAttrModified event which should be parsed as returnFromJavascriptInPage
875
911
  * TODO: Make the callback be passed the parsed result.
876
912
  */
877
913
  function execute_(script, passedArgs, callback) {
878
914
  console.log("executing " + script + ", args: " + JSON.stringify(passedArgs));
879
915
  var func = "function(){" + script + "}";
880
- var args = [];
881
- for (var i = 0; i < passedArgs.length; ++i) {
882
- console.log("Parsing: " + JSON.stringify(passedArgs[i]));
883
- var value = parseWrappedArguments(passedArgs[i]);
884
- if (value.success) {
885
- args.push(value.value);
886
- } else {
887
- ChromeDriverContentScript.port.postMessage({response: value.value, sequenceNumber: ChromeDriverContentScript.currentSequenceNumber});
888
- return;
889
- }
916
+ var args;
917
+ try {
918
+ args = parseWrappedArguments(passedArgs);
919
+ } catch (ex) {
920
+ ChromeDriverContentScript.port.postMessage({
921
+ response: {
922
+ statusCode: (ex.statusCode || 17),
923
+ message: (ex.message || ex.toString())
924
+ },
925
+ sequenceNumber: ChromeDriverContentScript.currentSequenceNumber
926
+ });
927
+ return;
890
928
  }
929
+
891
930
  //Add a script tag to the page, containing the script we wish to execute
892
931
  var scriptTag = ChromeDriverContentScript.currentDocument.createElement('script');
893
932
  var argsString = JSON.stringify(args).replace(/"/g, "\\\"");
894
- scriptTag.innerText = 'var e = document.createEvent("MutationEvent");' +
895
- //Dump our arguments in an array
896
- 'var args = JSON.parse("' + argsString + '");' +
897
- 'var element = null;' +
898
- 'for (var i = 0; i < args.length; ++i) {' +
899
- 'if (args[i] && typeof(args[i]) == "object" && args[i].webdriverElementXPath) {' +
900
- //If this is an element (because it has the proper xpath), turn it into an actual element object
901
- 'args[i] = document.evaluate(args[i].webdriverElementXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;' +
902
- '}' +
903
- '}' +
904
- 'try {' +
905
- 'var val = eval(' + func + ').apply(window, args);' +
906
- 'if (typeof(val) == "string") { val = JSON.stringify(val); }' +
907
- //TODO(danielwh): Deal with the undefined != null case better
908
- 'else if (val === undefined) { val = null; }' +
909
- 'else if (typeof(val) == "object" && val && val.nodeType == 1) {' +
910
- //If we're returning an element, turn it into a special xpath-containing object
911
- 'var path = "";' +
912
- 'for (; val && val.nodeType == 1; val = val.parentNode) {' +
913
- 'var index = 1;' +
914
- 'for (var sibling = val.previousSibling; sibling; sibling = sibling.previousSibling) {' +
915
- 'if (sibling.nodeType == 1 && sibling.tagName && sibling.tagName == val.tagName) {' +
916
- 'index++;' +
917
- '}' +
918
- '}' +
919
- 'path = "/" + val.tagName + "[" + index + "]" + path;' +
920
- '}' +
921
- 'val = JSON.stringify({webdriverElementXPath: path});' +
922
- '} else {' +
923
- 'val = JSON.stringify(val);' +
924
- '}' +
925
- //Fire mutation event with newValue set to the JSON of our return value
926
- 'e.initMutationEvent("DOMAttrModified", true, false, null, null, "{value: " + val + "}", null, 0);' +
927
- '} catch (exn) {' +
928
- //Fire mutation event with prevValue set to EXCEPTION to indicate an error in the script
929
- 'e.initMutationEvent("DOMAttrModified", true, false, null, "EXCEPTION", null, null, 0);' +
930
- '}' +
931
- 'document.getElementsByTagName("script")[document.getElementsByTagName("script").length - 1].dispatchEvent(e);' +
932
- 'document.getElementsByTagName("html")[0].removeChild(document.getElementsByTagName("script")[document.getElementsByTagName("script").length - 1]);';
933
+
934
+ // We use the fact that Function.prototype.toString() will decompile this to
935
+ // its source code so we can inject it into the page in a SCRIPT tag.
936
+ function executeInjectedScript(fn, argsAsString) {
937
+ var e = document.createEvent("MutationEvent");
938
+ var args = JSON.parse(argsAsString);
939
+ var element = null;
940
+ for (var i = 0; i < args.length; i++) {
941
+ if (args[i] && typeof args[i] == 'object' &&
942
+ args[i].webdriverElementXPath) {
943
+ //If this is an element (because it has the proper xpath), turn it into
944
+ //an actual element object
945
+ args[i] = document.evaluate(args[i].webdriverElementXPath, document,
946
+ null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
947
+ }
948
+ }
949
+ try {
950
+ var val = fn.apply(window, args);
951
+
952
+ // prepares the injected script result to be converted to json to be sent
953
+ // back to the content script.
954
+ function convertResultToJson(result) {
955
+ switch (typeof result) {
956
+ case 'string':
957
+ case 'number':
958
+ case 'boolean':
959
+ return result;
960
+ case 'undefined':
961
+ return null;
962
+ case 'object':
963
+ if (result == null) {
964
+ return result;
965
+ }
966
+ // Result was an array.
967
+ if (typeof result.length === 'number' &&
968
+ !(result.propertyIsEnumerable('length'))) {
969
+ var converted = [];
970
+ for (var i = 0; i < result.length; i++) {
971
+ converted.push(convertResultToJson(result[i]));
972
+ }
973
+ return converted;
974
+ }
975
+ // Result is a DOMNode; make sure it's a DOMElement
976
+ if (typeof result.nodeType == 'number') {
977
+ if (result.nodeType != 1) {
978
+ // Non-valid JSON value; we'll fail over when trying to
979
+ // stringify this, so fail early.
980
+ throw Error('Invalid script return type: result.nodeType == ' +
981
+ result.nodeType);
982
+ }
983
+ var path = '';
984
+ for (; result && result.nodeType == 1;
985
+ result = result.parentNode) {
986
+ var index = 1;
987
+ for (var sibling = result.previousSibling; sibling;
988
+ sibling = sibling.previousSibling) {
989
+ if (sibling.nodeType == 1 && sibling.tagName &&
990
+ sibling.tagName == result.tagName) {
991
+ index++;
992
+ }
993
+ }
994
+ path = '/' + result.tagName + '[' + index + ']' + path;
995
+ }
996
+ return {webdriverElementXPath: path};
997
+ }
998
+ // Result is an object; convert each property.
999
+ var converted = {};
1000
+ for (var prop in result) {
1001
+ converted[prop] = convertResultToJson(result[prop]);
1002
+ }
1003
+ return converted;
1004
+
1005
+ case 'function':
1006
+ default:
1007
+ throw Error('Invalid script return type: ' + (typeof result));
1008
+ } // switch
1009
+ }
1010
+
1011
+ val = JSON.stringify({
1012
+ value: convertResultToJson(val)
1013
+ });
1014
+ console.info('returning from injected script: ' + val);
1015
+ //Fire mutation event with newValue set to the JSON of our return value
1016
+ e.initMutationEvent(
1017
+ "DOMAttrModified", true, false, null, null, val, null, 0);
1018
+ } catch (ex) {
1019
+ //Fire mutation event with prevValue set to EXCEPTION to indicate an error
1020
+ //in the script
1021
+ console.error('injected script failed: ' + ex.toString());
1022
+ e.initMutationEvent("DOMAttrModified", true, false, null, "EXCEPTION",
1023
+ null, null, 0);
1024
+ }
1025
+ var scriptTags = document.getElementsByTagName("script");
1026
+ var scriptTag = scriptTags[scriptTags.length - 1];
1027
+ scriptTag.dispatchEvent(e);
1028
+ document.documentElement.removeChild(scriptTag);
1029
+ }
1030
+
1031
+ scriptTag.innerHTML =
1032
+ '(' + executeInjectedScript + ')(' + func + ', "' + argsString + '");';
1033
+
933
1034
  scriptTag.addEventListener('DOMAttrModified', callback, false);
934
- console.log("Injecting script element");
935
- ChromeDriverContentScript.currentDocument.getElementsByTagName("html")[0].appendChild(scriptTag);
1035
+ ChromeDriverContentScript.currentDocument.documentElement.
1036
+ appendChild(scriptTag);
936
1037
  }
937
1038
 
938
1039
  function execute(script, passedArgs) {
@@ -940,29 +1041,49 @@ function execute(script, passedArgs) {
940
1041
  }
941
1042
 
942
1043
  function parseReturnValueFromScript(result) {
943
- console.log("Parsing: " + JSON.stringify(result));
944
- var value = {"type":"NULL"};
945
- if (result !== undefined && result != null && typeof(result) == "object") {
946
- if (result.webdriverElementXPath) {
947
- //If we're returning an element, turn it into an actual element object
948
- value = {value: addElementToInternalArray(getElementsByXPath(result.webdriverElementXPath)[0]).toString(), type:"ELEMENT"};
949
- } else if (result.length !== undefined) {
950
- value = [];
951
- for (var i = 0; i < result.length; ++i) {
952
- value.push(parseReturnValueFromScript(result[i]));
1044
+ switch (typeof result) {
1045
+ case 'string':
1046
+ case 'number':
1047
+ case 'boolean':
1048
+ return result;
1049
+
1050
+ case 'object':
1051
+ if (result == null) {
1052
+ return result;
953
1053
  }
954
- }
955
- } else if (result !== undefined && result != null) {
956
- switch (typeof(result)) {
957
- //Intentional falling through because we treat all "VALUE"s the same
958
- case "string":
959
- case "number":
960
- case "boolean":
961
- value = {value: result, type: "VALUE"};
962
- break;
963
- }
1054
+
1055
+ // Received an array, parse each element.
1056
+ if (typeof result.length === 'number' &&
1057
+ !(result.propertyIsEnumerable('length'))) {
1058
+ var converted = [];
1059
+ for (var i = 0; i < result.length; i++) {
1060
+ converted.push(parseReturnValueFromScript(result[i]));
1061
+ }
1062
+ return converted;
1063
+ }
1064
+
1065
+ // Script returned an element; return it's cached ID.
1066
+ if (typeof result.webdriverElementXPath === 'string') {
1067
+ //If we're returning an element, turn it into an actual element object
1068
+ var element = getElementsByXPath(result.webdriverElementXPath)[0];
1069
+ return {'ELEMENT': addElementToInternalArray(element).toString()};
1070
+ }
1071
+
1072
+ // We were given a plain-old JSON object. Parse each property.
1073
+ var convertedObj = {};
1074
+ for (var prop in result) {
1075
+ convertedObj[prop] = parseReturnValueFromScript(result[prop]);
1076
+ }
1077
+ return convertedObj;
1078
+
1079
+ // The script we inject to the page should never give us a result of type
1080
+ // 'function' or 'undefined', so we do not need to check for those, but
1081
+ // just go ahead and return null for completeness.
1082
+ case 'function':
1083
+ case 'undefined':
1084
+ default:
1085
+ return null;
964
1086
  }
965
- return value;
966
1087
  }
967
1088
 
968
1089
  /**
@@ -972,11 +1093,11 @@ function returnFromJavascriptInPage(e) {
972
1093
  if (e.prevValue == "EXCEPTION") {
973
1094
  ChromeDriverContentScript.port.postMessage({sequenceNumber: ChromeDriverContentScript.currentSequenceNumber,
974
1095
  response: {response: "execute", value: {statusCode: 17,
975
- message: "Tried to execute bad javascript."}}});
1096
+ value: {message: "Tried to execute bad javascript."}}}});
976
1097
  return;
977
1098
  }
978
1099
  console.log("Got result");
979
- console.log("Result was: " + e.newValue.value);
1100
+ console.log("Result was: " + e.newValue);
980
1101
  var result = JSON.parse(e.newValue).value;
981
1102
  var value = parseReturnValueFromScript(result);
982
1103
  console.log("Return value: " + JSON.stringify(value));
@@ -1013,7 +1134,7 @@ function returnFromGetFrameNameFromIndexJavascriptInPage(e) {
1013
1134
  if (e.prevValue == "EXCEPTION") {
1014
1135
  ChromeDriverContentScript.port.postMessage({sequenceNumber: ChromeDriverContentScript.currentSequenceNumber,
1015
1136
  response: {response: "getFrameNameFromIndex", value: {statusCode: 8,
1016
- message: "No such frame"}}});
1137
+ value: {message: "No such frame"}}}});
1017
1138
  } else {
1018
1139
  ChromeDriverContentScript.port.postMessage({sequenceNumber: ChromeDriverContentScript.currentSequenceNumber,
1019
1140
  response: {response: "getFrameNameFromIndex", value: {statusCode: "no-op",