Skip to content

Commit 00f4f2e

Browse files
committed
rb - initial implementation of marionette
1 parent 8615760 commit 00f4f2e

File tree

14 files changed

+1441
-10
lines changed

14 files changed

+1441
-10
lines changed

rb/lib/selenium/webdriver/common.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
require 'selenium/webdriver/common/core_ext/dir'
2121
require 'selenium/webdriver/common/core_ext/base64'
22+
require 'selenium/webdriver/common/w3c_error'
2223
require 'selenium/webdriver/common/error'
2324
require 'selenium/webdriver/common/platform'
2425
require 'selenium/webdriver/common/proxy'

rb/lib/selenium/webdriver/common/driver.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ def for(browser, opts = {})
4747

4848
bridge = case browser
4949
when :firefox, :ff
50-
Firefox::Bridge.new(opts)
50+
if Remote::W3CCapabilities.w3c?(opts)
51+
Firefox::W3CBridge.new(opts)
52+
else
53+
Firefox::Bridge.new(opts)
54+
end
5155
when :remote
5256
Remote::Bridge.new(opts)
5357
when :ie, :internet_explorer

rb/lib/selenium/webdriver/common/error.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,12 @@ class MoveTargetOutOfBoundsError < WebDriverError; end # 34
216216
class << self
217217
def for_code(code)
218218
return if [nil, 0].include? code
219+
return Errors[code - 1] if code.is_a? Fixnum
219220

220-
Errors[code - 1] || WebDriverError
221+
klass_name = code.split(' ').map(&:capitalize).join
222+
Error.const_get("#{klass_name}Error")
223+
rescue NameError
224+
WebDriverError
221225
end
222226
end
223227

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# encoding: utf-8
2+
#
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
module Selenium
21+
module WebDriver
22+
module Error
23+
24+
class WebDriverError < StandardError; end
25+
26+
#
27+
# An attempt was made to select an element that cannot be selected.
28+
#
29+
30+
class ElementNotSelectableError < WebDriverError; end
31+
32+
#
33+
# An element command could not be completed because the element is
34+
# not visible on the page.
35+
#
36+
37+
class ElementNotVisibleError < WebDriverError; end
38+
39+
#
40+
# The arguments passed to a command are either invalid or malformed.
41+
#
42+
43+
class InvalidArgumentError < WebDriverError; end
44+
45+
#
46+
# An illegal attempt was made to set a cookie under a different
47+
# domain than the current page.
48+
#
49+
50+
class InvalidCookieDomainError < WebDriverError; end
51+
52+
#
53+
# The coordinates provided to an interactions operation are invalid.
54+
#
55+
56+
class InvalidElementCoordinatesError < WebDriverError; end
57+
58+
#
59+
# An element command could not be completed because the element is
60+
# in an invalid state, e.g. attempting to click an element that is no
61+
# longer attached to the document.
62+
#
63+
64+
class InvalidElementStateError < WebDriverError; end
65+
66+
#
67+
# Argument was an invalid selector.
68+
#
69+
70+
class InvalidSelectorError < WebDriverError; end
71+
72+
#
73+
# Occurs if the given session id is not in the list of active sessions,
74+
# meaning the session either does not exist or that it’s not active.
75+
#
76+
77+
class InvalidSessionIdError < WebDriverError; end
78+
79+
#
80+
# An error occurred while executing JavaScript supplied by the user.
81+
#
82+
83+
class JavascriptErrorError < WebDriverError; end
84+
85+
#
86+
# The target for mouse interaction is not in the browser’s viewport and
87+
# cannot be brought into that viewport.
88+
#
89+
90+
class MoveTargetOutOfBoundsError < WebDriverError; end
91+
92+
#
93+
# An attempt was made to operate on a modal dialog when one was not open.
94+
#
95+
96+
class NoSuchAlertError < WebDriverError; end
97+
98+
#
99+
# An element could not be located on the page using the given
100+
# search parameters.
101+
#
102+
103+
class NoSuchElementError < WebDriverError; end
104+
105+
#
106+
# A request to switch to a frame could not be satisfied because the
107+
# frame could not be found.
108+
#
109+
110+
class NoSuchFrameError < WebDriverError; end
111+
112+
#
113+
# A request to switch to a window could not be satisfied because the
114+
# window could not be found.
115+
#
116+
117+
class NoSuchWindowError < WebDriverError; end
118+
119+
#
120+
# A script did not complete before its timeout expired.
121+
#
122+
123+
class ScriptTimeoutError < WebDriverError; end
124+
125+
#
126+
# A new session could not be created.
127+
#
128+
129+
class SessionNotCreatedError < WebDriverError; end
130+
131+
#
132+
# An element command failed because the referenced element is no longer
133+
# attached to the DOM.
134+
#
135+
136+
class StaleElementReferenceError < WebDriverError; end
137+
138+
#
139+
# An operation did not complete before its timeout expired.
140+
#
141+
142+
class TimeoutError < WebDriverError; end
143+
144+
#
145+
# A request to set a cookie’s value could not be satisfied.
146+
#
147+
148+
class UnableToSetCookieError < WebDriverError; end
149+
150+
#
151+
# A screen capture was made impossible.
152+
#
153+
154+
class UnableToCaptureScreenError < WebDriverError; end
155+
156+
#
157+
# A modal dialog was open, blocking this operation.
158+
#
159+
160+
class UnexpectedAlertOpenError < WebDriverError; end
161+
162+
#
163+
# An unknown error occurred in the remote end while processing
164+
# the command.
165+
#
166+
167+
class UnknownErrorError < WebDriverError; end
168+
169+
#
170+
# The requested command matched a known URL but did not match a
171+
# method for that URL.
172+
#
173+
174+
class UnknownMethodError < WebDriverError; end
175+
176+
#
177+
# Indicates that a command that should have executed properly cannot be supported for some reason.
178+
#
179+
180+
class UnsupportedOperationError < WebDriverError; end
181+
182+
183+
end # Error
184+
end # WebDriver
185+
end # Selenium

rb/lib/selenium/webdriver/firefox.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
require 'selenium/webdriver/firefox/profile'
2929
require 'selenium/webdriver/firefox/launcher'
3030
require 'selenium/webdriver/firefox/bridge'
31+
require 'selenium/webdriver/firefox/w3c_bridge'
32+
require 'selenium/webdriver/firefox/binary'
33+
require 'selenium/webdriver/firefox/service'
3134

3235
module Selenium
3336
module WebDriver

rb/lib/selenium/webdriver/firefox/binary.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ def path
149149
@path
150150
end
151151

152+
def version
153+
`#{path} -v`.strip[/[^\s]*$/][/^\d+/].to_i
154+
end
155+
152156
private
153157

154158
def windows_path
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# encoding: utf-8
2+
#
3+
# Licensed to the Software Freedom Conservancy (SFC) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The SFC licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
20+
module Selenium
21+
module WebDriver
22+
module Firefox
23+
24+
#
25+
# @api private
26+
#
27+
class Service
28+
START_TIMEOUT = 20
29+
SOCKET_LOCK_TIMEOUT = 45
30+
STOP_TIMEOUT = 5
31+
DEFAULT_PORT = 4444
32+
MISSING_TEXT = "Unable to find Mozilla Wires. Please download the executable from https://github.com/jgraham/wires/releases"
33+
34+
def self.executable_path
35+
@executable_path ||= (
36+
path = Platform.find_binary "wires"
37+
path or raise Error::WebDriverError, MISSING_TEXT
38+
Platform.assert_executable path
39+
40+
path
41+
)
42+
end
43+
44+
def self.executable_path=(path)
45+
Platform.assert_executable path
46+
@executable_path = path
47+
end
48+
49+
def self.default_service(*extra_args)
50+
new executable_path, DEFAULT_PORT, *extra_args
51+
end
52+
53+
def initialize(executable_path, port, *extra_args)
54+
@executable_path = executable_path
55+
@host = Platform.localhost
56+
@port = Integer(port)
57+
58+
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
59+
60+
@extra_args = extra_args
61+
end
62+
63+
def start
64+
Platform.exit_hook { stop } # make sure we don't leave the server running
65+
66+
socket_lock.locked do
67+
find_free_port
68+
start_process
69+
connect_until_stable
70+
end
71+
end
72+
73+
def stop
74+
return if @process.nil? || @process.exited?
75+
76+
Net::HTTP.start(@host, @port) do |http|
77+
http.open_timeout = STOP_TIMEOUT / 2
78+
http.read_timeout = STOP_TIMEOUT / 2
79+
80+
http.head("/shutdown")
81+
end
82+
83+
@process.poll_for_exit STOP_TIMEOUT
84+
rescue ChildProcess::TimeoutError
85+
# ok, force quit
86+
@process.stop STOP_TIMEOUT
87+
end
88+
89+
def uri
90+
URI.parse "http://#{@host}:#{@port}"
91+
end
92+
93+
def find_free_port
94+
@port = PortProber.above @port
95+
end
96+
97+
def start_process
98+
server_command = [@executable_path, "--binary=#{Firefox::Binary.path}", "--webdriver-port=#{@port}", *@extra_args]
99+
@process = ChildProcess.build(*server_command)
100+
101+
@process.io.inherit! if $DEBUG == true
102+
@process.start
103+
end
104+
105+
def connect_until_stable
106+
@socket_poller = SocketPoller.new @host, @port, START_TIMEOUT
107+
108+
unless @socket_poller.connected?
109+
raise Error::WebDriverError, "unable to connect to Mozilla Wires #{@host}:#{@port}"
110+
end
111+
end
112+
113+
def socket_lock
114+
@socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
115+
end
116+
117+
end # Service
118+
end # Firefox
119+
end # WebDriver
120+
end # Service

0 commit comments

Comments
 (0)