selenium-webdriver 3.142.7 → 4.0.0.alpha1

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +21 -43
  3. data/lib/selenium/webdriver.rb +2 -4
  4. data/lib/selenium/webdriver/chrome/bridge.rb +3 -21
  5. data/lib/selenium/webdriver/chrome/driver.rb +12 -39
  6. data/lib/selenium/webdriver/chrome/options.rb +3 -7
  7. data/lib/selenium/webdriver/chrome/profile.rb +2 -2
  8. data/lib/selenium/webdriver/chrome/service.rb +4 -9
  9. data/lib/selenium/webdriver/common.rb +7 -16
  10. data/lib/selenium/webdriver/common/action_builder.rb +97 -249
  11. data/lib/selenium/webdriver/common/driver.rb +2 -4
  12. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +1 -1
  13. data/lib/selenium/webdriver/common/element.rb +3 -6
  14. data/lib/selenium/webdriver/common/error.rb +27 -203
  15. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -5
  16. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +13 -13
  17. data/lib/selenium/webdriver/common/manager.rb +1 -1
  18. data/lib/selenium/webdriver/common/options.rb +148 -24
  19. data/lib/selenium/webdriver/common/service.rb +16 -34
  20. data/lib/selenium/webdriver/common/socket_poller.rb +2 -2
  21. data/lib/selenium/webdriver/common/w3c_options.rb +45 -0
  22. data/lib/selenium/webdriver/edge.rb +0 -1
  23. data/lib/selenium/webdriver/edge/driver.rb +14 -10
  24. data/lib/selenium/webdriver/edge/service.rb +6 -7
  25. data/lib/selenium/webdriver/firefox.rb +2 -6
  26. data/lib/selenium/webdriver/firefox/binary.rb +3 -80
  27. data/lib/selenium/webdriver/firefox/bridge.rb +47 -0
  28. data/lib/selenium/webdriver/firefox/driver.rb +44 -22
  29. data/lib/selenium/webdriver/firefox/marionette/driver.rb +1 -1
  30. data/lib/selenium/webdriver/firefox/options.rb +2 -2
  31. data/lib/selenium/webdriver/firefox/profile.rb +25 -14
  32. data/lib/selenium/webdriver/firefox/service.rb +4 -4
  33. data/lib/selenium/webdriver/ie/driver.rb +5 -18
  34. data/lib/selenium/webdriver/ie/options.rb +2 -2
  35. data/lib/selenium/webdriver/ie/service.rb +4 -4
  36. data/lib/selenium/webdriver/remote.rb +2 -6
  37. data/lib/selenium/webdriver/remote/bridge.rb +515 -69
  38. data/lib/selenium/webdriver/remote/capabilities.rb +77 -99
  39. data/lib/selenium/webdriver/remote/commands.rb +156 -0
  40. data/lib/selenium/webdriver/remote/driver.rb +12 -5
  41. data/lib/selenium/webdriver/remote/http/default.rb +0 -9
  42. data/lib/selenium/webdriver/remote/response.rb +16 -47
  43. data/lib/selenium/webdriver/safari.rb +1 -1
  44. data/lib/selenium/webdriver/safari/bridge.rb +3 -3
  45. data/lib/selenium/webdriver/safari/driver.rb +4 -1
  46. data/lib/selenium/webdriver/safari/service.rb +4 -4
  47. data/lib/selenium/webdriver/support/select.rb +1 -1
  48. data/lib/selenium/webdriver/version.rb +1 -1
  49. data/selenium-webdriver.gemspec +3 -3
  50. metadata +14 -5
@@ -20,29 +20,38 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Remote
23
+
23
24
  #
24
25
  # Specification of the desired and/or actual capabilities of the browser that the
25
26
  # server is being asked to create.
26
27
  #
28
+
27
29
  class Capabilities
28
- DEFAULTS = {
29
- browser_name: '',
30
- version: '',
31
- platform: :any,
32
- javascript_enabled: false,
33
- css_selectors_enabled: false,
34
- takes_screenshot: false,
35
- native_events: false,
36
- rotatable: false,
37
- firefox_profile: nil,
38
- proxy: nil
39
- }.freeze
40
-
41
- DEFAULTS.each_key do |key|
42
- if key != :javascript_enabled
43
- define_method key do
44
- @capabilities.fetch(key)
45
- end
30
+
31
+ KNOWN = [
32
+ :browser_name,
33
+ :browser_version,
34
+ :platform_name,
35
+ :accept_insecure_certs,
36
+ :page_load_strategy,
37
+ :proxy,
38
+ :set_window_rect,
39
+ :timeouts,
40
+ :unhandled_prompt_behavior,
41
+ :strict_file_interactability,
42
+
43
+ # remote-specific
44
+ :remote_session_id,
45
+
46
+ # TODO: (AR) deprecate compatibility with OSS-capabilities
47
+ :implicit_timeout,
48
+ :page_load_timeout,
49
+ :script_timeout
50
+ ].freeze
51
+
52
+ KNOWN.each do |key|
53
+ define_method key do
54
+ @capabilities.fetch(key)
46
55
  end
47
56
 
48
57
  next if key == :proxy
@@ -53,19 +62,13 @@ module Selenium
53
62
  end
54
63
 
55
64
  #
56
- # Returns javascript_enabled capability.
57
- # It is true if not set explicitly.
65
+ # Backward compatibility
58
66
  #
59
- def javascript_enabled
60
- javascript_enabled = @capabilities.fetch(:javascript_enabled)
61
- javascript_enabled.nil? ? true : javascript_enabled
62
- end
63
67
 
64
- alias_method :css_selectors_enabled?, :css_selectors_enabled
65
- alias_method :javascript_enabled?, :javascript_enabled
66
- alias_method :native_events?, :native_events
67
- alias_method :takes_screenshot?, :takes_screenshot
68
- alias_method :rotatable?, :rotatable
68
+ alias_method :version, :browser_version
69
+ alias_method :version=, :browser_version=
70
+ alias_method :platform, :platform_name
71
+ alias_method :platform=, :platform_name=
69
72
 
70
73
  #
71
74
  # Convenience methods for the common choices.
@@ -74,16 +77,14 @@ module Selenium
74
77
  class << self
75
78
  def chrome(opts = {})
76
79
  new({
77
- browser_name: 'chrome',
78
- javascript_enabled: true,
79
- css_selectors_enabled: true
80
+ browser_name: 'chrome'
80
81
  }.merge(opts))
81
82
  end
82
83
 
83
84
  def edge(opts = {})
84
85
  new({
85
86
  browser_name: 'MicrosoftEdge',
86
- platform: :windows
87
+ platform_name: :windows
87
88
  }.merge(opts))
88
89
  end
89
90
 
@@ -94,15 +95,15 @@ module Selenium
94
95
  opts[:timeouts]['implicit'] = opts.delete(:implicit_timeout) if opts.key?(:implicit_timeout)
95
96
  opts[:timeouts]['pageLoad'] = opts.delete(:page_load_timeout) if opts.key?(:page_load_timeout)
96
97
  opts[:timeouts]['script'] = opts.delete(:script_timeout) if opts.key?(:script_timeout)
97
- new({browser_name: 'firefox', marionette: true}.merge(opts))
98
+ new({browser_name: 'firefox'}.merge(opts))
98
99
  end
99
100
 
100
- def firefox_legacy(opts = {})
101
+ alias_method :ff, :firefox
102
+
103
+ def safari(opts = {})
101
104
  new({
102
- browser_name: 'firefox',
103
- javascript_enabled: true,
104
- takes_screenshot: true,
105
- css_selectors_enabled: true
105
+ browser_name: 'safari',
106
+ platform_name: :mac
106
107
  }.merge(opts))
107
108
  end
108
109
 
@@ -112,44 +113,14 @@ module Selenium
112
113
  }.merge(opts))
113
114
  end
114
115
 
115
- def htmlunitwithjs(opts = {})
116
- new({
117
- browser_name: 'htmlunit',
118
- javascript_enabled: true
119
- }.merge(opts))
120
- end
121
-
122
116
  def internet_explorer(opts = {})
123
117
  new({
124
118
  browser_name: 'internet explorer',
125
- platform: :windows,
126
- takes_screenshot: true,
127
- css_selectors_enabled: true,
128
- native_events: true
119
+ platform_name: :windows
129
120
  }.merge(opts))
130
121
  end
131
122
  alias_method :ie, :internet_explorer
132
123
 
133
- def phantomjs(opts = {})
134
- WebDriver.logger.deprecate 'Selenium support for PhantomJS', 'headless Chrome/Firefox or HTMLUnit'
135
- new({
136
- browser_name: 'phantomjs',
137
- javascript_enabled: true,
138
- takes_screenshot: true,
139
- css_selectors_enabled: true
140
- }.merge(opts))
141
- end
142
-
143
- def safari(opts = {})
144
- new({
145
- browser_name: 'safari',
146
- platform: :mac,
147
- javascript_enabled: true,
148
- takes_screenshot: true,
149
- css_selectors_enabled: true
150
- }.merge(opts))
151
- end
152
-
153
124
  #
154
125
  # @api private
155
126
  #
@@ -158,15 +129,26 @@ module Selenium
158
129
  data = data.dup
159
130
 
160
131
  caps = new
161
- caps.browser_name = data.delete('browserName')
162
- caps.version = data.delete('version')
163
- caps.platform = data.delete('platform').downcase.tr(' ', '_').to_sym if data.key?('platform')
164
- caps.javascript_enabled = data.delete('javascriptEnabled')
165
- caps.css_selectors_enabled = data.delete('cssSelectorsEnabled')
166
- caps.takes_screenshot = data.delete('takesScreenshot')
167
- caps.native_events = data.delete('nativeEvents')
168
- caps.rotatable = data.delete('rotatable')
169
- caps.proxy = Proxy.json_create(data['proxy']) if data.key?('proxy') && !data['proxy'].empty?
132
+ caps.browser_name = data.delete('browserName') if data.key?('browserName')
133
+ caps.browser_version = data.delete('browserVersion') if data.key?('browserVersion')
134
+ caps.platform_name = data.delete('platformName') if data.key?('platformName')
135
+ caps.accept_insecure_certs = data.delete('acceptInsecureCerts') if data.key?('acceptInsecureCerts')
136
+ caps.page_load_strategy = data.delete('pageLoadStrategy') if data.key?('pageLoadStrategy')
137
+
138
+ if data.key?('timeouts')
139
+ timeouts = data.delete('timeouts')
140
+ caps.implicit_timeout = timeouts['implicit'] if timeouts
141
+ caps.page_load_timeout = timeouts['pageLoad'] if timeouts
142
+ caps.script_timeout = timeouts['script'] if timeouts
143
+ end
144
+
145
+ if data.key?('proxy')
146
+ proxy = data.delete('proxy')
147
+ caps.proxy = Proxy.json_create(proxy) unless proxy.nil? || proxy.empty?
148
+ end
149
+
150
+ # Remote Server Specific
151
+ caps[:remote_session_id] = data.delete('webdriver.remote.sessionid') if data.key?('webdriver.remote.sessionid')
170
152
 
171
153
  # any remaining pairs will be added as is, with no conversion
172
154
  caps.merge!(data)
@@ -176,21 +158,19 @@ module Selenium
176
158
  end
177
159
 
178
160
  #
179
- # @option :browser_name [String] required browser name
180
- # @option :version [String] required browser version number
181
- # @option :platform [Symbol] one of :any, :win, :mac, or :x
182
- # @option :javascript_enabled [Boolean] does the driver have javascript enabled?
183
- # @option :css_selectors_enabled [Boolean] does the driver support CSS selectors?
184
- # @option :takes_screenshot [Boolean] can this driver take screenshots?
185
- # @option :native_events [Boolean] does this driver use native events?
186
- # @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration
161
+ # @param [Hash] opts
162
+ # @option :browser_name [String] required browser name
163
+ # @option :browser_version [String] required browser version number
164
+ # @option :platform_name [Symbol] one of :any, :win, :mac, or :x
165
+ # @option :accept_insecure_certs [Boolean] does the driver accept insecure SSL certifications?
166
+ # @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration
187
167
  #
188
168
  # @api public
189
169
  #
190
170
 
191
171
  def initialize(opts = {})
192
- @capabilities = DEFAULTS.merge(opts)
193
- self.proxy = opts.delete(:proxy)
172
+ @capabilities = opts
173
+ self.proxy = opts.delete(:proxy)
194
174
  end
195
175
 
196
176
  #
@@ -230,24 +210,20 @@ module Selenium
230
210
  # @api private
231
211
  #
232
212
 
233
- def as_json(*) # rubocop:disable Metrics/CyclomaticComplexity
213
+ def as_json(*)
234
214
  hash = {}
235
215
 
236
216
  @capabilities.each do |key, value|
237
217
  case key
238
218
  when :platform
239
219
  hash['platform'] = value.to_s.upcase
240
- when :firefox_profile
241
- if value
242
- WebDriver.logger.deprecate(':firefox_profile capabilitiy', 'Selenium::WebDriver::Firefox::Options#profile')
243
- hash['firefox_profile'] = value.as_json['zip']
244
- end
245
220
  when :proxy
246
- hash['proxy'] = value.as_json if value
247
- when String, :firefox_binary
248
- if key == :firefox_binary && value
249
- WebDriver.logger.deprecate(':firefox_binary capabilitiy', 'Selenium::WebDriver::Firefox::Options#binary')
221
+ if value
222
+ hash['proxy'] = value.as_json
223
+ hash['proxy']['proxyType'] &&= hash['proxy']['proxyType'].downcase
224
+ hash['proxy']['noProxy'] = hash['proxy']['noProxy'].split(', ') if hash['proxy']['noProxy'].is_a?(String)
250
225
  end
226
+ when String
251
227
  hash[key.to_s] = value
252
228
  when Symbol
253
229
  hash[camel_case(key.to_s)] = value
@@ -268,6 +244,7 @@ module Selenium
268
244
 
269
245
  as_json == other.as_json
270
246
  end
247
+
271
248
  alias_method :eql?, :==
272
249
 
273
250
  protected
@@ -279,6 +256,7 @@ module Selenium
279
256
  def camel_case(str)
280
257
  str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
281
258
  end
259
+
282
260
  end # Capabilities
283
261
  end # Remote
284
262
  end # WebDriver
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
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 Remote
23
+
24
+ #
25
+ # https://w3c.github.io/webdriver/#endpoints
26
+ # @api private
27
+ #
28
+
29
+ class Bridge
30
+ COMMANDS = {
31
+ status: [:get, 'status'],
32
+
33
+ #
34
+ # session handling
35
+ #
36
+
37
+ new_session: [:post, 'session'],
38
+ delete_session: [:delete, 'session/:session_id'],
39
+
40
+ #
41
+ # basic driver
42
+ #
43
+
44
+ get: [:post, 'session/:session_id/url'],
45
+ get_current_url: [:get, 'session/:session_id/url'],
46
+ back: [:post, 'session/:session_id/back'],
47
+ forward: [:post, 'session/:session_id/forward'],
48
+ refresh: [:post, 'session/:session_id/refresh'],
49
+ get_title: [:get, 'session/:session_id/title'],
50
+
51
+ #
52
+ # window and Frame handling
53
+ #
54
+
55
+ get_window_handle: [:get, 'session/:session_id/window'],
56
+ new_window: [:post, 'session/:session_id/window/new'],
57
+ close_window: [:delete, 'session/:session_id/window'],
58
+ switch_to_window: [:post, 'session/:session_id/window'],
59
+ get_window_handles: [:get, 'session/:session_id/window/handles'],
60
+ fullscreen_window: [:post, 'session/:session_id/window/fullscreen'],
61
+ minimize_window: [:post, 'session/:session_id/window/minimize'],
62
+ maximize_window: [:post, 'session/:session_id/window/maximize'],
63
+ set_window_size: [:post, 'session/:session_id/window/size'],
64
+ get_window_size: [:get, 'session/:session_id/window/size'],
65
+ set_window_position: [:post, 'session/:session_id/window/position'],
66
+ get_window_position: [:get, 'session/:session_id/window/position'],
67
+ set_window_rect: [:post, 'session/:session_id/window/rect'],
68
+ get_window_rect: [:get, 'session/:session_id/window/rect'],
69
+ switch_to_frame: [:post, 'session/:session_id/frame'],
70
+ switch_to_parent_frame: [:post, 'session/:session_id/frame/parent'],
71
+
72
+ #
73
+ # element
74
+ #
75
+
76
+ find_element: [:post, 'session/:session_id/element'],
77
+ find_elements: [:post, 'session/:session_id/elements'],
78
+ find_child_element: [:post, 'session/:session_id/element/:id/element'],
79
+ find_child_elements: [:post, 'session/:session_id/element/:id/elements'],
80
+ get_active_element: [:get, 'session/:session_id/element/active'],
81
+ is_element_selected: [:get, 'session/:session_id/element/:id/selected'],
82
+ get_element_attribute: [:get, 'session/:session_id/element/:id/attribute/:name'],
83
+ get_element_property: [:get, 'session/:session_id/element/:id/property/:name'],
84
+ get_element_css_value: [:get, 'session/:session_id/element/:id/css/:property_name'],
85
+ get_element_text: [:get, 'session/:session_id/element/:id/text'],
86
+ get_element_tag_name: [:get, 'session/:session_id/element/:id/name'],
87
+ get_element_rect: [:get, 'session/:session_id/element/:id/rect'],
88
+ is_element_enabled: [:get, 'session/:session_id/element/:id/enabled'],
89
+
90
+ #
91
+ # document handling
92
+ #
93
+
94
+ get_page_source: [:get, 'session/:session_id/source'],
95
+ execute_script: [:post, 'session/:session_id/execute/sync'],
96
+ execute_async_script: [:post, 'session/:session_id/execute/async'],
97
+
98
+ #
99
+ # cookies
100
+ #
101
+
102
+ get_all_cookies: [:get, 'session/:session_id/cookie'],
103
+ get_cookie: [:get, 'session/:session_id/cookie/:name'],
104
+ add_cookie: [:post, 'session/:session_id/cookie'],
105
+ delete_cookie: [:delete, 'session/:session_id/cookie/:name'],
106
+ delete_all_cookies: [:delete, 'session/:session_id/cookie'],
107
+
108
+ #
109
+ # timeouts
110
+ #
111
+
112
+ set_timeout: [:post, 'session/:session_id/timeouts'],
113
+
114
+ #
115
+ # actions
116
+ #
117
+
118
+ actions: [:post, 'session/:session_id/actions'],
119
+ release_actions: [:delete, 'session/:session_id/actions'],
120
+
121
+ #
122
+ # Element Operations
123
+ #
124
+
125
+ element_click: [:post, 'session/:session_id/element/:id/click'],
126
+ element_tap: [:post, 'session/:session_id/element/:id/tap'],
127
+ element_clear: [:post, 'session/:session_id/element/:id/clear'],
128
+ element_send_keys: [:post, 'session/:session_id/element/:id/value'],
129
+
130
+ #
131
+ # alerts
132
+ #
133
+
134
+ dismiss_alert: [:post, 'session/:session_id/alert/dismiss'],
135
+ accept_alert: [:post, 'session/:session_id/alert/accept'],
136
+ get_alert_text: [:get, 'session/:session_id/alert/text'],
137
+ send_alert_text: [:post, 'session/:session_id/alert/text'],
138
+
139
+ #
140
+ # screenshot
141
+ #
142
+
143
+ take_screenshot: [:get, 'session/:session_id/screenshot'],
144
+ take_element_screenshot: [:get, 'session/:session_id/element/:id/screenshot'],
145
+
146
+ #
147
+ # server extensions
148
+ #
149
+
150
+ upload_file: [:post, 'session/:session_id/se/file']
151
+ }.freeze
152
+
153
+ end # Bridge
154
+ end # Remote
155
+ end # WebDriver
156
+ end # Selenium
@@ -36,12 +36,19 @@ module Selenium
36
36
 
37
37
  def initialize(opts = {})
38
38
  listener = opts.delete(:listener)
39
- @bridge = Bridge.handshake(opts)
40
- if @bridge.dialect == :oss
41
- extend DriverExtensions::HasTouchScreen
42
- extend DriverExtensions::HasLocation
43
- extend DriverExtensions::HasNetworkConnection
39
+ desired_capabilities = opts.delete(:desired_capabilities) { Capabilities.new }
40
+
41
+ if desired_capabilities.is_a?(Symbol)
42
+ unless Capabilities.respond_to?(desired_capabilities)
43
+ raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
44
+ end
45
+
46
+ desired_capabilities = Capabilities.__send__(desired_capabilities)
44
47
  end
48
+
49
+ @bridge = Bridge.new(opts)
50
+ @bridge.create_session(desired_capabilities, opts.delete(:options))
51
+
45
52
  super(@bridge, listener: listener)
46
53
  end
47
54