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
@@ -17,6 +17,8 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ require 'selenium/webdriver/chrome/driver'
21
+
20
22
  module Selenium
21
23
  module WebDriver
22
24
  module Edge
@@ -26,40 +28,16 @@ module Selenium
26
28
  # @api private
27
29
  #
28
30
 
29
- class Driver < WebDriver::Driver
30
- include DriverExtensions::TakesScreenshot
31
-
32
- def initialize(opts = {})
33
- opts[:desired_capabilities] ||= Remote::Capabilities.edge
34
-
35
- opts[:url] ||= service_url(opts)
36
-
37
- listener = opts.delete(:listener)
38
-
39
- # Edge is mostly using W3C dialect, but a request to
40
- # create session responds with OSS-like body,
41
- # so we need to force W3C implementation.
42
- desired_capabilities = opts.delete(:desired_capabilities)
43
- bridge = Remote::Bridge.new(opts)
44
- capabilities = bridge.create_session(desired_capabilities)
45
-
46
- WebDriver.logger.info 'Forcing W3C dialect.'
47
- @bridge = Remote::W3C::Bridge.new(capabilities, bridge.session_id, **opts)
48
- @bridge.extend Edge::Bridge
49
-
50
- super(@bridge, listener: listener)
51
- end
52
-
31
+ class Driver < Selenium::WebDriver::Chrome::Driver
53
32
  def browser
54
33
  :edge
55
34
  end
56
35
 
57
- def quit
58
- super
59
- ensure
60
- @service&.stop
61
- end
36
+ private
62
37
 
38
+ def devtools_address
39
+ "http://#{capabilities['ms:edgeOptions']['debuggerAddress']}"
40
+ end
63
41
  end # Driver
64
42
  end # Edge
65
43
  end # WebDriver
@@ -0,0 +1,45 @@
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
+ require 'selenium/webdriver/chrome/features'
21
+
22
+ module Selenium
23
+ module WebDriver
24
+ module Edge
25
+ module Features
26
+
27
+ include WebDriver::Chrome::Features
28
+
29
+ EDGE_COMMANDS = {
30
+ get_cast_sinks: [:get, 'session/:session_id/ms/cast/get_sinks'],
31
+ set_cast_sink_to_use: [:post, 'session/:session_id/ms/cast/set_sink_to_use'],
32
+ start_cast_tab_mirroring: [:post, 'session/:session_id/ms/cast/start_tab_mirroring'],
33
+ start_cast_desktop_mirroring: [:post, 'session/:session_id/ms/cast/start_desktop_mirroring'],
34
+ get_cast_issue_message: [:get, 'session/:session_id/ms/cast/get_issue_message'],
35
+ stop_casting: [:post, 'session/:session_id/ms/cast/stop_casting'],
36
+ send_command: [:post, 'session/:session_id/ms/cdp/execute']
37
+ }.freeze
38
+
39
+ def commands(command)
40
+ EDGE_COMMANDS[command] || Chrome::Features::CHROME_COMMANDS[command] || self.class::COMMANDS[command]
41
+ end
42
+ end # Bridge
43
+ end # Edge
44
+ end # WebDriver
45
+ end # Selenium
@@ -17,62 +17,25 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ require 'selenium/webdriver/chrome/options'
21
+
20
22
  module Selenium
21
23
  module WebDriver
22
24
  module Edge
23
- class Options
24
- attr_accessor :in_private, :start_page
25
- attr_reader :extension_paths
25
+ class Options < Selenium::WebDriver::Chrome::Options
26
+ KEY = 'ms:edgeOptions'
27
+ BROWSER = 'MicrosoftEdge'
26
28
 
27
- #
28
- # Create a new Options instance for Edge.
29
- #
30
- # @example
31
- # options = Selenium::WebDriver::Edge::Options.new(in_private: true)
32
- # driver = Selenium::WebDriver.for :edge, options: options
33
- #
34
- # @param [Hash] opts the pre-defined options to create the Edge::Options with
35
- # @option opts [Boolean] :in_private Start in private mode. Default is false
36
- # @option opts [Array<String>] :extension_paths A list of full paths to extensions to install on startup
37
- # @option opts [String] :start_page Default page to start with
38
- #
39
- # @see https://docs.microsoft.com/en-us/microsoft-edge/webdriver
40
- #
29
+ protected
41
30
 
42
- def initialize(**opts)
43
- @in_private = opts.delete(:in_private) || false
44
- @extension_paths = opts.delete(:extension_paths) || []
45
- @start_page = opts.delete(:start_page)
31
+ def enable_logging(browser_options)
32
+ browser_options['ms:loggingPrefs'] = @logging_prefs
46
33
  end
47
34
 
48
- #
49
- # Add an extension by local path.
50
- #
51
- # @example
52
- # options = Selenium::WebDriver::Edge::Options.new
53
- # options.add_extension_path('C:\path\to\extension')
54
- #
55
- # @param [String] path The local path to the extension folder
56
- #
57
-
58
- def add_extension_path(path)
59
- raise Error::WebDriverError, "could not find extension at #{path.inspect}" unless File.directory?(path)
60
-
61
- @extension_paths << path
62
- end
63
-
64
- #
65
- # @api private
66
- #
67
-
68
- def as_json(*)
69
- opts = {}
70
-
71
- opts['ms:inPrivate'] = true if @in_private
72
- opts['ms:extensionPaths'] = @extension_paths if @extension_paths.any?
73
- opts['ms:startPage'] = @start_page if @start_page
35
+ private
74
36
 
75
- opts
37
+ def binary_path
38
+ Edge.path
76
39
  end
77
40
  end # Options
78
41
  end # Edge
@@ -0,0 +1,33 @@
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
+ require 'selenium/webdriver/chrome/profile'
21
+
22
+ module Selenium
23
+ module WebDriver
24
+ module Edge
25
+ #
26
+ # @private
27
+ #
28
+
29
+ class Profile < Selenium::WebDriver::Chrome::Profile
30
+ end # Profile
31
+ end # Edge
32
+ end # WebDriver
33
+ end # Selenium
@@ -17,36 +17,20 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ require 'selenium/webdriver/chrome/service'
21
+
20
22
  module Selenium
21
23
  module WebDriver
22
24
  module Edge
23
- #
24
- # @api private
25
- #
26
-
27
- class Service < WebDriver::Service
28
- @default_port = 17556
29
- @executable = 'MicrosoftWebDriver'
30
- @missing_text = <<~ERROR
31
- Unable to find MicrosoftWebDriver. Please download the server from
32
- https://www.microsoft.com/en-us/download/details.aspx?id=48212 and place it somewhere on your PATH.
33
- More info at https://github.com/SeleniumHQ/selenium/wiki/MicrosoftWebDriver.
25
+ class Service < Selenium::WebDriver::Chrome::Service
26
+ DEFAULT_PORT = 9515
27
+ EXECUTABLE = 'msedgedriver'
28
+ MISSING_TEXT = <<~ERROR
29
+ Unable to find msedgedriver. Please download the server from
30
+ https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ and place it somewhere on your PATH.
34
31
  ERROR
35
- @shutdown_supported = true
36
-
37
- private
38
-
39
- # Note: This processing is deprecated
40
- def extract_service_args(driver_opts)
41
- driver_args = super
42
- driver_opts = driver_opts.dup
43
- driver_args << "--host=#{driver_opts[:host]}" if driver_opts.key? :host
44
- driver_args << "--package=#{driver_opts[:package]}" if driver_opts.key? :package
45
- driver_args << "--silent" if driver_opts[:silent] == true
46
- driver_args << "--verbose" if driver_opts[:verbose] == true
47
- driver_args
48
- end
32
+ SHUTDOWN_SUPPORTED = true
49
33
  end # Service
50
34
  end # Edge
51
35
  end # WebDriver
52
- end # Service
36
+ end # Selenium
@@ -19,26 +19,23 @@
19
19
 
20
20
  require 'net/http'
21
21
 
22
- require 'selenium/webdriver/edge/bridge'
23
- require 'selenium/webdriver/edge/driver'
24
- require 'selenium/webdriver/edge/options'
25
-
26
22
  module Selenium
27
23
  module WebDriver
28
24
  module Edge
29
- def self.driver_path=(path)
30
- WebDriver.logger.deprecate 'Selenium::WebDriver::Edge#driver_path=',
31
- 'Selenium::WebDriver::Edge::Service#driver_path='
32
- Selenium::WebDriver::Edge::Service.driver_path = path
25
+ autoload :Features, 'selenium/webdriver/edge/features'
26
+ autoload :Driver, 'selenium/webdriver/edge/driver'
27
+ autoload :Profile, 'selenium/webdriver/edge/profile'
28
+ autoload :Options, 'selenium/webdriver/edge/options'
29
+ autoload :Service, 'selenium/webdriver/edge/service'
30
+
31
+ def self.path=(path)
32
+ Platform.assert_executable path
33
+ @path = path
33
34
  end
34
35
 
35
- def self.driver_path
36
- WebDriver.logger.deprecate 'Selenium::WebDriver::Edge#driver_path',
37
- 'Selenium::WebDriver::Edge::Service#driver_path'
38
- Selenium::WebDriver::Edge::Service.driver_path
36
+ def self.path
37
+ @path ||= nil
39
38
  end
40
39
  end # Edge
41
40
  end # WebDriver
42
41
  end # Selenium
43
-
44
- require 'selenium/webdriver/edge/service'
@@ -20,30 +20,43 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Firefox
23
- module Driver
24
- class << self
25
-
26
- #
27
- # Instantiates correct Firefox driver implementation
28
- # @return [Marionette::Driver, Legacy::Driver]
29
- #
30
-
31
- def new(**opts)
32
- if marionette?(opts)
33
- Firefox::Marionette::Driver.new(opts)
34
- else
35
- Firefox::Legacy::Driver.new(opts)
36
- end
37
- end
38
23
 
39
- private
24
+ #
25
+ # Driver implementation for Firefox using GeckoDriver.
26
+ # @api private
27
+ #
28
+
29
+ class Driver < WebDriver::Driver
30
+ EXTENSIONS = [DriverExtensions::HasAddons,
31
+ DriverExtensions::FullPageScreenshot,
32
+ DriverExtensions::HasContext,
33
+ DriverExtensions::HasBiDi,
34
+ DriverExtensions::HasDevTools,
35
+ DriverExtensions::HasLogEvents,
36
+ DriverExtensions::HasNetworkInterception,
37
+ DriverExtensions::HasWebStorage,
38
+ DriverExtensions::PrintsPage].freeze
39
+
40
+ def browser
41
+ :firefox
42
+ end
43
+
44
+ private
40
45
 
41
- def marionette?(opts)
42
- opts.delete(:marionette) != false &&
43
- (!opts[:desired_capabilities] || opts[:desired_capabilities][:marionette] != false)
46
+ def devtools_url
47
+ if capabilities['moz:debuggerAddress'].nil?
48
+ raise(Error::WebDriverError, "DevTools is not supported by this version of Firefox; use v85 or higher")
44
49
  end
50
+
51
+ uri = URI("http://#{capabilities['moz:debuggerAddress']}")
52
+ response = Net::HTTP.get(uri.hostname, '/json/version', uri.port)
53
+
54
+ JSON.parse(response)['webSocketDebuggerUrl']
45
55
  end
46
56
 
57
+ def devtools_version
58
+ Firefox::DEVTOOLS_VERSION
59
+ end
47
60
  end # Driver
48
61
  end # Firefox
49
62
  end # WebDriver
@@ -87,6 +87,14 @@ module Selenium
87
87
  return unless File.exist?(manifest_path)
88
88
 
89
89
  manifest = JSON.parse(File.read(manifest_path))
90
+ applications_gecko_id(manifest) || name_and_version(manifest)
91
+ end
92
+
93
+ def applications_gecko_id(manifest)
94
+ manifest.dig('applications', 'gecko', 'id')&.strip
95
+ end
96
+
97
+ def name_and_version(manifest)
90
98
  [manifest['name'].delete(' '), manifest['version']].join('@')
91
99
  end
92
100
  end # Extension
@@ -0,0 +1,63 @@
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 Firefox
23
+ module Features
24
+
25
+ FIREFOX_COMMANDS = {
26
+ get_context: [:get, 'session/:session_id/moz/context'],
27
+ set_context: [:post, 'session/:session_id/moz/context'],
28
+ install_addon: [:post, 'session/:session_id/moz/addon/install'],
29
+ uninstall_addon: [:post, 'session/:session_id/moz/addon/uninstall'],
30
+ full_page_screenshot: [:get, 'session/:session_id/moz/screenshot/full']
31
+ }.freeze
32
+
33
+ def commands(command)
34
+ FIREFOX_COMMANDS[command] || self.class::COMMANDS[command]
35
+ end
36
+
37
+ def install_addon(path, temporary)
38
+ addon = File.open(path, 'rb') { |crx_file| Base64.strict_encode64 crx_file.read }
39
+
40
+ payload = {addon: addon}
41
+ payload[:temporary] = temporary unless temporary.nil?
42
+ execute :install_addon, {}, payload
43
+ end
44
+
45
+ def uninstall_addon(id)
46
+ execute :uninstall_addon, {}, {id: id}
47
+ end
48
+
49
+ def full_screenshot
50
+ execute :full_page_screenshot
51
+ end
52
+
53
+ def context=(context)
54
+ execute :set_context, {}, {context: context}
55
+ end
56
+
57
+ def context
58
+ execute :get_context
59
+ end
60
+ end # Bridge
61
+ end # Firefox
62
+ end # WebDriver
63
+ end # Selenium
@@ -20,18 +20,32 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Firefox
23
- class Options < WebDriver::Common::Options
24
- attr_reader :args, :prefs, :options, :profile
25
- attr_accessor :binary, :log_level
23
+ class Options < WebDriver::Options
24
+ attr_accessor :debugger_address
26
25
 
27
26
  KEY = 'moz:firefoxOptions'
28
27
 
28
+ # see: https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions
29
+ CAPABILITIES = {binary: 'binary',
30
+ args: 'args',
31
+ log: 'log',
32
+ prefs: 'prefs',
33
+ env: 'env',
34
+ android_package: 'androidPackage',
35
+ android_activity: 'androidActivity',
36
+ android_device_serial: 'androidDeviceSerial',
37
+ android_intent_arguments: 'androidIntentArguments'}.freeze
38
+ BROWSER = 'firefox'
39
+
40
+ # NOTE: special handling of 'profile' to validate when set instead of when used
41
+ attr_reader :profile
42
+
29
43
  #
30
44
  # Create a new Options instance, only for W3C-capable versions of Firefox.
31
45
  #
32
46
  # @example
33
47
  # options = Selenium::WebDriver::Firefox::Options.new(args: ['--host=127.0.0.1'])
34
- # driver = Selenium::WebDriver.for :firefox, options: options
48
+ # driver = Selenium::WebDriver.for :firefox, capabilities: options
35
49
  #
36
50
  # @param [Hash] opts the pre-defined options to create the Firefox::Options with
37
51
  # @option opts [String] :binary Path to the Firefox executable to use
@@ -42,13 +56,17 @@ module Selenium
42
56
  # @option opts [Hash] :options A hash for raw options
43
57
  #
44
58
 
45
- def initialize(**opts)
46
- @args = Set.new(opts.delete(:args) || [])
47
- @binary = opts.delete(:binary)
48
- @profile = process_profile(opts.delete(:profile))
49
- @log_level = opts.delete(:log_level)
50
- @prefs = opts.delete(:prefs) || {}
51
- @options = opts.delete(:options) || {}
59
+ def initialize(log_level: nil, **opts)
60
+ @debugger_address = opts.delete(:debugger_address)
61
+
62
+ super(**opts)
63
+
64
+ @options[:args] ||= []
65
+ @options[:prefs] ||= {}
66
+ @options[:env] ||= {}
67
+ @options[:log] ||= {level: log_level} if log_level
68
+
69
+ process_profile(@options.delete(:profile))
52
70
  end
53
71
 
54
72
  #
@@ -62,22 +80,7 @@ module Selenium
62
80
  #
63
81
 
64
82
  def add_argument(arg)
65
- @args << arg
66
- end
67
-
68
- #
69
- # Add a new option not yet handled by these bindings.
70
- #
71
- # @example
72
- # options = Selenium::WebDriver::Firefox::Options.new
73
- # options.add_option(:foo, 'bar')
74
- #
75
- # @param [String, Symbol] name Name of the option
76
- # @param [Boolean, String, Integer] value Value of the option
77
- #
78
-
79
- def add_option(name, value)
80
- @options[name] = value
83
+ @options[:args] << arg
81
84
  end
82
85
 
83
86
  #
@@ -92,7 +95,7 @@ module Selenium
92
95
  #
93
96
 
94
97
  def add_preference(name, value)
95
- prefs[name] = value
98
+ @options[:prefs][name] = value
96
99
  end
97
100
 
98
101
  #
@@ -123,38 +126,58 @@ module Selenium
123
126
  #
124
127
 
125
128
  def profile=(profile)
126
- @profile = process_profile(profile)
129
+ process_profile(profile)
127
130
  end
128
131
 
129
- #
130
- # @api private
131
- #
132
+ def log_level
133
+ @options.dig(:log, :level)
134
+ end
132
135
 
133
- def as_json(*)
134
- opts = @options
136
+ def log_level=(level)
137
+ @options[:log] = {level: level}
138
+ end
135
139
 
136
- opts[:profile] = @profile.encoded if @profile
137
- opts[:args] = @args.to_a if @args.any?
138
- opts[:binary] = @binary if @binary
139
- opts[:prefs] = @prefs unless @prefs.empty?
140
- opts[:log] = {level: @log_level} if @log_level
140
+ #
141
+ # Enables mobile browser use on Android.
142
+ #
143
+ # @see https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptions#android
144
+ #
145
+ # @param [String] package The package name of the Chrome or WebView app.
146
+ # @param [String] serial_number The serial number of the device on which to launch the application.
147
+ # If not specified and multiple devices are attached, an error will be returned.
148
+ # @param [String] activity The fully qualified class name of the activity to be launched.
149
+ # @param [Array] intent_arguments Arguments to launch the intent with.
150
+ #
141
151
 
142
- {KEY => generate_as_json(opts)}
152
+ def enable_android(package: 'org.mozilla.firefox', serial_number: nil, activity: nil, intent_arguments: nil)
153
+ @options[:android_package] = package
154
+ @options[:android_activity] = activity unless activity.nil?
155
+ @options[:android_device_serial] = serial_number unless serial_number.nil?
156
+ @options[:android_intent_arguments] = intent_arguments unless intent_arguments.nil?
143
157
  end
144
158
 
145
159
  private
146
160
 
161
+ def process_browser_options(browser_options)
162
+ browser_options['moz:debuggerAddress'] = true if @debugger_address
163
+ options = browser_options[KEY]
164
+ options['binary'] ||= Firefox.path if Firefox.path
165
+ options['profile'] = @profile if @profile
166
+ end
167
+
147
168
  def process_profile(profile)
148
- return unless profile
149
-
150
- case profile
151
- when Profile
152
- profile
153
- when String
154
- Profile.from_name(profile)
155
- else
156
- raise Error::WebDriverError, "don't know how to handle profile: #{profile.inspect}"
157
- end
169
+ @profile = case profile
170
+ when nil
171
+ nil
172
+ when Profile
173
+ profile
174
+ else
175
+ Profile.from_name(profile)
176
+ end
177
+ end
178
+
179
+ def camelize?(key)
180
+ key != "prefs"
158
181
  end
159
182
  end # Options
160
183
  end # Firefox