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
|
@@ -187,8 +187,8 @@ Utils.fireHtmlEvent = function(element, eventName, callback) {
|
|
|
187
187
|
callback = function() {};
|
|
188
188
|
}
|
|
189
189
|
var args = [
|
|
190
|
-
{
|
|
191
|
-
|
|
190
|
+
{"ELEMENT": addElementToInternalArray(element)},
|
|
191
|
+
eventName
|
|
192
192
|
];
|
|
193
193
|
|
|
194
194
|
// We need to do this because event handlers refer to functions that
|
|
@@ -208,10 +208,10 @@ Utils.fireMouseEventOn = function(element, eventName) {
|
|
|
208
208
|
|
|
209
209
|
Utils.triggerMouseEvent = function(element, eventType, clientX, clientY) {
|
|
210
210
|
var args = [
|
|
211
|
-
{
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
{"ELEMENT": addElementToInternalArray(element)},
|
|
212
|
+
eventType,
|
|
213
|
+
clientX,
|
|
214
|
+
clientY
|
|
215
215
|
];
|
|
216
216
|
|
|
217
217
|
// We need to do this because event handlers refer to functions that
|
|
@@ -227,5 +227,5 @@ Utils.triggerMouseEvent = function(element, eventType, clientX, clientY) {
|
|
|
227
227
|
};
|
|
228
228
|
|
|
229
229
|
Utils.trim = function(str) {
|
|
230
|
-
|
|
231
|
-
}
|
|
230
|
+
return str.replace(/^\s*/, "").replace(/\s*$/, "");
|
|
231
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
module Selenium
|
|
2
2
|
module WebDriver
|
|
3
3
|
module Chrome
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
# @private
|
|
6
|
+
class Bridge < Remote::Bridge
|
|
6
7
|
|
|
7
8
|
def initialize
|
|
8
9
|
@executor = CommandExecutor.new
|
|
@@ -19,73 +20,22 @@ module Selenium
|
|
|
19
20
|
[DriverExtensions::TakesScreenshot]
|
|
20
21
|
end
|
|
21
22
|
|
|
22
|
-
def
|
|
23
|
-
|
|
24
|
-
:url => url
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def goBack
|
|
28
|
-
execute :request => 'goBack'
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def goForward
|
|
32
|
-
execute :request => 'goForward'
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def getCurrentUrl
|
|
36
|
-
execute :request => 'getCurrentUrl'
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def getTitle
|
|
40
|
-
execute :request => 'getTitle'
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def getPageSource
|
|
44
|
-
execute :request => 'getPageSource'
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def switchToWindow(name)
|
|
48
|
-
execute :request => 'switchToWindow',
|
|
49
|
-
:windowName => name
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def switchToFrame(id)
|
|
53
|
-
execute :request => 'switchToFrameByName',
|
|
54
|
-
:name => id
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def switchToDefaultContent
|
|
58
|
-
execute :request => "switchToDefaultContent"
|
|
23
|
+
def capabilities
|
|
24
|
+
@capabilities ||= Remote::Capabilities.chrome
|
|
59
25
|
end
|
|
60
26
|
|
|
61
27
|
def quit
|
|
62
28
|
begin
|
|
63
|
-
|
|
29
|
+
super
|
|
64
30
|
rescue IOError
|
|
65
31
|
end
|
|
66
32
|
|
|
67
|
-
@launcher.kill
|
|
68
33
|
@executor.close
|
|
34
|
+
@launcher.kill
|
|
69
35
|
end
|
|
70
36
|
|
|
71
|
-
def
|
|
72
|
-
execute :
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def refresh
|
|
76
|
-
execute :request => 'refresh'
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def getWindowHandles
|
|
80
|
-
execute :request => 'getWindowHandles'
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def getCurrentWindowHandle
|
|
84
|
-
execute :request => 'getCurrentWindowHandle'
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def getScreenshotAsBase64
|
|
88
|
-
execute :request => "screenshot"
|
|
37
|
+
def getScreenshot
|
|
38
|
+
execute :screenshot
|
|
89
39
|
end
|
|
90
40
|
|
|
91
41
|
def setSpeed(value)
|
|
@@ -96,91 +46,6 @@ module Selenium
|
|
|
96
46
|
@speed
|
|
97
47
|
end
|
|
98
48
|
|
|
99
|
-
def executeScript(script, *args)
|
|
100
|
-
typed_args = args.map { |e| wrap_script_argument(e) }
|
|
101
|
-
|
|
102
|
-
resp = execute :request => 'executeScript',
|
|
103
|
-
:script => script,
|
|
104
|
-
:args => typed_args
|
|
105
|
-
|
|
106
|
-
return if resp.nil?
|
|
107
|
-
unwrap_script_argument resp
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def addCookie(cookie)
|
|
111
|
-
execute :request => 'addCookie',
|
|
112
|
-
:cookie => cookie
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def deleteCookie(name)
|
|
116
|
-
execute :request => 'deleteCookie',
|
|
117
|
-
:name => name
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def getAllCookies
|
|
121
|
-
execute :request => 'getCookies'
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def deleteAllCookies
|
|
125
|
-
execute :request => 'deleteAllCookies'
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def findElementByClassName(parent, class_name)
|
|
129
|
-
find_element_by 'class name', class_name, parent
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def findElementsByClassName(parent, class_name)
|
|
133
|
-
find_elements_by 'class name', class_name, parent
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def findElementById(parent, id)
|
|
137
|
-
find_element_by 'id', id, parent
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def findElementsById(parent, id)
|
|
141
|
-
find_elements_by 'id', id, parent
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def findElementByLinkText(parent, link_text)
|
|
145
|
-
find_element_by 'link text', link_text, parent
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def findElementsByLinkText(parent, link_text)
|
|
149
|
-
find_elements_by 'link text', link_text, parent
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def findElementByPartialLinkText(parent, link_text)
|
|
153
|
-
find_element_by 'partial link text', link_text, parent
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def findElementsByPartialLinkText(parent, link_text)
|
|
157
|
-
find_elements_by 'partial link text', link_text, parent
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def findElementByName(parent, name)
|
|
161
|
-
find_element_by 'name', name, parent
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def findElementsByName(parent, name)
|
|
165
|
-
find_elements_by 'name', name, parent
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def findElementByTagName(parent, tag_name)
|
|
169
|
-
find_element_by 'tag name', tag_name, parent
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def findElementsByTagName(parent, tag_name)
|
|
173
|
-
find_elements_by 'tag name', tag_name, parent
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def findElementByXpath(parent, xpath)
|
|
177
|
-
find_element_by 'xpath', xpath, parent
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def findElementsByXpath(parent, xpath)
|
|
181
|
-
find_elements_by 'xpath', xpath, parent
|
|
182
|
-
end
|
|
183
|
-
|
|
184
49
|
def findElementByCssSelector(parent, selector)
|
|
185
50
|
find_element_by 'css selector', selector, parent
|
|
186
51
|
end
|
|
@@ -189,154 +54,27 @@ module Selenium
|
|
|
189
54
|
find_elements_by 'css selector', selector, parent
|
|
190
55
|
end
|
|
191
56
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
# Element functions
|
|
195
|
-
#
|
|
196
|
-
|
|
197
|
-
def clickElement(element)
|
|
198
|
-
execute :request => 'clickElement',
|
|
199
|
-
:elementId => element
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
def getElementTagName(element)
|
|
203
|
-
execute :request => 'getElementTagName',
|
|
204
|
-
:elementId => element
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def getElementAttribute(element, name)
|
|
208
|
-
execute :request => 'getElementAttribute',
|
|
209
|
-
:elementId => element,
|
|
210
|
-
:attribute => name
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def getElementValue(element)
|
|
214
|
-
execute :request => 'getElementValue',
|
|
215
|
-
:elementId => element
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def getElementText(element)
|
|
219
|
-
execute :request => 'getElementText',
|
|
220
|
-
:elementId => element
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def getElementLocation(element)
|
|
224
|
-
data = execute :request => 'getElementLocation',
|
|
225
|
-
:elementId => element
|
|
226
|
-
|
|
227
|
-
Point.new data['x'], data['y']
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
def getElementSize(element)
|
|
231
|
-
data = execute :request => 'getElementSize',
|
|
232
|
-
:elementId => element
|
|
233
|
-
|
|
234
|
-
Dimension.new data['width'], data['height']
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def sendKeysToElement(element, string)
|
|
238
|
-
execute :request => 'sendKeysToElement',
|
|
239
|
-
:elementId => element,
|
|
240
|
-
:keys => string.split(//u)
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
def clearElement(element)
|
|
244
|
-
execute :request => 'clearElement',
|
|
245
|
-
:elementId => element
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def isElementEnabled(element)
|
|
249
|
-
execute :request => 'isElementEnabled',
|
|
250
|
-
:elementId => element
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def isElementSelected(element)
|
|
254
|
-
execute :request => 'isElementSelected',
|
|
255
|
-
:elementId => element
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
def isElementDisplayed(element)
|
|
259
|
-
execute :request => 'isElementDisplayed',
|
|
260
|
-
:elementId => element
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
def submitElement(element)
|
|
264
|
-
execute :request => 'submitElement',
|
|
265
|
-
:elementId => element
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
def toggleElement(element)
|
|
269
|
-
execute :request => 'toggleElement',
|
|
270
|
-
:elementId => element
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
def setElementSelected(element)
|
|
274
|
-
execute :request => 'setElementSelected',
|
|
275
|
-
:elementId => element
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
def getElementValueOfCssProperty(element, prop)
|
|
279
|
-
execute :request => 'getElementValueOfCssProperty',
|
|
280
|
-
:elementId => element,
|
|
281
|
-
:css => prop
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def getActiveElement
|
|
285
|
-
Element.new self, element_id_from(execute(:request => 'getActiveElement'))
|
|
286
|
-
end
|
|
287
|
-
alias_method :switchToActiveElement, :getActiveElement
|
|
288
|
-
|
|
289
|
-
def hoverOverElement(element)
|
|
290
|
-
execute :request => 'hoverOverElement',
|
|
291
|
-
:elementId => element
|
|
57
|
+
def getAllCookies
|
|
58
|
+
execute :getCookies
|
|
292
59
|
end
|
|
293
60
|
|
|
294
|
-
def
|
|
295
|
-
|
|
296
|
-
execute :drag_element, {:id => element}, element, rigth_by, down_by
|
|
61
|
+
def deleteCookie(name)
|
|
62
|
+
execute :deleteCookie, :name => name
|
|
297
63
|
end
|
|
298
64
|
|
|
299
65
|
private
|
|
300
66
|
|
|
301
|
-
def
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
:id => parent,
|
|
305
|
-
:using => how,
|
|
306
|
-
:value => what
|
|
307
|
-
else
|
|
308
|
-
id = execute :request => 'findElement',
|
|
309
|
-
:using => how,
|
|
310
|
-
:value => what
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
Element.new self, element_id_from(id)
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
def find_elements_by(how, what, parent = nil)
|
|
317
|
-
if parent
|
|
318
|
-
ids = execute :request => 'findChildElements',
|
|
319
|
-
:id => parent,
|
|
320
|
-
:using => how,
|
|
321
|
-
:value => what
|
|
322
|
-
else
|
|
323
|
-
ids = execute :request => 'findElements',
|
|
324
|
-
:using => how,
|
|
325
|
-
:value => what
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
ids.map { |id| Element.new self, element_id_from(id) }
|
|
329
|
-
end
|
|
330
|
-
|
|
67
|
+
def execute(command_name, opts = {}, args = nil)
|
|
68
|
+
command = {:request => command_name}.merge(opts)
|
|
69
|
+
command.merge!(args) if args
|
|
331
70
|
|
|
332
|
-
|
|
71
|
+
command = camel_case_keys_in(command)
|
|
333
72
|
|
|
334
|
-
def execute(command)
|
|
335
73
|
puts "--> #{command.inspect}" if $DEBUG
|
|
336
74
|
resp = raw_execute command
|
|
337
75
|
puts "<-- #{resp.inspect}" if $DEBUG
|
|
338
76
|
|
|
339
|
-
code = resp['
|
|
77
|
+
code = resp['status']
|
|
340
78
|
if e = Error.for_code(code)
|
|
341
79
|
msg = resp['value']['message'] if resp['value']
|
|
342
80
|
msg ||= "unknown exception for #{command.inspect}"
|
|
@@ -352,6 +90,26 @@ module Selenium
|
|
|
352
90
|
@executor.execute command
|
|
353
91
|
end
|
|
354
92
|
|
|
93
|
+
#
|
|
94
|
+
# TODO(jari): fix this in the remote driver
|
|
95
|
+
#
|
|
96
|
+
|
|
97
|
+
def camel_case(string)
|
|
98
|
+
parts = string.split('_')
|
|
99
|
+
parts[1..-1].map { |e| e.capitalize! }
|
|
100
|
+
parts.join
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def camel_case_keys_in(hash)
|
|
104
|
+
h = {}
|
|
105
|
+
|
|
106
|
+
hash.each do |key, value|
|
|
107
|
+
h[camel_case(key.to_s)] = value
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
h
|
|
111
|
+
end
|
|
112
|
+
|
|
355
113
|
end # Bridge
|
|
356
114
|
end # Chrome
|
|
357
115
|
end # WebDriver
|
|
@@ -1,124 +1,126 @@
|
|
|
1
1
|
module Selenium
|
|
2
2
|
module WebDriver
|
|
3
3
|
module Chrome
|
|
4
|
-
class CommandExecutor
|
|
5
|
-
HTML_TEMPLATE = "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n%s"
|
|
6
|
-
JSON_TEMPLATE = "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n%s"
|
|
7
|
-
|
|
8
|
-
def initialize
|
|
9
|
-
@server = TCPServer.new(localhost, 0)
|
|
10
|
-
@queue = Queue.new
|
|
11
|
-
|
|
12
|
-
@accepted_any = false
|
|
13
|
-
@next_socket = nil
|
|
14
|
-
@listening = true
|
|
15
|
-
|
|
16
|
-
Thread.new { start_run_loop }
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def execute(command)
|
|
20
|
-
until accepted_any?
|
|
21
|
-
Thread.pass
|
|
22
|
-
sleep 0.01
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
json = command.to_json
|
|
26
|
-
data = JSON_TEMPLATE % [json.length, json]
|
|
27
|
-
|
|
28
|
-
@next_socket.write data
|
|
29
|
-
@next_socket.close
|
|
30
|
-
|
|
31
|
-
JSON.parse read_response(@queue.pop)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def close
|
|
35
|
-
stop_listening
|
|
36
|
-
close_sockets
|
|
37
|
-
@server.close unless @server.closed?
|
|
38
|
-
rescue IOError
|
|
39
|
-
nil
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def port
|
|
43
|
-
@server.addr[1]
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def uri
|
|
47
|
-
"http://localhost:#{port}/chromeCommandExecutor"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
private
|
|
51
|
-
|
|
52
|
-
def localhost
|
|
53
|
-
Platform.ironruby? ? "localhost" : "0.0.0.0" # yeah, weird..
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def start_run_loop
|
|
57
|
-
while(@listening) do
|
|
58
|
-
socket = @server.accept
|
|
59
|
-
|
|
60
|
-
if socket.read(1) == "G" # initial GET(s)
|
|
61
|
-
write_holding_page_to socket
|
|
62
|
-
else
|
|
63
|
-
if accepted_any?
|
|
64
|
-
@queue << socket
|
|
65
|
-
else
|
|
66
|
-
read_response(socket)
|
|
67
|
-
@accepted_any = true
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
rescue IOError, Errno::EBADF
|
|
72
|
-
raise unless @server.closed?
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def read_response(socket)
|
|
76
|
-
result = ''
|
|
77
|
-
seen_double_crlf = false
|
|
78
|
-
|
|
79
|
-
while line = next_line(socket)
|
|
80
|
-
seen_double_crlf = true if line.empty?
|
|
81
|
-
result << "#{line}\n" if seen_double_crlf
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
@next_socket = socket
|
|
85
|
-
|
|
86
|
-
result.strip!
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def accepted_any?
|
|
90
|
-
@accepted_any
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def close_sockets
|
|
94
|
-
@queue.pop.close until @queue.empty?
|
|
95
|
-
@next_socket.close if @next_socket
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def stop_listening
|
|
99
|
-
@listening = false
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def next_line(socket)
|
|
103
|
-
return if socket.closed?
|
|
104
|
-
input = socket.gets
|
|
105
|
-
|
|
106
|
-
raise Error::WebDriverError, "unexpected EOF from Chrome" if input.nil?
|
|
107
4
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
5
|
+
# @private
|
|
6
|
+
class CommandExecutor
|
|
7
|
+
HTML_TEMPLATE = "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n%s"
|
|
8
|
+
JSON_TEMPLATE = "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n%s"
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@server = TCPServer.new(localhost, 0)
|
|
12
|
+
@queue = Queue.new
|
|
13
|
+
|
|
14
|
+
@accepted_any = false
|
|
15
|
+
@next_socket = nil
|
|
16
|
+
@listening = true
|
|
17
|
+
|
|
18
|
+
Thread.new { start_run_loop }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def execute(command)
|
|
22
|
+
until accepted_any?
|
|
23
|
+
Thread.pass
|
|
24
|
+
sleep 0.01
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
json = command.to_json
|
|
28
|
+
data = JSON_TEMPLATE % [json.length, json]
|
|
29
|
+
|
|
30
|
+
@next_socket.write data
|
|
31
|
+
@next_socket.close
|
|
32
|
+
|
|
33
|
+
JSON.parse read_response(@queue.pop)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def close
|
|
37
|
+
stop_listening
|
|
38
|
+
close_sockets
|
|
39
|
+
@server.close unless @server.closed?
|
|
40
|
+
rescue IOError
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def port
|
|
45
|
+
@server.addr[1]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def uri
|
|
49
|
+
"http://localhost:#{port}/chromeCommandExecutor"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def localhost
|
|
55
|
+
Platform.ironruby? ? "localhost" : "0.0.0.0" # yeah, weird..
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def start_run_loop
|
|
59
|
+
while(@listening) do
|
|
60
|
+
socket = @server.accept
|
|
61
|
+
|
|
62
|
+
if socket.read(1) == "G" # initial GET(s)
|
|
63
|
+
write_holding_page_to socket
|
|
64
|
+
else
|
|
65
|
+
if accepted_any?
|
|
66
|
+
@queue << socket
|
|
67
|
+
else
|
|
68
|
+
read_response(socket)
|
|
69
|
+
@accepted_any = true
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
rescue IOError, Errno::EBADF
|
|
74
|
+
raise if @listening
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def read_response(socket)
|
|
78
|
+
result = ''
|
|
79
|
+
seen_double_crlf = false
|
|
80
|
+
|
|
81
|
+
while line = next_line(socket)
|
|
82
|
+
seen_double_crlf = true if line.empty?
|
|
83
|
+
result << "#{line}\n" if seen_double_crlf
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
@next_socket = socket
|
|
87
|
+
|
|
88
|
+
result.strip!
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def accepted_any?
|
|
92
|
+
@accepted_any
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def close_sockets
|
|
96
|
+
@next_socket.close if @next_socket
|
|
97
|
+
@queue.pop.close until @queue.empty?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def stop_listening
|
|
101
|
+
@listening = false
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def next_line(socket)
|
|
105
|
+
return if socket.closed?
|
|
106
|
+
input = socket.gets
|
|
107
|
+
|
|
108
|
+
raise Error::WebDriverError, "unexpected EOF from Chrome" if input.nil?
|
|
109
|
+
|
|
110
|
+
line = input.chomp
|
|
111
|
+
return if line == "EOResponse"
|
|
112
|
+
|
|
113
|
+
line
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def write_holding_page_to(socket)
|
|
117
|
+
msg = %[<html><head><script type='text/javascript'>if (window.location.search == '') { setTimeout("window.location = window.location.href + '?reloaded'", 5000); }</script></head><body><p>ChromeDriver server started and connected. Please leave this tab open.</p></body></html>]
|
|
118
|
+
|
|
119
|
+
socket.write HTML_TEMPLATE % [msg.length, msg]
|
|
120
|
+
socket.close
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end # CommandExecutor
|
|
122
124
|
end # Chrome
|
|
123
125
|
end # WebDriver
|
|
124
126
|
end # Selenium
|