selenium-webdriver 3.142.7 → 4.3.0

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 (157) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +432 -5
  3. data/Gemfile +3 -1
  4. data/LICENSE +1 -1
  5. data/NOTICE +2 -0
  6. data/README.md +4 -5
  7. data/lib/selenium/server.rb +75 -64
  8. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  9. data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
  10. data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
  11. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  12. data/lib/selenium/webdriver/bidi/session.rb +38 -0
  13. data/lib/selenium/webdriver/bidi.rb +55 -0
  14. data/lib/selenium/webdriver/chrome/driver.rb +26 -83
  15. data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +55 -12
  16. data/lib/selenium/webdriver/chrome/options.rb +138 -67
  17. data/lib/selenium/webdriver/chrome/profile.rb +6 -3
  18. data/lib/selenium/webdriver/chrome/service.rb +8 -15
  19. data/lib/selenium/webdriver/chrome.rb +5 -18
  20. data/lib/selenium/webdriver/common/action_builder.rb +171 -236
  21. data/lib/selenium/webdriver/common/driver.rb +76 -29
  22. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  23. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
  24. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  25. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_bidi.rb} +10 -8
  26. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +87 -0
  27. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +38 -0
  28. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +44 -0
  29. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +43 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +38 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  32. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +144 -0
  33. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_logs.rb} +4 -4
  34. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +17 -0
  35. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  36. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +136 -0
  37. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
  38. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
  39. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  40. data/lib/selenium/webdriver/common/element.rb +83 -23
  41. data/lib/selenium/webdriver/common/error.rb +32 -196
  42. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  43. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -22
  44. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  45. data/lib/selenium/webdriver/common/interactions/key_actions.rb +10 -6
  46. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  47. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  48. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  49. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +68 -78
  50. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  51. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  52. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  53. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  54. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  55. data/lib/selenium/webdriver/common/interactions/scroll.rb +57 -0
  56. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  57. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  58. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  59. data/lib/selenium/webdriver/common/{w3c_manager.rb → interactions/wheel_input.rb} +14 -17
  60. data/lib/selenium/webdriver/common/keys.rb +1 -0
  61. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  62. data/lib/selenium/webdriver/common/logger.rb +50 -15
  63. data/lib/selenium/webdriver/common/manager.rb +11 -38
  64. data/lib/selenium/webdriver/common/options.rb +147 -23
  65. data/lib/selenium/webdriver/common/platform.rb +10 -5
  66. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  67. data/lib/selenium/webdriver/common/profile_helper.rb +11 -9
  68. data/lib/selenium/webdriver/common/proxy.rb +6 -3
  69. data/lib/selenium/webdriver/common/search_context.rb +7 -9
  70. data/lib/selenium/webdriver/common/service.rb +17 -125
  71. data/lib/selenium/webdriver/common/service_manager.rb +150 -0
  72. data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
  73. data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
  74. data/lib/selenium/webdriver/common/socket_poller.rb +3 -3
  75. data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
  76. data/lib/selenium/webdriver/common/target_locator.rb +32 -4
  77. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  78. data/lib/selenium/webdriver/common/wait.rb +1 -1
  79. data/lib/selenium/webdriver/common/websocket_connection.rb +149 -0
  80. data/lib/selenium/webdriver/common/window.rb +0 -4
  81. data/lib/selenium/webdriver/common/zipper.rb +3 -9
  82. data/lib/selenium/webdriver/common.rb +35 -18
  83. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  84. data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
  85. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  86. data/lib/selenium/webdriver/devtools/pinned_script.rb +59 -0
  87. data/lib/selenium/webdriver/devtools/request.rb +67 -0
  88. data/lib/selenium/webdriver/devtools/response.rb +66 -0
  89. data/lib/selenium/webdriver/devtools.rb +86 -0
  90. data/lib/selenium/webdriver/edge/driver.rb +7 -29
  91. data/lib/selenium/webdriver/edge/features.rb +45 -0
  92. data/lib/selenium/webdriver/edge/options.rb +11 -48
  93. data/lib/selenium/webdriver/edge/profile.rb +33 -0
  94. data/lib/selenium/webdriver/edge/service.rb +10 -26
  95. data/lib/selenium/webdriver/edge.rb +11 -14
  96. data/lib/selenium/webdriver/firefox/driver.rb +32 -19
  97. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  98. data/lib/selenium/webdriver/firefox/features.rb +63 -0
  99. data/lib/selenium/webdriver/firefox/options.rb +73 -50
  100. data/lib/selenium/webdriver/firefox/profile.rb +16 -70
  101. data/lib/selenium/webdriver/firefox/service.rb +5 -9
  102. data/lib/selenium/webdriver/firefox/util.rb +1 -1
  103. data/lib/selenium/webdriver/firefox.rb +17 -28
  104. data/lib/selenium/webdriver/ie/driver.rb +1 -47
  105. data/lib/selenium/webdriver/ie/options.rb +15 -46
  106. data/lib/selenium/webdriver/ie/service.rb +13 -15
  107. data/lib/selenium/webdriver/ie.rb +3 -16
  108. data/lib/selenium/webdriver/remote/bridge.rb +563 -86
  109. data/lib/selenium/webdriver/remote/capabilities.rb +159 -123
  110. data/lib/selenium/webdriver/remote/commands.rb +158 -0
  111. data/lib/selenium/webdriver/remote/driver.rb +22 -13
  112. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  113. data/lib/selenium/webdriver/remote/http/default.rb +22 -31
  114. data/lib/selenium/webdriver/remote/response.rb +18 -49
  115. data/lib/selenium/webdriver/remote.rb +15 -12
  116. data/lib/selenium/webdriver/safari/driver.rb +3 -31
  117. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
  118. data/lib/selenium/webdriver/safari/options.rb +10 -29
  119. data/lib/selenium/webdriver/safari/service.rb +4 -8
  120. data/lib/selenium/webdriver/safari.rb +13 -19
  121. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  122. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  123. data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
  124. data/lib/selenium/webdriver/support/color.rb +9 -9
  125. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  126. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  127. data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +22 -19
  128. data/lib/selenium/webdriver/support/guards.rb +95 -0
  129. data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
  130. data/lib/selenium/webdriver/support/select.rb +3 -3
  131. data/lib/selenium/webdriver/support.rb +1 -0
  132. data/lib/selenium/webdriver/version.rb +1 -1
  133. data/lib/selenium/webdriver.rb +14 -13
  134. data/selenium-webdriver.gemspec +32 -13
  135. metadata +176 -69
  136. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  137. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  138. data/lib/selenium/webdriver/common/keyboard.rb +0 -70
  139. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  140. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  141. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  142. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  143. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  144. data/lib/selenium/webdriver/firefox/binary.rb +0 -187
  145. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  146. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  147. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  148. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  149. data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
  150. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  151. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  152. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -60
  153. data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
  154. data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
  155. data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
  156. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
  157. data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
@@ -20,32 +20,35 @@
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
46
- end
47
30
 
48
- next if key == :proxy
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
+ :web_socket_url,
43
+
44
+ # remote-specific (webdriver.remote.sessionid)
45
+ :remote_session_id
46
+ ].freeze
47
+
48
+ (KNOWN - %i[proxy timeouts]).each do |key|
49
+ define_method key do
50
+ @capabilities[key]
51
+ end
49
52
 
50
53
  define_method "#{key}=" do |value|
51
54
  @capabilities[key] = value
@@ -53,19 +56,13 @@ module Selenium
53
56
  end
54
57
 
55
58
  #
56
- # Returns javascript_enabled capability.
57
- # It is true if not set explicitly.
59
+ # Backward compatibility
58
60
  #
59
- def javascript_enabled
60
- javascript_enabled = @capabilities.fetch(:javascript_enabled)
61
- javascript_enabled.nil? ? true : javascript_enabled
62
- end
63
61
 
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
62
+ alias_method :version, :browser_version
63
+ alias_method :version=, :browser_version=
64
+ alias_method :platform, :platform_name
65
+ alias_method :platform=, :platform_name=
69
66
 
70
67
  #
71
68
  # Convenience methods for the common choices.
@@ -74,80 +71,50 @@ module Selenium
74
71
  class << self
75
72
  def chrome(opts = {})
76
73
  new({
77
- browser_name: 'chrome',
78
- javascript_enabled: true,
79
- css_selectors_enabled: true
74
+ browser_name: 'chrome'
80
75
  }.merge(opts))
81
76
  end
82
77
 
83
78
  def edge(opts = {})
84
79
  new({
85
- browser_name: 'MicrosoftEdge',
86
- platform: :windows
80
+ browser_name: 'MicrosoftEdge'
87
81
  }.merge(opts))
88
82
  end
83
+ alias_method :microsoftedge, :edge
89
84
 
90
85
  def firefox(opts = {})
91
- opts[:browser_version] = opts.delete(:version) if opts.key?(:version)
92
- opts[:platform_name] = opts.delete(:platform) if opts.key?(:platform)
93
- opts[:timeouts] = {}
94
- opts[:timeouts]['implicit'] = opts.delete(:implicit_timeout) if opts.key?(:implicit_timeout)
95
- opts[:timeouts]['pageLoad'] = opts.delete(:page_load_timeout) if opts.key?(:page_load_timeout)
96
- opts[:timeouts]['script'] = opts.delete(:script_timeout) if opts.key?(:script_timeout)
97
- new({browser_name: 'firefox', marionette: true}.merge(opts))
98
- end
99
-
100
- def firefox_legacy(opts = {})
101
86
  new({
102
- browser_name: 'firefox',
103
- javascript_enabled: true,
104
- takes_screenshot: true,
105
- css_selectors_enabled: true
87
+ browser_name: 'firefox'
106
88
  }.merge(opts))
107
89
  end
90
+ alias_method :ff, :firefox
108
91
 
109
- def htmlunit(opts = {})
92
+ def safari(opts = {})
110
93
  new({
111
- browser_name: 'htmlunit'
94
+ browser_name: Selenium::WebDriver::Safari.technology_preview? ? "Safari Technology Preview" : 'safari'
112
95
  }.merge(opts))
113
96
  end
114
97
 
115
- def htmlunitwithjs(opts = {})
98
+ def htmlunit(opts = {})
116
99
  new({
117
- browser_name: 'htmlunit',
118
- javascript_enabled: true
100
+ browser_name: 'htmlunit'
119
101
  }.merge(opts))
120
102
  end
121
103
 
122
104
  def internet_explorer(opts = {})
123
105
  new({
124
106
  browser_name: 'internet explorer',
125
- platform: :windows,
126
- takes_screenshot: true,
127
- css_selectors_enabled: true,
128
- native_events: true
107
+ platform_name: :windows
129
108
  }.merge(opts))
130
109
  end
131
110
  alias_method :ie, :internet_explorer
132
111
 
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))
112
+ def always_match(capabilities)
113
+ new(always_match: capabilities)
141
114
  end
142
115
 
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))
116
+ def first_match(*capabilities)
117
+ new(first_match: capabilities)
151
118
  end
152
119
 
153
120
  #
@@ -156,41 +123,61 @@ module Selenium
156
123
 
157
124
  def json_create(data)
158
125
  data = data.dup
159
-
160
126
  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?
127
+
128
+ process_timeouts(caps, data.delete('timeouts'))
129
+
130
+ if data.key?('proxy')
131
+ proxy = data.delete('proxy')
132
+ caps.proxy = Proxy.json_create(proxy) unless proxy.nil? || proxy.empty?
133
+ end
134
+
135
+ # Remote Server Specific
136
+ if data.key?('webdriver.remote.sessionid')
137
+ caps[:remote_session_id] = data.delete('webdriver.remote.sessionid')
138
+ end
139
+
140
+ KNOWN.each do |cap|
141
+ data_value = camel_case(cap)
142
+ caps[cap] = data.delete(data_value) if data.key?(data_value)
143
+ end
170
144
 
171
145
  # any remaining pairs will be added as is, with no conversion
172
146
  caps.merge!(data)
173
147
 
174
148
  caps
175
149
  end
150
+
151
+ def camel_case(str_or_sym)
152
+ str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
153
+ end
154
+
155
+ private
156
+
157
+ def process_timeouts(caps, timeouts)
158
+ return if timeouts.nil?
159
+
160
+ caps.implicit_timeout = timeouts['implicit']
161
+ caps.page_load_timeout = timeouts['pageLoad']
162
+ caps.script_timeout = timeouts['script']
163
+ end
176
164
  end
177
165
 
178
166
  #
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
167
+ # @param [Hash] opts
168
+ # @option :browser_name [String] required browser name
169
+ # @option :browser_version [String] required browser version number
170
+ # @option :platform_name [Symbol] one of :any, :win, :mac, or :x
171
+ # @option :accept_insecure_certs [Boolean] does the driver accept insecure SSL certifications?
172
+ # @option :proxy [Selenium::WebDriver::Proxy, Hash] proxy configuration
187
173
  #
188
174
  # @api public
189
175
  #
190
176
 
191
177
  def initialize(opts = {})
192
- @capabilities = DEFAULTS.merge(opts)
193
- self.proxy = opts.delete(:proxy)
178
+ @capabilities = {}
179
+ self.proxy = opts.delete(:proxy) if opts[:proxy]
180
+ @capabilities.merge!(opts)
194
181
  end
195
182
 
196
183
  #
@@ -215,6 +202,10 @@ module Selenium
215
202
  end
216
203
  end
217
204
 
205
+ def proxy
206
+ @capabilities[:proxy]
207
+ end
208
+
218
209
  def proxy=(proxy)
219
210
  case proxy
220
211
  when Hash
@@ -226,37 +217,46 @@ module Selenium
226
217
  end
227
218
  end
228
219
 
220
+ def timeouts
221
+ @capabilities[:timeouts] ||= {}
222
+ end
223
+
224
+ def timeouts=(timeouts)
225
+ @capabilities[:timeouts] = timeouts
226
+ end
227
+
228
+ def implicit_timeout
229
+ timeouts[:implicit]
230
+ end
231
+
232
+ def implicit_timeout=(timeout)
233
+ timeouts[:implicit] = timeout
234
+ end
235
+
236
+ def page_load_timeout
237
+ timeouts[:page_load] || timeouts[:pageLoad]
238
+ end
239
+
240
+ def page_load_timeout=(timeout)
241
+ timeouts[:page_load] = timeout
242
+ end
243
+
244
+ def script_timeout
245
+ timeouts[:script]
246
+ end
247
+
248
+ def script_timeout=(timeout)
249
+ timeouts[:script] = timeout
250
+ end
251
+
229
252
  #
230
253
  # @api private
231
254
  #
232
255
 
233
- def as_json(*) # rubocop:disable Metrics/CyclomaticComplexity
234
- hash = {}
235
-
236
- @capabilities.each do |key, value|
237
- case key
238
- when :platform
239
- 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
- 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')
250
- end
251
- hash[key.to_s] = value
252
- when Symbol
253
- hash[camel_case(key.to_s)] = value
254
- else
255
- raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class} / #{value.inspect}"
256
- end
256
+ def as_json(*)
257
+ @capabilities.each_with_object({}) do |(key, value), hash|
258
+ hash[convert_key(key)] = process_capabilities(key, value, hash)
257
259
  end
258
-
259
- hash
260
260
  end
261
261
 
262
262
  def to_json(*)
@@ -268,6 +268,7 @@ module Selenium
268
268
 
269
269
  as_json == other.as_json
270
270
  end
271
+
271
272
  alias_method :eql?, :==
272
273
 
273
274
  protected
@@ -276,8 +277,43 @@ module Selenium
276
277
 
277
278
  private
278
279
 
279
- def camel_case(str)
280
- str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
280
+ def process_capabilities(key, value, hash)
281
+ case value
282
+ when Array
283
+ value.map { |v| process_capabilities(key, v, hash) }
284
+ when Hash
285
+ value.each_with_object({}) do |(k, v), h|
286
+ h[convert_key(k)] = process_capabilities(k, v, h)
287
+ end
288
+ when Capabilities, Options
289
+ value.as_json
290
+ else
291
+ convert_value(key, value)
292
+ end
293
+ end
294
+
295
+ def convert_key(key)
296
+ case key
297
+ when String
298
+ key.to_s
299
+ when Symbol
300
+ self.class.camel_case(key)
301
+ else
302
+ raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
303
+ end
304
+ end
305
+
306
+ def convert_value(key, value)
307
+ case key
308
+ when :platform
309
+ value.to_s.upcase
310
+ when :proxy
311
+ value&.as_json
312
+ when :unhandled_prompt_behavior
313
+ value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
314
+ else
315
+ value
316
+ end
281
317
  end
282
318
  end # Capabilities
283
319
  end # Remote
@@ -0,0 +1,158 @@
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_rect: [:post, 'session/:session_id/window/rect'],
64
+ get_window_rect: [:get, 'session/:session_id/window/rect'],
65
+ switch_to_frame: [:post, 'session/:session_id/frame'],
66
+ switch_to_parent_frame: [:post, 'session/:session_id/frame/parent'],
67
+
68
+ #
69
+ # element
70
+ #
71
+
72
+ find_element: [:post, 'session/:session_id/element'],
73
+ find_elements: [:post, 'session/:session_id/elements'],
74
+ find_child_element: [:post, 'session/:session_id/element/:id/element'],
75
+ find_child_elements: [:post, 'session/:session_id/element/:id/elements'],
76
+ find_shadow_child_element: [:post, 'session/:session_id/shadow/:id/element'],
77
+ find_shadow_child_elements: [:post, 'session/:session_id/shadow/:id/elements'],
78
+ get_active_element: [:get, 'session/:session_id/element/active'],
79
+ get_element_shadow_root: [:get, 'session/:session_id/element/:id/shadow'],
80
+ is_element_selected: [:get, 'session/:session_id/element/:id/selected'],
81
+ get_element_attribute: [:get, 'session/:session_id/element/:id/attribute/:name'],
82
+ get_element_property: [:get, 'session/:session_id/element/:id/property/:name'],
83
+ get_element_css_value: [:get, 'session/:session_id/element/:id/css/:property_name'],
84
+ get_element_aria_role: [:get, 'session/:session_id/element/:id/computedrole'],
85
+ get_element_aria_label: [:get, 'session/:session_id/element/:id/computedlabel'],
86
+ get_element_text: [:get, 'session/:session_id/element/:id/text'],
87
+ get_element_tag_name: [:get, 'session/:session_id/element/:id/name'],
88
+ get_element_rect: [:get, 'session/:session_id/element/:id/rect'],
89
+ is_element_enabled: [:get, 'session/:session_id/element/:id/enabled'],
90
+
91
+ #
92
+ # document handling
93
+ #
94
+
95
+ get_page_source: [:get, 'session/:session_id/source'],
96
+ execute_script: [:post, 'session/:session_id/execute/sync'],
97
+ execute_async_script: [:post, 'session/:session_id/execute/async'],
98
+
99
+ #
100
+ # cookies
101
+ #
102
+
103
+ get_all_cookies: [:get, 'session/:session_id/cookie'],
104
+ get_cookie: [:get, 'session/:session_id/cookie/:name'],
105
+ add_cookie: [:post, 'session/:session_id/cookie'],
106
+ delete_cookie: [:delete, 'session/:session_id/cookie/:name'],
107
+ delete_all_cookies: [:delete, 'session/:session_id/cookie'],
108
+
109
+ #
110
+ # timeouts
111
+ #
112
+
113
+ get_timeouts: [:get, 'session/:session_id/timeouts'],
114
+ set_timeout: [:post, 'session/:session_id/timeouts'],
115
+
116
+ #
117
+ # actions
118
+ #
119
+
120
+ actions: [:post, 'session/:session_id/actions'],
121
+ release_actions: [:delete, 'session/:session_id/actions'],
122
+ print_page: [:post, 'session/:session_id/print'],
123
+
124
+ #
125
+ # Element Operations
126
+ #
127
+
128
+ element_click: [:post, 'session/:session_id/element/:id/click'],
129
+ element_clear: [:post, 'session/:session_id/element/:id/clear'],
130
+ element_send_keys: [:post, 'session/:session_id/element/:id/value'],
131
+
132
+ #
133
+ # alerts
134
+ #
135
+
136
+ dismiss_alert: [:post, 'session/:session_id/alert/dismiss'],
137
+ accept_alert: [:post, 'session/:session_id/alert/accept'],
138
+ get_alert_text: [:get, 'session/:session_id/alert/text'],
139
+ send_alert_text: [:post, 'session/:session_id/alert/text'],
140
+
141
+ #
142
+ # screenshot
143
+ #
144
+
145
+ take_screenshot: [:get, 'session/:session_id/screenshot'],
146
+ take_element_screenshot: [:get, 'session/:session_id/element/:id/screenshot'],
147
+
148
+ #
149
+ # server extensions
150
+ #
151
+
152
+ upload_file: [:post, 'session/:session_id/se/file']
153
+ }.freeze
154
+
155
+ end # Bridge
156
+ end # Remote
157
+ end # WebDriver
158
+ end # Selenium
@@ -28,23 +28,32 @@ module Selenium
28
28
 
29
29
  class Driver < WebDriver::Driver
30
30
  include DriverExtensions::UploadsFiles
31
- include DriverExtensions::TakesScreenshot
32
31
  include DriverExtensions::HasSessionId
33
- include DriverExtensions::Rotatable
34
- include DriverExtensions::HasRemoteStatus
35
- include DriverExtensions::HasWebStorage
36
-
37
- def initialize(opts = {})
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
32
+
33
+ def initialize(bridge: nil, listener: nil, **opts)
34
+ desired_capabilities = opts[:desired_capabilities]
35
+ if desired_capabilities.is_a?(Symbol)
36
+ unless Remote::Capabilities.respond_to?(desired_capabilities)
37
+ raise Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
38
+ end
39
+
40
+ opts[:desired_capabilities] = Remote::Capabilities.__send__(desired_capabilities)
44
41
  end
45
- super(@bridge, listener: listener)
42
+ opts[:url] ||= "http://#{Platform.localhost}:4444/wd/hub"
43
+ super
44
+ @bridge.file_detector = ->((filename, *)) { File.exist?(filename) && filename.to_s }
45
+ end
46
+
47
+ private
48
+
49
+ def devtools_url
50
+ capabilities['se:cdp']
46
51
  end
47
52
 
53
+ def devtools_version
54
+ capabilities['se:cdpVersion']&.split('.')&.first ||
55
+ raise(Error::WebDriverError, "DevTools is not supported by the Remote Server")
56
+ end
48
57
  end # Driver
49
58
  end # Remote
50
59
  end # WebDriver
@@ -30,13 +30,8 @@ module Selenium
30
30
  'User-Agent' => "selenium/#{WebDriver::VERSION} (ruby #{Platform.os})"
31
31
  }.freeze
32
32
 
33
- attr_accessor :timeout
34
33
  attr_writer :server_url
35
34
 
36
- def initialize
37
- @timeout = nil
38
- end
39
-
40
35
  def quit_errors
41
36
  [IOError]
42
37
  end