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.
- data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
- data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
- data/chrome/src/extension/background.js +64 -48
- data/chrome/src/extension/content_script.js +253 -132
- data/chrome/src/extension/manifest-nonwin.json +1 -1
- data/chrome/src/extension/manifest-win.json +1 -1
- data/chrome/src/extension/utils.js +8 -8
- data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +9 -0
- data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +38 -280
- data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +119 -117
- data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +36 -26
- data/common/src/js/abstractcommandprocessor.js +9 -11
- data/common/src/js/command.js +159 -83
- data/common/src/js/core/RemoteRunner.html +2 -2
- data/common/src/js/core/TestRunner-splash.html +3 -3
- data/common/src/js/core/TestRunner.html +5 -17
- data/common/src/js/core/scripts/htmlutils.js +4208 -2506
- data/common/src/js/core/scripts/selenium-api.js +2 -2
- data/common/src/js/core/scripts/selenium-browserbot.js +66 -58
- data/common/src/js/core/scripts/selenium-version.js +1 -1
- data/common/src/js/localcommandprocessor.js +5 -19
- data/common/src/js/testcase.js +2 -0
- data/common/src/js/webdriver.js +63 -93
- data/common/src/js/webelement.js +40 -42
- data/common/src/rb/lib/selenium/webdriver.rb +23 -14
- data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +8 -35
- data/common/src/rb/lib/selenium/webdriver/child_process.rb +2 -0
- data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +1 -0
- data/common/src/rb/lib/selenium/webdriver/core_ext/string.rb +5 -0
- data/common/src/rb/lib/selenium/webdriver/driver.rb +20 -15
- data/common/src/rb/lib/selenium/webdriver/driver_extensions/takes_screenshot.rb +7 -2
- data/common/src/rb/lib/selenium/webdriver/element.rb +11 -2
- data/common/src/rb/lib/selenium/webdriver/error.rb +9 -5
- data/common/src/rb/lib/selenium/webdriver/keys.rb +1 -2
- data/common/src/rb/lib/selenium/webdriver/navigation.rb +16 -0
- data/common/src/rb/lib/selenium/webdriver/options.rb +32 -0
- data/common/src/rb/lib/selenium/webdriver/platform.rb +17 -1
- data/firefox/prebuilt/Win32/Release/webdriver-firefox.dll +0 -0
- data/firefox/src/extension/components/dispatcher.js +492 -0
- data/firefox/src/extension/components/driver-component.js +4 -1
- data/firefox/src/extension/components/errorcode.js +70 -0
- data/firefox/src/extension/components/firefoxDriver.js +173 -154
- data/firefox/src/extension/components/nsCommandProcessor.js +171 -132
- data/firefox/src/extension/components/promptService.js +5 -5
- data/firefox/src/extension/components/request.js +219 -0
- data/firefox/src/extension/components/response.js +276 -0
- data/firefox/src/extension/components/session.js +281 -0
- data/firefox/src/extension/components/sessionstore.js +226 -0
- data/firefox/src/extension/components/socketListener.js +350 -100
- data/firefox/src/extension/components/utils.js +166 -98
- data/firefox/src/extension/components/webdriverserver.js +9 -5
- data/firefox/src/extension/components/wrappedElement.js +189 -166
- data/firefox/src/extension/install.rdf +1 -1
- data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +2 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +39 -33
- data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +7 -421
- data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +7 -64
- data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +2 -3
- data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +54 -10
- data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +2 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +6 -0
- data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
- data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +2 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +38 -13
- data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +9 -2
- data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +5 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +2 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +42 -38
- data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +56 -47
- data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +26 -26
- data/remote/client/src/rb/lib/selenium/webdriver/remote/patron_http_client.rb +58 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +10 -12
- data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +2 -17
- metadata +44 -23
- data/common/src/js/context.js +0 -58
- data/firefox/src/extension/components/context.js +0 -37
|
Binary file
|
|
Binary file
|
|
@@ -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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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 "
|
|
453
|
-
|
|
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.
|
|
473
|
+
switchToFrame(request.id);
|
|
460
474
|
break;
|
|
461
475
|
case "switchToWindow":
|
|
462
476
|
ChromeDriver.hasHwnd = false;
|
|
463
|
-
if (request.
|
|
464
|
-
setActivePortByWindowName(request.
|
|
477
|
+
if (request.name !== undefined) {
|
|
478
|
+
setActivePortByWindowName(request.name);
|
|
465
479
|
} else {
|
|
466
480
|
sendResponseToParsedRequest({
|
|
467
|
-
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
563
|
+
sendResponseToParsedRequest({status: 99}, false);
|
|
550
564
|
return;
|
|
551
565
|
}
|
|
552
566
|
var base64 = snapshotDataUrl.substring(index + 'base64,'.length);
|
|
553
|
-
sendResponseToParsedRequest({
|
|
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 = {
|
|
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 = {
|
|
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({
|
|
631
|
+
sendResponseToParsedRequest({status: 0}, true);
|
|
617
632
|
} else {
|
|
618
|
-
sendResponseToParsedRequest({
|
|
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
|
-
|
|
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({
|
|
648
|
+
sendResponseToParsedRequest({status: 0}, true);
|
|
634
649
|
} else {
|
|
635
|
-
sendResponseToParsedRequest({
|
|
650
|
+
sendResponseToParsedRequest({status: 99}, true);
|
|
636
651
|
}
|
|
637
652
|
} catch(e) {
|
|
638
|
-
sendResponseToParsedRequest({
|
|
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({
|
|
659
|
+
sendResponseToParsedRequest({status: 0}, true);
|
|
645
660
|
} else {
|
|
646
|
-
sendResponseToParsedRequest({
|
|
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
|
-
|
|
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 {
|
|
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: '
|
|
779
|
+
parseRequest({request: 'switchToFrame', id: 0});
|
|
765
780
|
} else {
|
|
766
781
|
ChromeDriver.activePort = ChromeDriver.tabs[tab].mainPort;
|
|
767
|
-
sendResponseToParsedRequest({
|
|
782
|
+
sendResponseToParsedRequest({status: 0}, false);
|
|
768
783
|
}
|
|
769
784
|
return;
|
|
770
785
|
}
|
|
771
786
|
}
|
|
772
787
|
}
|
|
773
788
|
|
|
774
|
-
function switchToFrame(
|
|
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 (
|
|
783
|
-
switchToFrameByName(
|
|
784
|
-
} else if (
|
|
785
|
-
getFrameNameFromIndex(
|
|
797
|
+
if (typeof id == 'string') {
|
|
798
|
+
switchToFrameByName(id);
|
|
799
|
+
} else if (typeof id == 'number') {
|
|
800
|
+
getFrameNameFromIndex(id);
|
|
786
801
|
} else {
|
|
787
802
|
sendResponseToParsedRequest({
|
|
788
|
-
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
990
|
+
sendResponseToParsedRequest({status: 0}, false);
|
|
976
991
|
return;
|
|
977
992
|
}
|
|
978
993
|
}
|
|
979
|
-
sendResponseToParsedRequest({
|
|
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.
|
|
55
|
-
//If it seems an
|
|
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.
|
|
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.
|
|
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){}", {
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
512
|
+
toReturn = {
|
|
513
|
+
'ELEMENT': addElementToInternalArray(elements[0]).toString()
|
|
514
|
+
};
|
|
503
515
|
}
|
|
504
|
-
return {statusCode: 0, value:
|
|
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",
|
|
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",
|
|
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,
|
|
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(
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
var
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
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
|
|
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
|
|
873
|
-
* @param passedArgs array of arguments to pass to the
|
|
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
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
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
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
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
|
-
|
|
935
|
-
|
|
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
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
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
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
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
|
|
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",
|