selenium-webdriver 0.0.6 → 0.0.7
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/src/rb/lib/selenium/webdriver/chrome/bridge.rb +4 -0
- data/common/src/js/webelement.js +2 -1
- data/common/src/rb/lib/selenium/webdriver.rb +1 -0
- data/common/src/rb/lib/selenium/webdriver/child_process.rb +7 -1
- data/common/src/rb/lib/selenium/webdriver/driver.rb +21 -13
- data/common/src/rb/lib/selenium/webdriver/driver_extensions/takes_screenshot.rb +24 -0
- data/firefox/src/extension/components/driver-component.js +3 -3
- data/firefox/src/extension/components/firefoxDriver.js +51 -0
- data/firefox/src/extension/components/nsCommandProcessor.js +12 -0
- data/firefox/src/extension/components/promptService.js +208 -0
- data/firefox/src/extension/components/screenshooter.js +11 -0
- data/firefox/src/extension/components/utils.js +18 -1
- data/firefox/src/extension/components/webdriverserver.js +2 -2
- data/firefox/src/extension/components/wrappedElement.js +8 -2
- data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +23 -4
- data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +10 -2
- data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +4 -0
- data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +4 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +4 -0
- metadata +4 -2
data/common/src/js/webelement.js
CHANGED
@@ -465,7 +465,8 @@ webdriver.WebElement.prototype.getSize = function() {
|
|
465
465
|
webdriver.WebElement.createCoordinatesFromResponse_ = function(future,
|
466
466
|
response) {
|
467
467
|
var xy = response.value.replace(/\s/g, '').split(',');
|
468
|
-
response.value = new goog.math.Coordinate(
|
468
|
+
response.value = new goog.math.Coordinate(
|
469
|
+
Number(xy[0]), Number(xy[1]));
|
469
470
|
future.setValue(response.value);
|
470
471
|
};
|
471
472
|
|
@@ -9,6 +9,7 @@ require "selenium/webdriver/target_locator"
|
|
9
9
|
require "selenium/webdriver/navigation"
|
10
10
|
require "selenium/webdriver/options"
|
11
11
|
require "selenium/webdriver/find"
|
12
|
+
require "selenium/webdriver/driver_extensions/takes_screenshot"
|
12
13
|
require "selenium/webdriver/keys"
|
13
14
|
require "selenium/webdriver/bridge_helper"
|
14
15
|
require "selenium/webdriver/driver"
|
@@ -6,19 +6,27 @@ module Selenium
|
|
6
6
|
attr_reader :bridge
|
7
7
|
|
8
8
|
class << self
|
9
|
-
def for(
|
10
|
-
case
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
9
|
+
def for(browser, *args)
|
10
|
+
bridge = case browser
|
11
|
+
when :ie, :internet_explorer
|
12
|
+
WebDriver::IE::Bridge.new(*args)
|
13
|
+
when :remote
|
14
|
+
WebDriver::Remote::Bridge.new(*args)
|
15
|
+
when :chrome
|
16
|
+
WebDriver::Chrome::Bridge.new(*args)
|
17
|
+
when :firefox, :ff
|
18
|
+
WebDriver::Firefox::Bridge.new(*args)
|
19
|
+
else
|
20
|
+
raise ArgumentError, "unknown driver: #{driver.inspect}"
|
21
|
+
end
|
22
|
+
|
23
|
+
driver = new(bridge)
|
24
|
+
|
25
|
+
unless bridge.driver_extensions.empty?
|
26
|
+
driver.extend(*bridge.driver_extensions)
|
27
|
+
end
|
28
|
+
|
29
|
+
driver
|
22
30
|
end
|
23
31
|
end
|
24
32
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
3
|
+
module DriverExtensions
|
4
|
+
module TakesScreenshot
|
5
|
+
|
6
|
+
def save_screenshot(png_path)
|
7
|
+
File.open(png_path, 'w') { |f| f << screenshot_as(:png) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def screenshot_as(format)
|
11
|
+
case format
|
12
|
+
when :base64
|
13
|
+
bridge.getScreenshotAsBase64
|
14
|
+
when :png
|
15
|
+
bridge.getScreenshotAsBase64.unpack("m")[0]
|
16
|
+
else
|
17
|
+
raise Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end # TakesScreenshot
|
22
|
+
end # DriverExtensions
|
23
|
+
end # WebDriver
|
24
|
+
end # Selenium
|
@@ -86,11 +86,11 @@ var ServerFactory = {
|
|
86
86
|
|
87
87
|
//module definition (xpcom registration)
|
88
88
|
var ServerModule = {
|
89
|
-
|
89
|
+
firstTime_: true,
|
90
90
|
|
91
91
|
registerSelf: function(aCompMgr, aFileSpec, aLocation, aType) {
|
92
|
-
if (this.
|
93
|
-
this.
|
92
|
+
if (this.firstTime_) {
|
93
|
+
this.firstTime_ = false;
|
94
94
|
throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
|
95
95
|
}
|
96
96
|
aCompMgr =
|
@@ -242,6 +242,7 @@ FirefoxDriver.ElementLocator = {
|
|
242
242
|
ID: 'id',
|
243
243
|
NAME: 'name',
|
244
244
|
CLASS_NAME: 'class name',
|
245
|
+
CSS_SELECTOR: 'css selector',
|
245
246
|
TAG_NAME: 'tag name',
|
246
247
|
LINK_TEXT: 'link text',
|
247
248
|
PARTIAL_LINK_TEXT: 'partial link text',
|
@@ -291,6 +292,16 @@ FirefoxDriver.prototype.findElementInternal_ = function(respond, method,
|
|
291
292
|
selector + ' ")]', rootNode);
|
292
293
|
break;
|
293
294
|
|
295
|
+
case FirefoxDriver.ElementLocator.CSS_SELECTOR:
|
296
|
+
if (rootNode['querySelector']) {
|
297
|
+
element = rootNode.querySelector(selector);
|
298
|
+
} else {
|
299
|
+
respond.isError = true;
|
300
|
+
respond.response = "CSS Selectors not supported natively";
|
301
|
+
respond.send();
|
302
|
+
}
|
303
|
+
break;
|
304
|
+
|
294
305
|
case FirefoxDriver.ElementLocator.TAG_NAME:
|
295
306
|
element = rootNode.getElementsByTagName(selector)[0];
|
296
307
|
break;
|
@@ -401,6 +412,16 @@ FirefoxDriver.prototype.findElementsInternal_ = function(respond, method,
|
|
401
412
|
theDocument, './/*[@name="' + selector + '"]', rootNode);
|
402
413
|
break;
|
403
414
|
|
415
|
+
case FirefoxDriver.ElementLocator.CSS_SELECTOR:
|
416
|
+
if (rootNode['querySelector']) {
|
417
|
+
elements = rootNode.querySelectorAll(selector);
|
418
|
+
} else {
|
419
|
+
respond.isError = true;
|
420
|
+
respond.response = "CSS Selectors not supported natively";
|
421
|
+
respond.send();
|
422
|
+
}
|
423
|
+
break;
|
424
|
+
|
404
425
|
case FirefoxDriver.ElementLocator.TAG_NAME:
|
405
426
|
elements = rootNode.getElementsByTagName(selector);
|
406
427
|
break;
|
@@ -704,3 +725,33 @@ FirefoxDriver.prototype.saveScreenshot = function(respond, pngFile) {
|
|
704
725
|
}
|
705
726
|
respond.send();
|
706
727
|
};
|
728
|
+
|
729
|
+
|
730
|
+
FirefoxDriver.prototype.getScreenshotAsBase64 = function(respond) {
|
731
|
+
var window = Utils.getBrowser(respond.context).contentWindow;
|
732
|
+
try {
|
733
|
+
var canvas = Screenshooter.grab(window);
|
734
|
+
respond.isError = false;
|
735
|
+
respond.response = Screenshooter.toBase64(canvas);
|
736
|
+
} catch (e) {
|
737
|
+
respond.isError = true;
|
738
|
+
respond.response = 'Could not take screenshot of current page - ' + e;
|
739
|
+
}
|
740
|
+
respond.send();
|
741
|
+
};
|
742
|
+
|
743
|
+
FirefoxDriver.prototype.dismissAlert = function(respond, alertText) {
|
744
|
+
// TODO(simon): Is there a type for alerts?
|
745
|
+
var wm = Utils.getService("@mozilla.org/appshell/window-mediator;1", "nsIWindowMediator");
|
746
|
+
var allWindows = wm.getEnumerator("");
|
747
|
+
while (allWindows.hasMoreElements()) {
|
748
|
+
var alert = allWindows.getNext();
|
749
|
+
var doc = alert.document;
|
750
|
+
if (doc && doc.documentURI == "chrome://global/content/commonDialog.xul") {
|
751
|
+
var dialog = doc.getElementsByTagName("dialog")[0];
|
752
|
+
dialog.getButton("accept").click();
|
753
|
+
break;
|
754
|
+
}
|
755
|
+
}
|
756
|
+
respond.send();
|
757
|
+
};
|
@@ -96,12 +96,20 @@ Response.prototype = {
|
|
96
96
|
* Sends the encapsulated response to the registered callback.
|
97
97
|
*/
|
98
98
|
send: function() {
|
99
|
+
if (this.responseSent_) {
|
100
|
+
// We shouldn't ever send the same response twice.
|
101
|
+
return;
|
102
|
+
}
|
99
103
|
// Indicate that we are no longer executing a command.
|
100
104
|
if (this.statusBarLabel_) {
|
101
105
|
this.statusBarLabel_.style.color = 'black';
|
102
106
|
}
|
107
|
+
|
103
108
|
this.context = this.context.toString();
|
104
109
|
this.responseHandler_.handleResponse(JSON.stringify(this.json_));
|
110
|
+
|
111
|
+
// Neuter ourselves
|
112
|
+
this.responseSent_ = true;
|
105
113
|
},
|
106
114
|
|
107
115
|
/**
|
@@ -202,6 +210,10 @@ DelayedCommand.prototype.executeInternal_ = function() {
|
|
202
210
|
} else {
|
203
211
|
try {
|
204
212
|
this.response_.commandName = this.command_.commandName;
|
213
|
+
// TODO(simon): This is rampantly ugly, but allows an alert to kill the command
|
214
|
+
// TODO(simon): This is never cleared, but _should_ be okay, because send wipes itself
|
215
|
+
this.driver_.response_ = this.response_;
|
216
|
+
|
205
217
|
this.driver_[this.command_.commandName](
|
206
218
|
this.response_, this.command_.parameters);
|
207
219
|
} catch (e) {
|
@@ -0,0 +1,208 @@
|
|
1
|
+
// Spoof the prompt service. Interesting thread on mozillazine:
|
2
|
+
// http://www.mail-archive.com/dev-tech-xpcom@lists.mozilla.org/msg00193.html
|
3
|
+
|
4
|
+
const CC = Components.classes;
|
5
|
+
const CI = Components.interfaces;
|
6
|
+
|
7
|
+
const CONSOLE = CC["@mozilla.org/consoleservice;1"].getService(CI["nsIConsoleService"]);
|
8
|
+
|
9
|
+
function dumpn(message) {
|
10
|
+
try {
|
11
|
+
CONSOLE.logStringMessage(message + "\n");
|
12
|
+
} catch (e) {
|
13
|
+
dump(message + "\n");
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
// Spoof implementation
|
18
|
+
function DrivenPromptService() {
|
19
|
+
// as defined in nsPromptService.h
|
20
|
+
var ORIGINAL_PARENT_SERVICE_ID = "{A2112D6A-0E28-421f-B46A-25C0B308CBD0}";
|
21
|
+
|
22
|
+
// Keep a reference to the original service
|
23
|
+
var originalService = Components.classesByID[ORIGINAL_PARENT_SERVICE_ID].getService();
|
24
|
+
|
25
|
+
this.originalPromptService_ =
|
26
|
+
originalService.QueryInterface(Components.interfaces.nsIPromptService);
|
27
|
+
|
28
|
+
dumpn("Spoofing prompt service");
|
29
|
+
}
|
30
|
+
|
31
|
+
// Constants from nsIPromtService.idl
|
32
|
+
DrivenPromptService.prototype = {
|
33
|
+
BUTTON_POS_0: 1,
|
34
|
+
BUTTON_POS_1: 256,
|
35
|
+
BUTTON_POS_2: 65536,
|
36
|
+
|
37
|
+
// Button Title Flags (used to set the labels of buttons in the prompt)
|
38
|
+
BUTTON_TITLE_OK: 1,
|
39
|
+
BUTTON_TITLE_CANCEL: 2,
|
40
|
+
BUTTON_TITLE_YES: 3,
|
41
|
+
BUTTON_TITLE_NO: 4,
|
42
|
+
BUTTON_TITLE_SAVE: 5,
|
43
|
+
BUTTON_TITLE_DONT_SAVE: 6,
|
44
|
+
BUTTON_TITLE_REVERT: 7,
|
45
|
+
BUTTON_TITLE_IS_STRING: 127,
|
46
|
+
|
47
|
+
// Button Default Flags (used to select which button is the default one)
|
48
|
+
BUTTON_POS_0_DEFAULT: 0,
|
49
|
+
BUTTON_POS_1_DEFAULT: 16777216,
|
50
|
+
BUTTON_POS_2_DEFAULT: 33554432,
|
51
|
+
|
52
|
+
// Causes the buttons to be initially disabled. They are enabled after a
|
53
|
+
// timeout expires. The implementation may interpret this loosely as the
|
54
|
+
// intent is to ensure that the user does not click through a security dialog
|
55
|
+
// too quickly. Strictly speaking, the implementation could choose to ignore
|
56
|
+
// this flag.
|
57
|
+
BUTTON_DELAY_ENABLE: 67108864,
|
58
|
+
|
59
|
+
// Selects the standard set of OK/Cancel buttons.
|
60
|
+
STD_OK_CANCEL_BUTTONS: (this.BUTTON_TITLE_OK * this.BUTTON_POS_0) + (this.BUTTON_TITLE_CANCEL
|
61
|
+
* this.BUTTON_POS_1),
|
62
|
+
|
63
|
+
// Selects the standard set of Yes/No buttons.
|
64
|
+
STD_YES_NO_BUTTONS: (this.BUTTON_TITLE_YES * this.BUTTON_POS_0) + (this.BUTTON_TITLE_NO
|
65
|
+
* this.BUTTON_POS_1)
|
66
|
+
};
|
67
|
+
|
68
|
+
DrivenPromptService.prototype.findAssociatedDriver_ = function(window) {
|
69
|
+
var ww = CC["@mozilla.org/embedcomp/window-watcher;1"].getService(CI["nsIWindowWatcher"]);
|
70
|
+
|
71
|
+
// There might be an easy answer.
|
72
|
+
var win = ww.getChromeForWindow(window);
|
73
|
+
if (win) {
|
74
|
+
return win;
|
75
|
+
}
|
76
|
+
|
77
|
+
// There isn't. Grab the top window's default view
|
78
|
+
var parent = window ? window : ww.activeWindow;
|
79
|
+
if (parent.wrappedJSObject)
|
80
|
+
parent = parent.wrappedJSObject;
|
81
|
+
var top = parent.top;
|
82
|
+
|
83
|
+
// Now iterate over all open browsers to find the one we belong to
|
84
|
+
var wm = CC["@mozilla.org/appshell/window-mediator;1"].getService(CI["nsIWindowMediator"]);
|
85
|
+
var allWindows = wm.getEnumerator("navigator:browser");
|
86
|
+
while (allWindows.hasMoreElements()) {
|
87
|
+
var chrome = allWindows.getNext().QueryInterface(CI.nsIDOMWindow);
|
88
|
+
if (chrome.content == window) {
|
89
|
+
return chrome.fxdriver;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
// There's no meaningful way we can reach this.
|
94
|
+
return undefined;
|
95
|
+
};
|
96
|
+
|
97
|
+
DrivenPromptService.prototype.alert = function(aParent, aDialogTitle, aText) {
|
98
|
+
// Try to grab the top level window
|
99
|
+
var driver = this.findAssociatedDriver_(aParent);
|
100
|
+
|
101
|
+
if (driver && driver.response_) {
|
102
|
+
var res = driver.response_;
|
103
|
+
// TODO(simon): We can't rely on the normal JSON library here because it might not be available
|
104
|
+
// Come up with a cleaner way of doing this.
|
105
|
+
var json = "{ title: \"" + aDialogTitle + "\", text: \"" + aText + "\", __webdriverType: 'alert' }";
|
106
|
+
|
107
|
+
res.response = json;
|
108
|
+
res.send();
|
109
|
+
} else {
|
110
|
+
// TODO(simon): we should prevent the next command from blocking.
|
111
|
+
}
|
112
|
+
|
113
|
+
return this.originalPromptService_.alert(aParent, aDialogTitle, aText);
|
114
|
+
};
|
115
|
+
|
116
|
+
DrivenPromptService.prototype.alertCheck =
|
117
|
+
function(aParent, aDialogTitle, aText, aCheckMsg, aCheckState) {
|
118
|
+
return this.originalPromptService_.alertCheck(aParent, aDialogTitle, aText, aCheckMsg, aCheckState);
|
119
|
+
};
|
120
|
+
|
121
|
+
DrivenPromptService.prototype.confirm = function(aParent, aDialogTitle, aText) {
|
122
|
+
return this.originalPromptService_.confirm(aParent, aDialogTitle, aText);
|
123
|
+
};
|
124
|
+
|
125
|
+
DrivenPromptService.prototype.confirmCheck =
|
126
|
+
function(aParent, aDialogTitle, aText, aCheckMsg, aCheckState) {
|
127
|
+
return this.originalPromptService_.confirmCheck(aParent, aDialogTitle, aText, aCheckMsg, aCheckState);
|
128
|
+
};
|
129
|
+
|
130
|
+
DrivenPromptService.prototype.confirmEx =
|
131
|
+
function(aParent, aDialogTitle, aText, aButtonFlags, aButton0Title, aButton1Title, aButton2Title, aCheckMsg, aCheckState) {
|
132
|
+
return this.originalPromptService_.confirmEx(aParent, aDialogTitle, aText, aButtonFlags, aButton0Title, aButton1Title, aButton2Title, aCheckMsg, aCheckState);
|
133
|
+
};
|
134
|
+
|
135
|
+
DrivenPromptService.prototype.prompt =
|
136
|
+
function(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState) {
|
137
|
+
return this.originalPromptService_.prompt(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState);
|
138
|
+
};
|
139
|
+
|
140
|
+
DrivenPromptService.prototype.promptUsernameAndPassword =
|
141
|
+
function(aParent, aDialogTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState) {
|
142
|
+
return this.originalPromptService_.promptUsernameAndPassword(aParent, aDialogTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState);
|
143
|
+
};
|
144
|
+
|
145
|
+
DrivenPromptService.prototype.promptPassword =
|
146
|
+
function(aParent, aDialogTitle, aText, aPassword, aCheckMsg, aCheckState) {
|
147
|
+
return this.originalPromptService_.promptPassword(aParent, aDialogTitle, aText, aPassword, aCheckMsg, aCheckState);
|
148
|
+
};
|
149
|
+
|
150
|
+
DrivenPromptService.prototype.select =
|
151
|
+
function(aParent, aDialogTitle, aText, aCount, aSelectList, aOutSelection) {
|
152
|
+
return this.originalPromptService_.select(aParent, aDialogTitle, aText, aCount, aSelectList, aOutSelection);
|
153
|
+
};
|
154
|
+
|
155
|
+
const PROMPT_CONTRACT_ID = "@mozilla.org/embedcomp/prompt-service;1";
|
156
|
+
const DRIVEN_PROMPT_SERVICE_CLASS_ID = Components.ID('{e26dbdcd-d3ba-4ded-88c3-6cb07ee3e9e0}');
|
157
|
+
|
158
|
+
var service = undefined;
|
159
|
+
|
160
|
+
var PromptServiceSpoofFactory = {
|
161
|
+
createInstance: function (aOuter, aIID) {
|
162
|
+
if (aOuter != null)
|
163
|
+
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
164
|
+
if (service == undefined) {
|
165
|
+
service = new DrivenPromptService();
|
166
|
+
}
|
167
|
+
return service;
|
168
|
+
}
|
169
|
+
};
|
170
|
+
|
171
|
+
function PromptServiceSpoofModule() {
|
172
|
+
this.firstTime_ = true;
|
173
|
+
}
|
174
|
+
|
175
|
+
PromptServiceSpoofModule.prototype.registerSelf = function(aCompMgr, aFileSpec, aLocation, aType) {
|
176
|
+
if (this.firstTime_) {
|
177
|
+
this.firstTime_ = false;
|
178
|
+
throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
|
179
|
+
}
|
180
|
+
aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
181
|
+
aCompMgr.registerFactoryLocation(
|
182
|
+
DRIVEN_PROMPT_SERVICE_CLASS_ID, "Driven prompt service", PROMPT_CONTRACT_ID, aFileSpec, aLocation, aType);
|
183
|
+
};
|
184
|
+
|
185
|
+
PromptServiceSpoofModule.prototype.unregisterSelf = function(aCompMgr, aLocation, aType) {
|
186
|
+
dumpn("Unregistering\n");
|
187
|
+
aCompMgr =
|
188
|
+
aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
189
|
+
aCompMgr.unregisterFactoryLocation(DRIVEN_PROMPT_SERVICE_CLASS_ID, aLocation);
|
190
|
+
};
|
191
|
+
|
192
|
+
PromptServiceSpoofModule.prototype.getClassObject = function(aCompMgr, aCID, aIID) {
|
193
|
+
if (!aIID.equals(Components.interfaces.nsIFactory))
|
194
|
+
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
195
|
+
|
196
|
+
if (aCID.equals(DRIVEN_PROMPT_SERVICE_CLASS_ID))
|
197
|
+
return PromptServiceSpoofFactory;
|
198
|
+
|
199
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
200
|
+
};
|
201
|
+
|
202
|
+
PromptServiceSpoofModule.prototype.canUnload = function(aCompMgr) {
|
203
|
+
return true;
|
204
|
+
};
|
205
|
+
|
206
|
+
function NSGetModule(comMgr, fileSpec) {
|
207
|
+
return new PromptServiceSpoofModule();
|
208
|
+
}
|
@@ -42,6 +42,17 @@ Screenshooter.grab = function(window) {
|
|
42
42
|
};
|
43
43
|
|
44
44
|
|
45
|
+
Screenshooter.toBase64 = function(canvas) {
|
46
|
+
var dataUrl = canvas.toDataURL('image/png');
|
47
|
+
var index = dataUrl.indexOf('base64,');
|
48
|
+
if (index == -1) {
|
49
|
+
// No base64 data marker.
|
50
|
+
throw new Error("Invalid base64 data: " + dataUrl);
|
51
|
+
}
|
52
|
+
return dataUrl.substring(index + 'base64,'.length);
|
53
|
+
};
|
54
|
+
|
55
|
+
|
45
56
|
Screenshooter.save = function(canvas, filepath) {
|
46
57
|
var cc = Components.classes;
|
47
58
|
var ci = Components.interfaces;
|
@@ -1086,7 +1086,11 @@ Utils.findElementsByXPath = function (xpath, contextNode, context) {
|
|
1086
1086
|
|
1087
1087
|
|
1088
1088
|
Utils.getLocationOnceScrolledIntoView = function(element) {
|
1089
|
-
|
1089
|
+
// Some elements may not a scrollIntoView function - for example,
|
1090
|
+
// elements under an SVG element. Call those only if they exist.
|
1091
|
+
if (typeof element.scrollIntoView == 'function') {
|
1092
|
+
element.scrollIntoView(true);
|
1093
|
+
}
|
1090
1094
|
|
1091
1095
|
var retrieval = Utils.newInstance(
|
1092
1096
|
"@mozilla.org/accessibleRetrieval;1", "nsIAccessibleRetrieval");
|
@@ -1106,6 +1110,18 @@ Utils.getLocationOnceScrolledIntoView = function(element) {
|
|
1106
1110
|
};
|
1107
1111
|
}
|
1108
1112
|
|
1113
|
+
// Firefox 3.0.14 seems to have top, bottom attributes.
|
1114
|
+
if (clientRect['top'] !== undefined) {
|
1115
|
+
var retWidth = clientRect.right - clientRect.left;
|
1116
|
+
var retHeight = clientRect.bottom - clientRect.top;
|
1117
|
+
return {
|
1118
|
+
x : clientRect.left,
|
1119
|
+
y : clientRect.top,
|
1120
|
+
width: retWidth,
|
1121
|
+
height: retHeight
|
1122
|
+
}
|
1123
|
+
}
|
1124
|
+
|
1109
1125
|
// Firefox 3.0
|
1110
1126
|
Utils.dumpn("Falling back to firefox3 mechanism");
|
1111
1127
|
var accessible = retrieval.getAccessibleFor(element);
|
@@ -1125,6 +1141,7 @@ Utils.getLocationOnceScrolledIntoView = function(element) {
|
|
1125
1141
|
|
1126
1142
|
// Firefox 2.0
|
1127
1143
|
|
1144
|
+
Utils.dumpn("Falling back to firefox2 mechanism");
|
1128
1145
|
// Fallback. Use the (deprecated) method to find out where the element is in
|
1129
1146
|
// the viewport. This should be fine to use because we only fall down this
|
1130
1147
|
// code path on older versions of Firefox (I think!)
|
@@ -22,8 +22,7 @@ function WebDriverServer() {
|
|
22
22
|
this.serverSocket =
|
23
23
|
Components.classes["@mozilla.org/network/server-socket;1"].
|
24
24
|
createInstance(Components.interfaces.nsIServerSocket);
|
25
|
-
this.generator =
|
26
|
-
Utils.getService("@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
|
25
|
+
this.generator = Utils.getService("@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
|
27
26
|
this.enableNativeEvents = null;
|
28
27
|
}
|
29
28
|
|
@@ -43,6 +42,7 @@ WebDriverServer.prototype.newDriver = function(window) {
|
|
43
42
|
window.fxdriver = new FirefoxDriver(this, this.enableNativeEvents);
|
44
43
|
// Yuck. But it allows us to refer to it later.
|
45
44
|
window.fxdriver.window = window;
|
45
|
+
|
46
46
|
return window.fxdriver;
|
47
47
|
};
|
48
48
|
|
@@ -76,8 +76,14 @@ FirefoxDriver.prototype.click = function(respond) {
|
|
76
76
|
Utils.fireMouseEventOn(respond.context, element, "mousemove");
|
77
77
|
Utils.fireMouseEventOn(respond.context, element, "mousedown");
|
78
78
|
if (element != currentlyActive) {
|
79
|
-
|
80
|
-
element.
|
79
|
+
// Some elements may not have blur, focus functions - for example,
|
80
|
+
// elements under an SVG element. Call those only if they exist.
|
81
|
+
if (typeof currentlyActive.blur == 'function') {
|
82
|
+
currentlyActive.blur();
|
83
|
+
}
|
84
|
+
if (typeof element.focus == 'function') {
|
85
|
+
element.focus();
|
86
|
+
}
|
81
87
|
}
|
82
88
|
|
83
89
|
Utils.fireMouseEventOn(respond.context, element, "mouseup");
|
@@ -4,9 +4,15 @@ module Selenium
|
|
4
4
|
class Bridge
|
5
5
|
include BridgeHelper
|
6
6
|
|
7
|
-
def initialize
|
7
|
+
def initialize(opts = {})
|
8
8
|
@binary = Binary.new
|
9
|
-
@launcher = Launcher.new(
|
9
|
+
@launcher = Launcher.new(
|
10
|
+
@binary,
|
11
|
+
opts[:port] || DEFAULT_PORT,
|
12
|
+
opts[:profile] || DEFAULT_PROFILE_NAME
|
13
|
+
)
|
14
|
+
|
15
|
+
@launcher.launch
|
10
16
|
@connection = @launcher.connection
|
11
17
|
@context = newSession
|
12
18
|
end
|
@@ -15,6 +21,10 @@ module Selenium
|
|
15
21
|
:firefox
|
16
22
|
end
|
17
23
|
|
24
|
+
def driver_extensions
|
25
|
+
[DriverExtensions::TakesScreenshot]
|
26
|
+
end
|
27
|
+
|
18
28
|
def quit
|
19
29
|
@connection.quit
|
20
30
|
@binary.wait
|
@@ -33,6 +43,9 @@ module Selenium
|
|
33
43
|
execute :getCurrentWindowHandle
|
34
44
|
end
|
35
45
|
|
46
|
+
def getScreenshotAsBase64
|
47
|
+
execute :getScreenshotAsBase64
|
48
|
+
end
|
36
49
|
|
37
50
|
def get(url)
|
38
51
|
execute :get,
|
@@ -366,8 +379,14 @@ module Selenium
|
|
366
379
|
puts "<-- #{resp.inspect}" if $DEBUG
|
367
380
|
|
368
381
|
if resp['isError']
|
369
|
-
|
370
|
-
|
382
|
+
case resp['response']
|
383
|
+
when String
|
384
|
+
msg = resp['response']
|
385
|
+
when Hash
|
386
|
+
msg = resp['response']['message']
|
387
|
+
end
|
388
|
+
|
389
|
+
msg ||= resp.inspect
|
371
390
|
raise Error::WebDriverError, msg
|
372
391
|
end
|
373
392
|
|
@@ -66,8 +66,16 @@ HTTP
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
length
|
70
|
-
json_string
|
69
|
+
length = Integer(resp.split(":").last.strip)
|
70
|
+
json_string = ''
|
71
|
+
bytes_received = 0
|
72
|
+
|
73
|
+
until bytes_received == length
|
74
|
+
read_string = @socket.recv(length - bytes_received)
|
75
|
+
|
76
|
+
bytes_received += read_string.length
|
77
|
+
json_string << read_string
|
78
|
+
end
|
71
79
|
|
72
80
|
if json_string.empty?
|
73
81
|
raise Error::WebDriverError, "empty response from extension"
|
@@ -88,6 +88,10 @@ module Selenium
|
|
88
88
|
|
89
89
|
def create_copy
|
90
90
|
tmp_directory = Dir.mktmpdir("webdriver-rb-profilecopy")
|
91
|
+
|
92
|
+
# TODO: must be a better way..
|
93
|
+
FileUtils.rm_rf tmp_directory
|
94
|
+
FileUtils.mkdir_p File.dirname(tmp_directory), :mode => 0700
|
91
95
|
FileUtils.cp_r @directory, tmp_directory
|
92
96
|
|
93
97
|
Profile.new(tmp_directory)
|
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: selenium-webdriver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jari Bakken
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-22 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -66,6 +66,7 @@ files:
|
|
66
66
|
- common/src/rb/lib/selenium/webdriver/child_process.rb
|
67
67
|
- common/src/rb/lib/selenium/webdriver/core_ext/dir.rb
|
68
68
|
- common/src/rb/lib/selenium/webdriver/driver.rb
|
69
|
+
- common/src/rb/lib/selenium/webdriver/driver_extensions/takes_screenshot.rb
|
69
70
|
- common/src/rb/lib/selenium/webdriver/element.rb
|
70
71
|
- common/src/rb/lib/selenium/webdriver/error.rb
|
71
72
|
- common/src/rb/lib/selenium/webdriver/find.rb
|
@@ -108,6 +109,7 @@ files:
|
|
108
109
|
- firefox/src/extension/components/json2.js
|
109
110
|
- firefox/src/extension/components/keytest.html
|
110
111
|
- firefox/src/extension/components/nsCommandProcessor.js
|
112
|
+
- firefox/src/extension/components/promptService.js
|
111
113
|
- firefox/src/extension/components/screenshooter.js
|
112
114
|
- firefox/src/extension/components/socketListener.js
|
113
115
|
- firefox/src/extension/components/utils.js
|