selenium-webdriver 3.142.4 → 4.1.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 (137) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +381 -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 +69 -63
  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/chrome/driver.rb +26 -70
  13. data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +50 -12
  14. data/lib/selenium/webdriver/chrome/options.rb +128 -53
  15. data/lib/selenium/webdriver/chrome/profile.rb +8 -5
  16. data/lib/selenium/webdriver/chrome/service.rb +8 -15
  17. data/lib/selenium/webdriver/chrome.rb +10 -9
  18. data/lib/selenium/webdriver/common/action_builder.rb +97 -249
  19. data/lib/selenium/webdriver/common/driver.rb +112 -23
  20. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  21. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
  22. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  23. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
  24. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_cdp.rb} +10 -8
  25. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
  26. data/lib/selenium/webdriver/{firefox/util.rb → common/driver_extensions/has_devtools.rb} +16 -19
  27. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +38 -0
  28. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  29. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +144 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +17 -0
  32. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  33. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +136 -0
  34. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
  35. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
  36. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  37. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  38. data/lib/selenium/webdriver/common/element.rb +82 -22
  39. data/lib/selenium/webdriver/common/error.rb +32 -196
  40. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  41. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -5
  42. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +13 -13
  43. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  44. data/lib/selenium/webdriver/common/logger.rb +50 -15
  45. data/lib/selenium/webdriver/common/manager.rb +15 -15
  46. data/lib/selenium/webdriver/common/options.rb +184 -0
  47. data/lib/selenium/webdriver/common/platform.rb +6 -1
  48. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  49. data/lib/selenium/webdriver/common/profile_helper.rb +11 -9
  50. data/lib/selenium/webdriver/common/proxy.rb +6 -3
  51. data/lib/selenium/webdriver/common/search_context.rb +7 -3
  52. data/lib/selenium/webdriver/common/service.rb +17 -125
  53. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  54. data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
  55. data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
  56. data/lib/selenium/webdriver/common/socket_poller.rb +2 -2
  57. data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
  58. data/lib/selenium/webdriver/common/target_locator.rb +32 -4
  59. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  60. data/lib/selenium/webdriver/common/wait.rb +1 -1
  61. data/lib/selenium/webdriver/common/window.rb +0 -4
  62. data/lib/selenium/webdriver/common/zipper.rb +3 -9
  63. data/lib/selenium/webdriver/common.rb +24 -17
  64. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  65. data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
  66. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  67. data/lib/selenium/webdriver/devtools/pinned_script.rb +59 -0
  68. data/lib/selenium/webdriver/devtools/request.rb +67 -0
  69. data/lib/selenium/webdriver/devtools/response.rb +66 -0
  70. data/lib/selenium/webdriver/devtools.rb +193 -0
  71. data/lib/selenium/webdriver/edge/driver.rb +7 -29
  72. data/lib/selenium/webdriver/edge/features.rb +44 -0
  73. data/lib/selenium/webdriver/edge/options.rb +11 -48
  74. data/lib/selenium/webdriver/{common/w3c_manager.rb → edge/profile.rb} +7 -19
  75. data/lib/selenium/webdriver/edge/service.rb +10 -26
  76. data/lib/selenium/webdriver/edge.rb +11 -14
  77. data/lib/selenium/webdriver/firefox/driver.rb +31 -19
  78. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  79. data/lib/selenium/webdriver/firefox/features.rb +66 -0
  80. data/lib/selenium/webdriver/firefox/options.rb +71 -50
  81. data/lib/selenium/webdriver/firefox/profile.rb +21 -71
  82. data/lib/selenium/webdriver/firefox/service.rb +5 -9
  83. data/lib/selenium/webdriver/firefox.rb +22 -20
  84. data/lib/selenium/webdriver/ie/driver.rb +1 -47
  85. data/lib/selenium/webdriver/ie/options.rb +15 -46
  86. data/lib/selenium/webdriver/ie/service.rb +13 -15
  87. data/lib/selenium/webdriver/ie.rb +8 -7
  88. data/lib/selenium/webdriver/remote/bridge.rb +561 -86
  89. data/lib/selenium/webdriver/remote/capabilities.rb +159 -123
  90. data/lib/selenium/webdriver/remote/commands.rb +163 -0
  91. data/lib/selenium/webdriver/remote/driver.rb +22 -12
  92. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  93. data/lib/selenium/webdriver/remote/http/default.rb +17 -20
  94. data/lib/selenium/webdriver/remote/http/persistent.rb +11 -6
  95. data/lib/selenium/webdriver/remote/response.rb +16 -47
  96. data/lib/selenium/webdriver/remote.rb +15 -12
  97. data/lib/selenium/webdriver/safari/driver.rb +3 -31
  98. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
  99. data/lib/selenium/webdriver/safari/options.rb +10 -29
  100. data/lib/selenium/webdriver/safari/service.rb +4 -8
  101. data/lib/selenium/webdriver/safari.rb +17 -9
  102. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  103. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  104. data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
  105. data/lib/selenium/webdriver/support/color.rb +2 -2
  106. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  107. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  108. data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +22 -19
  109. data/lib/selenium/webdriver/support/guards.rb +95 -0
  110. data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
  111. data/lib/selenium/webdriver/support/select.rb +3 -3
  112. data/lib/selenium/webdriver/support.rb +1 -0
  113. data/lib/selenium/webdriver/version.rb +1 -1
  114. data/lib/selenium/webdriver.rb +13 -13
  115. data/selenium-webdriver.gemspec +29 -13
  116. metadata +126 -72
  117. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  118. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  119. data/lib/selenium/webdriver/common/keyboard.rb +0 -70
  120. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  121. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  122. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  123. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  124. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  125. data/lib/selenium/webdriver/firefox/binary.rb +0 -187
  126. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  127. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  128. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  129. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  130. data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
  131. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  132. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  133. data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
  134. data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
  135. data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
  136. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
  137. data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
@@ -27,87 +27,43 @@ module Selenium
27
27
  #
28
28
 
29
29
  class Driver < WebDriver::Driver
30
- include DriverExtensions::HasNetworkConditions
31
- include DriverExtensions::HasTouchScreen
32
- include DriverExtensions::HasWebStorage
33
- include DriverExtensions::HasLocation
34
- include DriverExtensions::TakesScreenshot
35
- include DriverExtensions::DownloadsFiles
36
-
37
- def initialize(opts = {})
38
- opts[:desired_capabilities] = create_capabilities(opts)
39
-
40
- opts[:url] ||= service_url(opts)
41
-
42
- listener = opts.delete(:listener)
43
- @bridge = Remote::Bridge.handshake(opts)
44
- @bridge.extend Bridge
45
-
46
- super(@bridge, listener: listener)
47
- end
30
+ EXTENSIONS = [DriverExtensions::HasCDP,
31
+ DriverExtensions::HasCasting,
32
+ DriverExtensions::HasNetworkConditions,
33
+ DriverExtensions::HasNetworkInterception,
34
+ DriverExtensions::HasWebStorage,
35
+ DriverExtensions::HasLaunching,
36
+ DriverExtensions::HasLocation,
37
+ DriverExtensions::HasPermissions,
38
+ DriverExtensions::DownloadsFiles,
39
+ DriverExtensions::HasDevTools,
40
+ DriverExtensions::HasAuthentication,
41
+ DriverExtensions::HasLogs,
42
+ DriverExtensions::HasLogEvents,
43
+ DriverExtensions::HasPinnedScripts,
44
+ DriverExtensions::PrintsPage].freeze
48
45
 
49
46
  def browser
50
47
  :chrome
51
48
  end
52
49
 
53
- def quit
54
- super
55
- ensure
56
- @service&.stop
57
- end
58
-
59
- def execute_cdp(cmd, **params)
60
- @bridge.send_command(cmd: cmd, params: params)
61
- end
62
-
63
50
  private
64
51
 
65
- def create_capabilities(opts)
66
- caps = opts.delete(:desired_capabilities) { Remote::Capabilities.chrome }
67
- options = opts.delete(:options) { Options.new }
68
-
69
- args = opts.delete(:args) || opts.delete(:switches)
70
- if args
71
- WebDriver.logger.deprecate ':args or :switches', 'Selenium::WebDriver::Chrome::Options#add_argument'
72
- raise ArgumentError, ':args must be an Array of Strings' unless args.is_a? Array
52
+ def devtools_url
53
+ uri = URI(devtools_address)
54
+ response = Net::HTTP.get(uri.hostname, '/json/version', uri.port)
73
55
 
74
- args.each { |arg| options.add_argument(arg.to_s) }
75
- end
76
-
77
- profile = opts.delete(:profile)
78
- if profile
79
- profile = profile.as_json
80
-
81
- options.add_argument("--user-data-dir=#{profile[:directory]}") if options.args.none? { |arg| arg =~ /user-data-dir/ }
82
-
83
- if profile[:extensions]
84
- WebDriver.logger.deprecate 'Using Selenium::WebDriver::Chrome::Profile#extensions',
85
- 'Selenium::WebDriver::Chrome::Options#add_extension'
86
- profile[:extensions].each do |extension|
87
- options.add_encoded_extension(extension)
88
- end
89
- end
90
- end
91
-
92
- detach = opts.delete(:detach)
93
- options.add_option(:detach, true) if detach
94
-
95
- prefs = opts.delete(:prefs)
96
- if prefs
97
- WebDriver.logger.deprecate ':prefs', 'Selenium::WebDriver::Chrome::Options#add_preference'
98
- prefs.each do |key, value|
99
- options.add_preference(key, value)
100
- end
101
- end
102
-
103
- options = options.as_json
104
- caps.merge!(options) unless options[Options::KEY].empty?
56
+ JSON.parse(response)['webSocketDebuggerUrl']
57
+ end
105
58
 
106
- caps[:proxy] = opts.delete(:proxy) if opts.key?(:proxy)
107
- caps[:proxy] ||= opts.delete('proxy') if opts.key?('proxy')
59
+ def devtools_version
60
+ Integer(capabilities.browser_version.split('.').first)
61
+ end
108
62
 
109
- caps
63
+ def devtools_address
64
+ "http://#{capabilities['goog:chromeOptions']['debuggerAddress']}"
110
65
  end
66
+
111
67
  end # Driver
112
68
  end # Chrome
113
69
  end # WebDriver
@@ -20,32 +20,72 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Chrome
23
- module Bridge
23
+ module Features
24
24
 
25
- COMMANDS = {
25
+ CHROME_COMMANDS = {
26
+ launch_app: [:post, 'session/:session_id/chromium/launch_app'],
27
+ get_cast_sinks: [:get, 'session/:session_id/goog/cast/get_sinks'],
28
+ set_cast_sink_to_use: [:post, 'session/:session_id/goog/cast/set_sink_to_use'],
29
+ start_cast_tab_mirroring: [:post, 'session/:session_id/goog/cast/start_tab_mirroring'],
30
+ get_cast_issue_message: [:get, 'session/:session_id/goog/cast/get_issue_message'],
31
+ stop_casting: [:post, 'session/:session_id/goog/cast/stop_casting'],
26
32
  get_network_conditions: [:get, 'session/:session_id/chromium/network_conditions'],
27
33
  set_network_conditions: [:post, 'session/:session_id/chromium/network_conditions'],
34
+ delete_network_conditions: [:delete, 'session/:session_id/chromium/network_conditions'],
35
+ set_permission: [:post, 'session/:session_id/permissions'],
28
36
  send_command: [:post, 'session/:session_id/goog/cdp/execute'],
29
37
  get_available_log_types: [:get, 'session/:session_id/se/log/types'],
30
38
  get_log: [:post, 'session/:session_id/se/log']
31
39
  }.freeze
32
40
 
33
41
  def commands(command)
34
- COMMANDS[command] || super
42
+ CHROME_COMMANDS[command] || self.class::COMMANDS[command]
35
43
  end
36
44
 
37
- def network_conditions
38
- execute :get_network_conditions
45
+ def launch_app(id)
46
+ execute :launch_app, {}, {id: id}
39
47
  end
40
48
 
41
- def send_command(command_params)
42
- execute :send_command, {}, command_params
49
+ def cast_sinks
50
+ execute :get_cast_sinks
51
+ end
52
+
53
+ def cast_sink_to_use=(name)
54
+ execute :set_cast_sink_to_use, {}, {sinkName: name}
55
+ end
56
+
57
+ def cast_issue_message
58
+ execute :cast_issue_message
59
+ end
60
+
61
+ def start_cast_tab_mirroring(name)
62
+ execute :start_cast_tab_mirroring, {}, {sinkName: name}
63
+ end
64
+
65
+ def stop_casting(name)
66
+ execute :stop_casting, {}, {sinkName: name}
67
+ end
68
+
69
+ def set_permission(name, value)
70
+ execute :set_permission, {}, {descriptor: {name: name}, state: value}
71
+ end
72
+
73
+ def network_conditions
74
+ execute :get_network_conditions
43
75
  end
44
76
 
45
77
  def network_conditions=(conditions)
46
78
  execute :set_network_conditions, {}, {network_conditions: conditions}
47
79
  end
48
80
 
81
+ def delete_network_conditions
82
+ execute :delete_network_conditions
83
+ end
84
+
85
+ def send_command(command_params)
86
+ execute :send_command, {}, command_params
87
+ end
88
+
49
89
  def available_log_types
50
90
  types = execute :get_available_log_types
51
91
  Array(types).map(&:to_sym)
@@ -55,11 +95,9 @@ module Selenium
55
95
  data = execute :get_log, {}, {type: type.to_s}
56
96
 
57
97
  Array(data).map do |l|
58
- begin
59
- LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
60
- rescue KeyError
61
- next
62
- end
98
+ LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
99
+ rescue KeyError
100
+ next
63
101
  end
64
102
  end
65
103
  end # Bridge
@@ -20,19 +20,40 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Chrome
23
- class Options
24
- attr_reader :args, :prefs, :options, :emulation, :extensions, :encoded_extensions
25
- attr_accessor :binary
23
+ class Options < WebDriver::Options
24
+ attr_accessor :profile, :logging_prefs
26
25
 
27
26
  KEY = 'goog:chromeOptions'
27
+ BROWSER = 'chrome'
28
+
29
+ # see: http://chromedriver.chromium.org/capabilities
30
+ CAPABILITIES = {args: 'args',
31
+ binary: 'binary',
32
+ local_state: 'localState',
33
+ prefs: 'prefs',
34
+ detach: 'detach',
35
+ debugger_address: 'debuggerAddress',
36
+ exclude_switches: 'excludeSwitches',
37
+ minidump_path: 'minidumpPath',
38
+ emulation: 'mobileEmulation',
39
+ perf_logging_prefs: 'perfLoggingPrefs',
40
+ window_types: 'windowTypes',
41
+ android_package: 'androidPackage',
42
+ android_activity: 'androidActivity',
43
+ android_device_serial: 'androidDeviceSerial',
44
+ android_use_running_app: 'androidUseRunningApp'}.freeze
45
+
46
+ # NOTE: special handling of 'extensions' to validate when set instead of when used
47
+ attr_reader :extensions
28
48
 
29
- #
30
49
  # Create a new Options instance.
31
50
  #
32
51
  # @example
33
52
  # options = Selenium::WebDriver::Chrome::Options.new(args: ['start-maximized', 'user-data-dir=/tmp/temp_profile'])
34
- # driver = Selenium::WebDriver.for(:chrome, options: options)
53
+ # driver = Selenium::WebDriver.for(:chrome, capabilities: options)
35
54
  #
55
+ # @param [Profile] :profile An instance of a Chrome::Profile Class
56
+ # @param [Array] :encoded_extensions List of extensions that do not need to be Base64 encoded
36
57
  # @param [Hash] opts the pre-defined options to create the Chrome::Options with
37
58
  # @option opts [Array<String>] :args List of command-line arguments to use when starting Chrome
38
59
  # @option opts [String] :binary Path to the Chrome executable to use
@@ -40,16 +61,33 @@ module Selenium
40
61
  # @option opts [Array<String>] :extensions A list of paths to (.crx) Chrome extensions to install on startup
41
62
  # @option opts [Hash] :options A hash for raw options
42
63
  # @option opts [Hash] :emulation A hash for raw emulation options
64
+ # @option opts [Hash] :local_state A hash for the Local State file in the user data folder
65
+ # @option opts [Boolean] :detach whether browser is closed when the driver is sent the quit command
66
+ # @option opts [String] :debugger_address address of a Chrome debugger server to connect to
67
+ # @option opts [Array<String>] :exclude_switches command line switches to exclude
68
+ # @option opts [String] :minidump_path Directory to store Chrome minidumps (linux only)
69
+ # @option opts [Hash] :perf_logging_prefs A hash for performance logging preferences
70
+ # @option opts [Array<String>] :window_types A list of window types to appear in the list of window handles
43
71
  #
44
72
 
45
- def initialize(**opts)
46
- @args = Set.new(opts.delete(:args) || [])
47
- @binary = opts.delete(:binary) || Chrome.path
48
- @prefs = opts.delete(:prefs) || {}
49
- @extensions = opts.delete(:extensions) || []
50
- @options = opts.delete(:options) || {}
51
- @emulation = opts.delete(:emulation) || {}
52
- @encoded_extensions = []
73
+ def initialize(profile: nil, **opts)
74
+ super(**opts)
75
+
76
+ @profile = profile
77
+
78
+ @options = {args: [],
79
+ prefs: {},
80
+ emulation: {},
81
+ extensions: [],
82
+ local_state: {},
83
+ exclude_switches: [],
84
+ perf_logging_prefs: {},
85
+ window_types: []}.merge(@options)
86
+
87
+ @logging_prefs = options.delete(:logging_prefs) || {}
88
+ @encoded_extensions = @options.delete(:encoded_extensions) || []
89
+ @extensions = []
90
+ (@options.delete(:extensions)).each(&method(:validate_extension))
53
91
  end
54
92
 
55
93
  #
@@ -63,10 +101,22 @@ module Selenium
63
101
  #
64
102
 
65
103
  def add_extension(path)
66
- raise Error::WebDriverError, "could not find extension at #{path.inspect}" unless File.file?(path)
67
- raise Error::WebDriverError, "file was not an extension #{path.inspect}" unless File.extname(path) == '.crx'
104
+ validate_extension(path)
105
+ end
68
106
 
69
- @extensions << path
107
+ #
108
+ # Add an extension by local path.
109
+ #
110
+ # @example
111
+ # extensions = ['/path/to/extension.crx', '/path/to/other.crx']
112
+ # options = Selenium::WebDriver::Chrome::Options.new
113
+ # options.extensions = extensions
114
+ #
115
+ # @param [Array<String>] :extensions A list of paths to (.crx) Chrome extensions to install on startup
116
+ #
117
+
118
+ def extensions=(extensions)
119
+ extensions.each(&method(:validate_extension))
70
120
  end
71
121
 
72
122
  #
@@ -94,22 +144,7 @@ module Selenium
94
144
  #
95
145
 
96
146
  def add_argument(arg)
97
- @args << arg
98
- end
99
-
100
- #
101
- # Add a new option not yet handled by bindings.
102
- #
103
- # @example Leave Chrome open when chromedriver is killed
104
- # options = Selenium::WebDriver::Chrome::Options.new
105
- # options.add_option(:detach, true)
106
- #
107
- # @param [String, Symbol] name Name of the option
108
- # @param [Boolean, String, Integer] value Value of the option
109
- #
110
-
111
- def add_option(name, value)
112
- @options[name] = value
147
+ @options[:args] << arg
113
148
  end
114
149
 
115
150
  #
@@ -124,7 +159,7 @@ module Selenium
124
159
  #
125
160
 
126
161
  def add_preference(name, value)
127
- prefs[name] = value
162
+ @options[:prefs][name] = value
128
163
  end
129
164
 
130
165
  #
@@ -140,7 +175,9 @@ module Selenium
140
175
  end
141
176
 
142
177
  #
143
- # Add an emulation device name
178
+ # Add emulation device information
179
+ #
180
+ # see: http://chromedriver.chromium.org/mobile-emulation
144
181
  #
145
182
  # @example Start Chrome in mobile emulation mode by device name
146
183
  # options = Selenium::WebDriver::Chrome::Options.new
@@ -150,35 +187,73 @@ module Selenium
150
187
  # options = Selenium::WebDriver::Chrome::Options.new
151
188
  # options.add_emulation(device_metrics: {width: 400, height: 800, pixelRatio: 1, touch: true})
152
189
  #
153
- # @param [String] device_name Name of the device or a hash containing width, height, pixelRatio, touch
154
- # @param [Hash] device_metrics Hash containing width, height, pixelRatio, touch
155
- # @param [String] user_agent Full user agent
190
+ # @param [Hash] opts the pre-defined options for adding mobile emulation values
191
+ # @option opts [String] :device_name A valid device name from the Chrome DevTools Emulation panel
192
+ # @option opts [Hash] :device_metrics Hash containing width, height, pixelRatio, touch
193
+ # @option opts [String] :user_agent Full user agent
156
194
  #
157
195
 
158
- def add_emulation(device_name: nil, device_metrics: nil, user_agent: nil)
159
- @emulation[:deviceName] = device_name if device_name
160
- @emulation[:deviceMetrics] = device_metrics if device_metrics
161
- @emulation[:userAgent] = user_agent if user_agent
196
+ def add_emulation(**opts)
197
+ @options[:emulation] = opts
162
198
  end
163
199
 
164
200
  #
165
- # @api private
201
+ # Enables mobile browser use on Android.
166
202
  #
203
+ # @see https://chromedriver.chromium.org/getting-started/getting-started---android
204
+ #
205
+ # @param [String] package The package name of the Chrome or WebView app.
206
+ # @param [String] serial_number The device serial number on which to launch the Chrome or WebView app.
207
+ # @param [String] use_running_app When true uses an already-running Chrome or WebView app,
208
+ # instead of launching the app with a clear data directory.
209
+ # @param [String] activity Name of the Activity hosting the WebView (Not available on Chrome Apps).
210
+ #
211
+
212
+ def enable_android(package: 'com.android.chrome', serial_number: nil, use_running_app: nil, activity: nil)
213
+ @options[:android_package] = package
214
+ @options[:android_activity] = activity unless activity.nil?
215
+ @options[:android_device_serial] = serial_number unless serial_number.nil?
216
+ @options[:android_use_running_app] = use_running_app unless use_running_app.nil?
217
+ end
218
+
219
+ private
220
+
221
+ def enable_logging(browser_options)
222
+ browser_options['goog:loggingPrefs'] = @logging_prefs
223
+ end
224
+
225
+ def process_browser_options(browser_options)
226
+ enable_logging(browser_options) unless @logging_prefs.empty?
167
227
 
168
- def as_json(*)
169
- extensions = @extensions.map do |crx_path|
170
- File.open(crx_path, 'rb') { |crx_file| Base64.strict_encode64 crx_file.read }
228
+ options = browser_options[self.class::KEY]
229
+ options['binary'] ||= binary_path if binary_path
230
+ if @profile
231
+ options['args'] ||= []
232
+ options['args'] << "--user-data-dir=#{@profile.directory}"
171
233
  end
172
- extensions.concat(@encoded_extensions)
173
234
 
174
- opts = @options
175
- opts[:binary] = @binary if @binary
176
- opts[:args] = @args.to_a if @args.any?
177
- opts[:extensions] = extensions if extensions.any?
178
- opts[:mobileEmulation] = @emulation unless @emulation.empty?
179
- opts[:prefs] = @prefs unless @prefs.empty?
235
+ return if (@encoded_extensions + @extensions).empty?
236
+
237
+ options['extensions'] = @encoded_extensions + @extensions.map(&method(:encode_extension))
238
+ end
239
+
240
+ def binary_path
241
+ Chrome.path
242
+ end
243
+
244
+ def encode_extension(path)
245
+ File.open(path, 'rb') { |crx_file| Base64.strict_encode64 crx_file.read }
246
+ end
247
+
248
+ def validate_extension(path)
249
+ raise Error::WebDriverError, "could not find extension at #{path.inspect}" unless File.file?(path)
250
+ raise Error::WebDriverError, "file was not an extension #{path.inspect}" unless File.extname(path) == '.crx'
251
+
252
+ @extensions << path
253
+ end
180
254
 
181
- {KEY => opts}
255
+ def camelize?(key)
256
+ !%w[localState prefs].include?(key)
182
257
  end
183
258
  end # Options
184
259
  end # Chrome
@@ -27,12 +27,11 @@ module Selenium
27
27
  class Profile
28
28
  include ProfileHelper
29
29
 
30
- attr_reader :directory
31
-
32
30
  def initialize(model = nil)
33
31
  @model = verify_model(model)
34
32
  @extensions = []
35
33
  @encoded_extensions = []
34
+ @directory = nil
36
35
  end
37
36
 
38
37
  def add_extension(path)
@@ -45,10 +44,14 @@ module Selenium
45
44
  @encoded_extensions << encoded
46
45
  end
47
46
 
47
+ def directory
48
+ @directory || layout_on_disk
49
+ end
50
+
48
51
  #
49
52
  # Set a preference in the profile.
50
53
  #
51
- # See https://src.chromium.org/svn/trunk/src/chrome/common/pref_names.cc
54
+ # See https://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/pref_names.cc
52
55
  #
53
56
 
54
57
  def []=(key, value)
@@ -77,8 +80,8 @@ module Selenium
77
80
 
78
81
  extensions.concat(@encoded_extensions)
79
82
 
80
- opts = {directory: directory || layout_on_disk}
81
- opts[:extensions] = extensions if extensions.any?
83
+ opts = {'directory' => directory || layout_on_disk}
84
+ opts['extensions'] = extensions if extensions.any?
82
85
  opts
83
86
  end
84
87
 
@@ -20,35 +20,28 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Chrome
23
- #
24
- # @api private
25
- #
26
-
27
23
  class Service < WebDriver::Service
28
- @default_port = 9515
29
- @executable = 'chromedriver'
30
- @missing_text = <<~ERROR
24
+ DEFAULT_PORT = 9515
25
+ EXECUTABLE = 'chromedriver'
26
+ MISSING_TEXT = <<~ERROR
31
27
  Unable to find chromedriver. Please download the server from
32
28
  https://chromedriver.storage.googleapis.com/index.html and place it somewhere on your PATH.
33
29
  More info at https://github.com/SeleniumHQ/selenium/wiki/ChromeDriver.
34
30
  ERROR
35
- @shutdown_supported = true
36
-
37
- def self.driver_path=(path)
38
- Platform.assert_executable path if path.is_a?(String)
39
- @driver_path = path
40
- end
31
+ SHUTDOWN_SUPPORTED = true
41
32
 
42
33
  private
43
34
 
44
- # Note: This processing is deprecated
35
+ # NOTE: This processing is deprecated
45
36
  def extract_service_args(driver_opts)
46
37
  driver_args = super
47
38
  driver_opts = driver_opts.dup
48
39
  driver_args << "--log-path=#{driver_opts.delete(:log_path)}" if driver_opts.key?(:log_path)
49
40
  driver_args << "--url-base=#{driver_opts.delete(:url_base)}" if driver_opts.key?(:url_base)
50
41
  driver_args << "--port-server=#{driver_opts.delete(:port_server)}" if driver_opts.key?(:port_server)
51
- driver_args << "--whitelisted-ips=#{driver_opts.delete(:whitelisted_ips)}" if driver_opts.key?(:whitelisted_ips)
42
+ if driver_opts.key?(:whitelisted_ips)
43
+ driver_args << "--whitelisted-ips=#{driver_opts.delete(:whitelisted_ips)}"
44
+ end
52
45
  driver_args << "--verbose" if driver_opts.key?(:verbose)
53
46
  driver_args << "--silent" if driver_opts.key?(:silent)
54
47
  driver_args
@@ -19,23 +19,26 @@
19
19
 
20
20
  require 'net/http'
21
21
 
22
- require 'selenium/webdriver/chrome/bridge'
23
- require 'selenium/webdriver/chrome/driver'
24
- require 'selenium/webdriver/chrome/profile'
25
- require 'selenium/webdriver/chrome/options'
26
-
27
22
  module Selenium
28
23
  module WebDriver
29
24
  module Chrome
25
+ autoload :Features, 'selenium/webdriver/chrome/features'
26
+ autoload :Driver, 'selenium/webdriver/chrome/driver'
27
+ autoload :Profile, 'selenium/webdriver/chrome/profile'
28
+ autoload :Options, 'selenium/webdriver/chrome/options'
29
+ autoload :Service, 'selenium/webdriver/chrome/service'
30
+
30
31
  def self.driver_path=(path)
31
32
  WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome#driver_path=',
32
- 'Selenium::WebDriver::Chrome::Service#driver_path='
33
+ 'Selenium::WebDriver::Chrome::Service#driver_path=',
34
+ id: :driver_path
33
35
  Selenium::WebDriver::Chrome::Service.driver_path = path
34
36
  end
35
37
 
36
38
  def self.driver_path
37
39
  WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome#driver_path',
38
- 'Selenium::WebDriver::Chrome::Service#driver_path'
40
+ 'Selenium::WebDriver::Chrome::Service#driver_path',
41
+ id: :driver_path
39
42
  Selenium::WebDriver::Chrome::Service.driver_path
40
43
  end
41
44
 
@@ -50,5 +53,3 @@ module Selenium
50
53
  end # Chrome
51
54
  end # WebDriver
52
55
  end # Selenium
53
-
54
- require 'selenium/webdriver/chrome/service'