selenium-webdriver 2.53.4 → 3.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. data/CHANGES +24 -18
  2. data/README.md +2 -3
  3. data/lib/selenium/server.rb +64 -68
  4. data/lib/selenium/webdriver.rb +5 -9
  5. data/lib/selenium/webdriver/chrome.rb +18 -3
  6. data/lib/selenium/webdriver/chrome/bridge.rb +13 -16
  7. data/lib/selenium/webdriver/chrome/profile.rb +7 -9
  8. data/lib/selenium/webdriver/chrome/service.rb +8 -84
  9. data/lib/selenium/webdriver/common.rb +1 -2
  10. data/lib/selenium/webdriver/common/action_builder.rb +28 -38
  11. data/lib/selenium/webdriver/common/alert.rb +7 -10
  12. data/lib/selenium/webdriver/common/bridge_helper.rb +10 -15
  13. data/lib/selenium/webdriver/common/driver.rb +19 -28
  14. data/lib/selenium/webdriver/common/driver_extensions/has_input_devices.rb +0 -3
  15. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +4 -6
  16. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +4 -5
  17. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +0 -2
  18. data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +0 -2
  19. data/lib/selenium/webdriver/common/driver_extensions/has_touch_screen.rb +0 -2
  20. data/lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb +0 -3
  21. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +3 -6
  22. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +2 -5
  23. data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +2 -5
  24. data/lib/selenium/webdriver/common/element.rb +27 -29
  25. data/lib/selenium/webdriver/common/error.rb +17 -20
  26. data/lib/selenium/webdriver/common/file_reaper.rb +3 -9
  27. data/lib/selenium/webdriver/common/html5/local_storage.rb +6 -8
  28. data/lib/selenium/webdriver/common/html5/session_storage.rb +6 -8
  29. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +6 -15
  30. data/lib/selenium/webdriver/common/keyboard.rb +7 -12
  31. data/lib/selenium/webdriver/common/keys.rb +67 -69
  32. data/lib/selenium/webdriver/common/log_entry.rb +3 -4
  33. data/lib/selenium/webdriver/common/logs.rb +2 -4
  34. data/lib/selenium/webdriver/common/mouse.rb +9 -12
  35. data/lib/selenium/webdriver/common/navigation.rb +2 -4
  36. data/lib/selenium/webdriver/common/options.rb +16 -19
  37. data/lib/selenium/webdriver/common/platform.rb +61 -90
  38. data/lib/selenium/webdriver/common/port_prober.rb +1 -2
  39. data/lib/selenium/webdriver/common/profile_helper.rb +5 -8
  40. data/lib/selenium/webdriver/common/proxy.rb +58 -70
  41. data/lib/selenium/webdriver/common/search_context.rb +15 -19
  42. data/lib/selenium/webdriver/common/service.rb +127 -0
  43. data/lib/selenium/webdriver/common/socket_lock.rb +5 -11
  44. data/lib/selenium/webdriver/common/socket_poller.rb +4 -9
  45. data/lib/selenium/webdriver/common/target_locator.rb +11 -13
  46. data/lib/selenium/webdriver/common/timeouts.rb +4 -6
  47. data/lib/selenium/webdriver/common/touch_action_builder.rb +2 -4
  48. data/lib/selenium/webdriver/common/touch_screen.rb +15 -18
  49. data/lib/selenium/webdriver/common/w3c_error.rb +3 -6
  50. data/lib/selenium/webdriver/common/wait.rb +6 -11
  51. data/lib/selenium/webdriver/common/window.rb +12 -15
  52. data/lib/selenium/webdriver/common/zipper.rb +6 -8
  53. data/lib/selenium/webdriver/edge.rb +18 -3
  54. data/lib/selenium/webdriver/edge/bridge.rb +11 -16
  55. data/lib/selenium/webdriver/edge/legacy_support.rb +38 -39
  56. data/lib/selenium/webdriver/edge/service.rb +8 -82
  57. data/lib/selenium/webdriver/firefox.rb +25 -6
  58. data/lib/selenium/webdriver/firefox/binary.rb +37 -53
  59. data/lib/selenium/webdriver/firefox/bridge.rb +3 -6
  60. data/lib/selenium/webdriver/firefox/extension.rb +4 -6
  61. data/lib/selenium/webdriver/firefox/extension/prefs.json +1 -10
  62. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  63. data/lib/selenium/webdriver/firefox/launcher.rb +8 -11
  64. data/lib/selenium/webdriver/firefox/profile.rb +40 -42
  65. data/lib/selenium/webdriver/firefox/profiles_ini.rb +8 -15
  66. data/lib/selenium/webdriver/firefox/service.rb +23 -79
  67. data/lib/selenium/webdriver/firefox/util.rb +0 -2
  68. data/lib/selenium/webdriver/firefox/w3c_bridge.rb +2 -4
  69. data/lib/selenium/webdriver/ie.rb +16 -7
  70. data/lib/selenium/webdriver/ie/bridge.rb +16 -23
  71. data/lib/selenium/webdriver/{iphone.rb → ie/service.rb} +26 -4
  72. data/lib/selenium/webdriver/phantomjs.rb +8 -3
  73. data/lib/selenium/webdriver/phantomjs/bridge.rb +9 -11
  74. data/lib/selenium/webdriver/phantomjs/service.rb +17 -81
  75. data/lib/selenium/webdriver/remote.rb +0 -2
  76. data/lib/selenium/webdriver/remote/bridge.rb +193 -191
  77. data/lib/selenium/webdriver/remote/capabilities.rb +60 -90
  78. data/lib/selenium/webdriver/remote/commands.rb +197 -192
  79. data/lib/selenium/webdriver/remote/http/common.rb +15 -13
  80. data/lib/selenium/webdriver/remote/http/curb.rb +5 -9
  81. data/lib/selenium/webdriver/remote/http/default.rb +32 -37
  82. data/lib/selenium/webdriver/remote/http/persistent.rb +4 -6
  83. data/lib/selenium/webdriver/remote/response.rb +13 -21
  84. data/lib/selenium/webdriver/remote/server_error.rb +1 -3
  85. data/lib/selenium/webdriver/remote/w3c_bridge.rb +200 -195
  86. data/lib/selenium/webdriver/remote/w3c_capabilities.rb +38 -46
  87. data/lib/selenium/webdriver/remote/w3c_commands.rb +116 -113
  88. data/lib/selenium/webdriver/safari.rb +23 -7
  89. data/lib/selenium/{client/javascript_frameworks/jquery.rb → webdriver/safari/apple_bridge.rb} +28 -9
  90. data/lib/selenium/webdriver/safari/browser.rb +0 -2
  91. data/lib/selenium/webdriver/safari/{bridge.rb → legacy_bridge.rb} +12 -9
  92. data/lib/selenium/webdriver/safari/options.rb +3 -4
  93. data/lib/selenium/webdriver/safari/resources/client.js +56 -7255
  94. data/lib/selenium/webdriver/safari/server.rb +18 -24
  95. data/lib/selenium/{client/javascript_frameworks/prototype.rb → webdriver/safari/service.rb} +27 -9
  96. data/lib/selenium/webdriver/support.rb +1 -0
  97. data/lib/selenium/webdriver/support/abstract_event_listener.rb +17 -2
  98. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -3
  99. data/lib/selenium/webdriver/support/color.rb +55 -38
  100. data/lib/selenium/webdriver/{android.rb → support/escaper.rb} +19 -4
  101. data/lib/selenium/webdriver/support/event_firing_bridge.rb +36 -38
  102. data/lib/selenium/webdriver/support/select.rb +33 -84
  103. data/selenium-webdriver.gemspec +23 -23
  104. metadata +19 -30
  105. data/lib/selenium-client.rb +0 -21
  106. data/lib/selenium/client.rb +0 -57
  107. data/lib/selenium/client/base.rb +0 -151
  108. data/lib/selenium/client/driver.rb +0 -29
  109. data/lib/selenium/client/errors.rb +0 -28
  110. data/lib/selenium/client/extensions.rb +0 -132
  111. data/lib/selenium/client/idiomatic.rb +0 -507
  112. data/lib/selenium/client/javascript_expression_builder.rb +0 -135
  113. data/lib/selenium/client/legacy_driver.rb +0 -1722
  114. data/lib/selenium/client/protocol.rb +0 -123
  115. data/lib/selenium/client/selenium_helper.rb +0 -49
  116. data/lib/selenium/rake/server_task.rb +0 -176
  117. data/lib/selenium/webdriver/android/bridge.rb +0 -68
  118. data/lib/selenium/webdriver/common/core_ext/base64.rb +0 -28
  119. data/lib/selenium/webdriver/common/core_ext/dir.rb +0 -61
  120. data/lib/selenium/webdriver/common/html5/location.rb +0 -19
  121. data/lib/selenium/webdriver/ie/server.rb +0 -133
  122. data/lib/selenium/webdriver/iphone/bridge.rb +0 -64
@@ -38,7 +38,7 @@ module Selenium
38
38
  port
39
39
  end
40
40
 
41
- IGNORED_ERRORS = [Errno::EADDRNOTAVAIL]
41
+ IGNORED_ERRORS = [Errno::EADDRNOTAVAIL].freeze
42
42
  IGNORED_ERRORS << Errno::EBADF if Platform.cygwin?
43
43
 
44
44
  def self.free?(port)
@@ -55,7 +55,6 @@ module Selenium
55
55
  rescue SocketError, Errno::EADDRINUSE
56
56
  false
57
57
  end
58
-
59
58
  end # PortProber
60
59
  end # WebDriver
61
60
  end # Selenium
@@ -19,7 +19,6 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
-
23
22
  #
24
23
  # @api private
25
24
  #
@@ -28,27 +27,26 @@ module Selenium
28
27
  #
29
28
 
30
29
  module ProfileHelper
31
-
32
30
  def self.included(base)
33
31
  base.extend ClassMethods
34
32
  end
35
33
 
36
- def as_json(opts = nil)
34
+ def as_json(*)
37
35
  {'zip' => Zipper.zip(layout_on_disk)}
38
36
  end
39
37
 
40
- def to_json(*args)
38
+ def to_json(*)
41
39
  JSON.generate as_json
42
40
  end
43
41
 
44
42
  private
45
43
 
46
44
  def create_tmp_copy(directory)
47
- tmp_directory = Dir.mktmpdir("webdriver-rb-profilecopy")
45
+ tmp_directory = Dir.mktmpdir('webdriver-rb-profilecopy')
48
46
 
49
47
  # TODO: must be a better way..
50
48
  FileUtils.rm_rf tmp_directory
51
- FileUtils.mkdir_p File.dirname(tmp_directory), :mode => 0700
49
+ FileUtils.mkdir_p File.dirname(tmp_directory), mode: 0700
52
50
  FileUtils.cp_r directory, tmp_directory
53
51
 
54
52
  tmp_directory
@@ -72,7 +70,7 @@ module Selenium
72
70
  tmp_dir = Dir.mktmpdir
73
71
  begin
74
72
  zip_path = File.join(tmp_dir, "webdriver-profile-duplicate-#{json.hash}.zip")
75
- File.open(zip_path, "wb") { |zip_file| zip_file << Base64.decode64(data) }
73
+ File.open(zip_path, 'wb') { |zip_file| zip_file << Base64.decode64(data) }
76
74
 
77
75
  new Zipper.unzip(zip_path)
78
76
  ensure
@@ -80,7 +78,6 @@ module Selenium
80
78
  end
81
79
  end
82
80
  end # ClassMethods
83
-
84
81
  end # ProfileHelper
85
82
  end # WebDriver
86
83
  end # Selenium
@@ -21,45 +21,56 @@ module Selenium
21
21
  module WebDriver
22
22
  class Proxy
23
23
  TYPES = {
24
- :direct => "DIRECT", # Direct connection, no proxy (default on Windows).
25
- :manual => "MANUAL", # Manual proxy settings (e.g., for httpProxy).
26
- :pac => "PAC", # Proxy autoconfiguration from URL.
27
- :auto_detect => "AUTODETECT", # Proxy autodetection (presumably with WPAD).
28
- :system => "SYSTEM" # Use system settings (default on Linux).
29
- }
30
-
31
- attr_reader :type,
32
- :ftp,
33
- :http,
34
- :socks,
35
- :socks_username,
36
- :socks_password,
37
- :no_proxy,
38
- :pac,
39
- :ssl,
40
- :auto_detect
24
+ direct: 'DIRECT', # Direct connection, no proxy (default on Windows).
25
+ manual: 'MANUAL', # Manual proxy settings (e.g., for httpProxy).
26
+ pac: 'PAC', # Proxy autoconfiguration from URL.
27
+ auto_detect: 'AUTODETECT', # Proxy autodetection (presumably with WPAD).
28
+ system: 'SYSTEM' # Use system settings (default on Linux).
29
+ }.freeze
30
+
31
+ ALLOWED = {type: 'proxyType',
32
+ ftp: 'ftpProxy',
33
+ http: 'httpProxy',
34
+ no_proxy: 'noProxy',
35
+ pac: 'proxyAutoconfigUrl',
36
+ ssl: 'sslProxy',
37
+ auto_detect: 'autodetect',
38
+ socks: 'socksProxy',
39
+ socks_username: 'socksUsername',
40
+ socks_password: 'socksPassword'}.freeze
41
+
42
+ ALLOWED.keys.each { |t| attr_reader t }
43
+
44
+ def self.json_create(data)
45
+ data['proxyType'] = data['proxyType'].downcase.to_sym
46
+ return if data['proxyType'] == :unspecified
47
+
48
+ proxy = new
49
+
50
+ ALLOWED.each do |k, v|
51
+ proxy.send("#{k}=", data[v]) if data.key?(v)
52
+ end
53
+
54
+ proxy
55
+ end
41
56
 
42
57
  def initialize(opts = {})
43
- opts = opts.dup
44
-
45
- self.type = opts.delete(:type) if opts.has_key? :type
46
- self.ftp = opts.delete(:ftp) if opts.has_key? :ftp
47
- self.http = opts.delete(:http) if opts.has_key? :http
48
- self.no_proxy = opts.delete(:no_proxy) if opts.has_key? :no_proxy
49
- self.ssl = opts.delete(:ssl) if opts.has_key? :ssl
50
- self.pac = opts.delete(:pac) if opts.has_key? :pac
51
- self.auto_detect = opts.delete(:auto_detect) if opts.has_key? :auto_detect
52
- self.socks = opts.delete(:socks) if opts.has_key? :socks
53
- self.socks_username = opts.delete(:socks_username) if opts.has_key? :socks_username
54
- self.socks_password = opts.delete(:socks_password) if opts.has_key? :socks_password
55
-
56
- unless opts.empty?
57
- raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
58
+ not_allowed = []
59
+
60
+ opts.each do |k, v|
61
+ if ALLOWED.key?(k)
62
+ send("#{k}=", v)
63
+ else
64
+ not_allowed << k
65
+ end
58
66
  end
67
+
68
+ return if not_allowed.empty?
69
+ raise ArgumentError, "unknown option#{'s' if not_allowed.size != 1}: #{not_allowed.inspect}"
59
70
  end
60
71
 
61
72
  def ==(other)
62
- other.kind_of?(self.class) && as_json == other.as_json
73
+ other.is_a?(self.class) && as_json == other.as_json
63
74
  end
64
75
  alias_method :eql?, :==
65
76
 
@@ -109,7 +120,7 @@ module Selenium
109
120
  end
110
121
 
111
122
  def type=(type)
112
- unless TYPES.has_key? type
123
+ unless TYPES.key? type
113
124
  raise ArgumentError, "invalid proxy type: #{type.inspect}, expected one of #{TYPES.keys.inspect}"
114
125
  end
115
126
 
@@ -120,49 +131,26 @@ module Selenium
120
131
  @type = type
121
132
  end
122
133
 
123
- def as_json(opts = nil)
134
+ def as_json(*)
124
135
  json_result = {
125
- "proxyType" => TYPES[type]
126
- }
127
-
128
- json_result["ftpProxy"] = ftp if ftp
129
- json_result["httpProxy"] = http if http
130
- json_result["noProxy"] = no_proxy if no_proxy
131
- json_result["proxyAutoconfigUrl"] = pac if pac
132
- json_result["sslProxy"] = ssl if ssl
133
- json_result["autodetect"] = auto_detect if auto_detect
134
- json_result["socksProxy"] = socks if socks
135
- json_result["socksUsername"] = socks_username if socks_username
136
- json_result["socksPassword"] = socks_password if socks_password
136
+ 'proxyType' => TYPES[type],
137
+ 'ftpProxy' => ftp,
138
+ 'httpProxy' => http,
139
+ 'noProxy' => no_proxy,
140
+ 'proxyAutoconfigUrl' => pac,
141
+ 'sslProxy' => ssl,
142
+ 'autodetect' => auto_detect,
143
+ 'socksProxy' => socks,
144
+ 'socksUsername' => socks_username,
145
+ 'socksPassword' => socks_password
146
+ }.delete_if { |_k, v| v.nil? }
137
147
 
138
148
  json_result if json_result.length > 1
139
149
  end
140
150
 
141
- def to_json(*args)
151
+ def to_json(*)
142
152
  JSON.generate as_json
143
153
  end
144
-
145
- class << self
146
- def json_create(data)
147
- return if data['proxyType'] == 'UNSPECIFIED'
148
-
149
- proxy = new
150
-
151
- proxy.type = data['proxyType'].downcase.to_sym if data.has_key? 'proxyType'
152
- proxy.ftp = data['ftpProxy'] if data.has_key? 'ftpProxy'
153
- proxy.http = data['httpProxy'] if data.has_key? 'httpProxy'
154
- proxy.no_proxy = data['noProxy'] if data.has_key? 'noProxy'
155
- proxy.pac = data['proxyAutoconfigUrl'] if data.has_key? 'proxyAutoconfigUrl'
156
- proxy.ssl = data['sslProxy'] if data.has_key? 'sslProxy'
157
- proxy.auto_detect = data['autodetect'] if data.has_key? 'autodetect'
158
- proxy.socks = data['socksProxy'] if data.has_key? 'socksProxy'
159
- proxy.socks_username = data['socksUsername'] if data.has_key? 'socksUsername'
160
- proxy.socks_password = data['socksPassword'] if data.has_key? 'socksPassword'
161
-
162
- proxy
163
- end
164
- end # class << self
165
-
166
154
  end # Proxy
167
155
  end # WebDriver
168
156
  end # Selenium
@@ -20,20 +20,19 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module SearchContext
23
-
24
23
  # @api private
25
24
  FINDERS = {
26
- :class => 'class name',
27
- :class_name => 'class name',
28
- :css => 'css selector',
29
- :id => 'id',
30
- :link => 'link text',
31
- :link_text => 'link text',
32
- :name => 'name',
33
- :partial_link_text => 'partial link text',
34
- :tag_name => 'tag name',
35
- :xpath => 'xpath',
36
- }
25
+ class: 'class name',
26
+ class_name: 'class name',
27
+ css: 'css selector',
28
+ id: 'id',
29
+ link: 'link text',
30
+ link_text: 'link text',
31
+ name: 'name',
32
+ partial_link_text: 'partial link text',
33
+ tag_name: 'tag name',
34
+ xpath: 'xpath'
35
+ }.freeze
37
36
 
38
37
  #
39
38
  # Find the first element matching the given arguments.
@@ -54,9 +53,8 @@ module Selenium
54
53
  def find_element(*args)
55
54
  how, what = extract_args(args)
56
55
 
57
- unless by = FINDERS[how.to_sym]
58
- raise ArgumentError, "cannot find element by #{how.inspect}"
59
- end
56
+ by = FINDERS[how.to_sym]
57
+ raise ArgumentError, "cannot find element by #{how.inspect}" unless by
60
58
 
61
59
  bridge.find_element_by by, what.to_s, ref
62
60
  rescue Selenium::WebDriver::Error::TimeOutError
@@ -77,9 +75,8 @@ module Selenium
77
75
  def find_elements(*args)
78
76
  how, what = extract_args(args)
79
77
 
80
- unless by = FINDERS[how.to_sym]
81
- raise ArgumentError, "cannot find elements by #{how.inspect}"
82
- end
78
+ by = FINDERS[how.to_sym]
79
+ raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
83
80
 
84
81
  bridge.find_elements_by by, what.to_s, ref
85
82
  rescue Selenium::WebDriver::Error::TimeOutError
@@ -111,7 +108,6 @@ module Selenium
111
108
  raise ArgumentError, "wrong number of arguments (#{args.size} for 2)"
112
109
  end
113
110
  end
114
-
115
111
  end # SearchContext
116
112
  end # WebDriver
117
113
  end # Selenium
@@ -0,0 +1,127 @@
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
+ #
23
+ # Base class implementing default behavior of service object,
24
+ # responsible for starting and stopping driver implementations.
25
+ #
26
+ # Subclasses must implement the following private methods:
27
+ # * #start_process
28
+ # * #stop_server
29
+ # * #cannot_connect_error_text
30
+ #
31
+ # @api private
32
+ #
33
+
34
+ class Service
35
+ START_TIMEOUT = 20
36
+ SOCKET_LOCK_TIMEOUT = 45
37
+ STOP_TIMEOUT = 5
38
+
39
+ attr_accessor :host
40
+
41
+ def initialize(executable_path, port, *extra_args)
42
+ @executable_path = executable_path
43
+ @host = Platform.localhost
44
+ @port = Integer(port)
45
+ @extra_args = extra_args
46
+
47
+ raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
48
+ end
49
+
50
+ def start
51
+ if process_running?
52
+ raise "already started: #{uri.inspect} #{@executable_path.inspect}"
53
+ end
54
+
55
+ Platform.exit_hook { stop } # make sure we don't leave the server running
56
+
57
+ socket_lock.locked do
58
+ find_free_port
59
+ start_process
60
+ connect_until_stable
61
+ end
62
+ end
63
+
64
+ def stop
65
+ return if process_exited?
66
+ stop_server
67
+ ensure
68
+ stop_process
69
+ end
70
+
71
+ def uri
72
+ @uri ||= URI.parse("http://#{@host}:#{@port}")
73
+ end
74
+
75
+ private
76
+
77
+ def connect_to_server
78
+ Net::HTTP.start(@host, @port) do |http|
79
+ http.open_timeout = STOP_TIMEOUT / 2
80
+ http.read_timeout = STOP_TIMEOUT / 2
81
+
82
+ yield http
83
+ end
84
+ end
85
+
86
+ def find_free_port
87
+ @port = PortProber.above(@port)
88
+ end
89
+
90
+ def start_process
91
+ raise NotImplementedError, 'subclass responsibility'
92
+ end
93
+
94
+ def stop_server
95
+ raise NotImplementedError, 'subclass responsibility'
96
+ end
97
+
98
+ def stop_process
99
+ @process.poll_for_exit STOP_TIMEOUT
100
+ rescue ChildProcess::TimeoutError
101
+ @process.stop STOP_TIMEOUT
102
+ end
103
+
104
+ def process_running?
105
+ @process && @process.alive?
106
+ end
107
+
108
+ def process_exited?
109
+ @process.nil? || @process.exited?
110
+ end
111
+
112
+ def connect_until_stable
113
+ socket_poller = SocketPoller.new @host, @port, START_TIMEOUT
114
+ return if socket_poller.connected?
115
+ raise Error::WebDriverError, cannot_connect_error_text
116
+ end
117
+
118
+ def cannot_connect_error_text
119
+ raise NotImplementedError, 'subclass responsibility'
120
+ end
121
+
122
+ def socket_lock
123
+ @socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
124
+ end
125
+ end # Service
126
+ end # WebDriver
127
+ end # Selenium
@@ -19,13 +19,11 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
-
23
22
  #
24
23
  # @api private
25
24
  #
26
25
 
27
26
  class SocketLock
28
-
29
27
  def initialize(port, timeout)
30
28
  @port = port
31
29
  @timeout = timeout
@@ -36,7 +34,7 @@ module Selenium
36
34
  # execution block if the lock could be successfully obtained.
37
35
  #
38
36
 
39
- def locked(&blk)
37
+ def locked
40
38
  lock
41
39
 
42
40
  begin
@@ -51,13 +49,10 @@ module Selenium
51
49
  def lock
52
50
  max_time = Time.now + @timeout
53
51
 
54
- until can_lock? || Time.now >= max_time
55
- sleep 0.1
56
- end
52
+ sleep 0.1 until can_lock? || Time.now >= max_time
57
53
 
58
- unless did_lock?
59
- raise Error::WebDriverError, "unable to bind to locking port #{@port} within #{@timeout} seconds"
60
- end
54
+ return if did_lock?
55
+ raise Error::WebDriverError, "unable to bind to locking port #{@port} within #{@timeout} seconds"
61
56
  end
62
57
 
63
58
  def release
@@ -75,9 +70,8 @@ module Selenium
75
70
  end
76
71
 
77
72
  def did_lock?
78
- !!@server
73
+ !@server.nil?
79
74
  end
80
-
81
75
  end # SocketLock
82
76
  end # WebDriver
83
77
  end # Selenium