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
@@ -0,0 +1,38 @@
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
+ class BiDi
23
+ class Session
24
+ Status = Struct.new(:ready, :message)
25
+
26
+ def initialize(bidi)
27
+ @bidi = bidi
28
+ end
29
+
30
+ def status
31
+ status = @bidi.send_cmd('session.status')
32
+ Status.new(status['ready'], status['message'])
33
+ end
34
+
35
+ end # Session
36
+ end # BiDi
37
+ end # WebDriver
38
+ end # Selenium
@@ -0,0 +1,55 @@
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
+ class BiDi
23
+ autoload :Session, 'selenium/webdriver/bidi/session'
24
+
25
+ def initialize(url:)
26
+ @ws = WebSocketConnection.new(url: url)
27
+ end
28
+
29
+ def close
30
+ @ws.close
31
+ end
32
+
33
+ def callbacks
34
+ @ws.callbacks
35
+ end
36
+
37
+ def session
38
+ Session.new(self)
39
+ end
40
+
41
+ def send_cmd(method, **params)
42
+ data = {method: method, params: params.compact}
43
+ message = @ws.send_cmd(**data)
44
+ raise Error::WebDriverError, error_message(message) if message['error']
45
+
46
+ message['result']
47
+ end
48
+
49
+ def error_message(message)
50
+ "#{message['error']}: #{message['message']}\n#{message['stacktrace']}"
51
+ end
52
+
53
+ end # BiDi
54
+ end # WebDriver
55
+ end # Selenium
@@ -27,100 +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
73
-
74
- args.each { |arg| options.add_argument(arg.to_s) }
75
- end
52
+ def devtools_url
53
+ uri = URI(devtools_address)
54
+ response = Net::HTTP.get(uri.hostname, '/json/version', uri.port)
76
55
 
77
- profile = opts.delete(:profile)
78
- if profile
79
- WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome::Driver#new with `:profile` parameter',
80
- 'Selenium::WebDriver::Chrome::Options#profile or Options#add_option'
81
-
82
- profile = profile.as_json
83
-
84
- if options.args.none?(&/user-data-dir/.method(:match?))
85
- options.add_argument("--user-data-dir=#{profile['directory']}")
86
- end
87
-
88
- if profile['extensions']
89
- WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome::Profile#extensions',
90
- 'Selenium::WebDriver::Chrome::Options#add_extension'
91
- profile['extensions'].each do |extension|
92
- options.add_encoded_extension(extension)
93
- end
94
- end
95
- end
96
-
97
- if opts.key?(:detach)
98
- WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome::Driver#new with `:detach` parameter',
99
- 'Selenium::WebDriver::Chrome::Options#new or Options#add_option'
100
- options.add_option(:detach, opts.delete(:detach))
101
- end
102
-
103
- prefs = opts.delete(:prefs)
104
- if prefs
105
- WebDriver.logger.deprecate ':prefs', 'Selenium::WebDriver::Chrome::Options#add_preference'
106
- prefs.each do |key, value|
107
- options.add_preference(key, value)
108
- end
109
- end
110
-
111
- options = options.as_json
112
- caps.merge!(options) unless options[Options::KEY].empty?
113
-
114
- if opts.key?(:proxy) || opts.key?('proxy')
115
- WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome::Driver#new with `:proxy` parameter',
116
- 'Selenium::WebDriver::Chrome::Capabilities#proxy='
56
+ JSON.parse(response)['webSocketDebuggerUrl']
57
+ end
117
58
 
118
- caps[:proxy] = opts.delete(:proxy) if opts.key?(:proxy)
119
- caps[:proxy] ||= opts.delete('proxy') if opts.key?('proxy')
120
- end
59
+ def devtools_version
60
+ Integer(capabilities.browser_version.split('.').first)
61
+ end
121
62
 
122
- caps
63
+ def devtools_address
64
+ "http://#{capabilities['goog:chromeOptions']['debuggerAddress']}"
123
65
  end
66
+
124
67
  end # Driver
125
68
  end # Chrome
126
69
  end # WebDriver
@@ -20,32 +20,77 @@
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
+ start_cast_desktop_mirroring: [:post, 'session/:session_id/goog/cast/start_desktop_mirroring'],
31
+ get_cast_issue_message: [:get, 'session/:session_id/goog/cast/get_issue_message'],
32
+ stop_casting: [:post, 'session/:session_id/goog/cast/stop_casting'],
26
33
  get_network_conditions: [:get, 'session/:session_id/chromium/network_conditions'],
27
34
  set_network_conditions: [:post, 'session/:session_id/chromium/network_conditions'],
35
+ delete_network_conditions: [:delete, 'session/:session_id/chromium/network_conditions'],
36
+ set_permission: [:post, 'session/:session_id/permissions'],
28
37
  send_command: [:post, 'session/:session_id/goog/cdp/execute'],
29
38
  get_available_log_types: [:get, 'session/:session_id/se/log/types'],
30
39
  get_log: [:post, 'session/:session_id/se/log']
31
40
  }.freeze
32
41
 
33
42
  def commands(command)
34
- COMMANDS[command] || super
43
+ CHROME_COMMANDS[command] || self.class::COMMANDS[command]
35
44
  end
36
45
 
37
- def network_conditions
38
- execute :get_network_conditions
46
+ def launch_app(id)
47
+ execute :launch_app, {}, {id: id}
39
48
  end
40
49
 
41
- def send_command(command_params)
42
- execute :send_command, {}, command_params
50
+ def cast_sinks
51
+ execute :get_cast_sinks
52
+ end
53
+
54
+ def cast_sink_to_use=(name)
55
+ execute :set_cast_sink_to_use, {}, {sinkName: name}
56
+ end
57
+
58
+ def cast_issue_message
59
+ execute :cast_issue_message
60
+ end
61
+
62
+ def start_cast_tab_mirroring(name)
63
+ execute :start_cast_tab_mirroring, {}, {sinkName: name}
64
+ end
65
+
66
+ def start_cast_desktop_mirroring(name)
67
+ execute :start_cast_desktop_mirroring, {}, {sinkName: name}
68
+ end
69
+
70
+ def stop_casting(name)
71
+ execute :stop_casting, {}, {sinkName: name}
72
+ end
73
+
74
+ def set_permission(name, value)
75
+ execute :set_permission, {}, {descriptor: {name: name}, state: value}
76
+ end
77
+
78
+ def network_conditions
79
+ execute :get_network_conditions
43
80
  end
44
81
 
45
82
  def network_conditions=(conditions)
46
83
  execute :set_network_conditions, {}, {network_conditions: conditions}
47
84
  end
48
85
 
86
+ def delete_network_conditions
87
+ execute :delete_network_conditions
88
+ end
89
+
90
+ def send_command(command_params)
91
+ execute :send_command, {}, command_params
92
+ end
93
+
49
94
  def available_log_types
50
95
  types = execute :get_available_log_types
51
96
  Array(types).map(&:to_sym)
@@ -55,11 +100,9 @@ module Selenium
55
100
  data = execute :get_log, {}, {type: type.to_s}
56
101
 
57
102
  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
103
+ LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
104
+ rescue KeyError
105
+ next
63
106
  end
64
107
  end
65
108
  end # Bridge
@@ -20,38 +20,74 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Chrome
23
- class Options < WebDriver::Common::Options
24
- attr_reader :args, :prefs, :options, :emulation, :extensions, :encoded_extensions
25
- attr_accessor :binary, :profile, :detach
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
36
56
  # @param [Hash] opts the pre-defined options to create the Chrome::Options with
37
- # @option opts [Array<String>] :args List of command-line arguments to use when starting Chrome
38
- # @option opts [String] :binary Path to the Chrome executable to use
39
- # @option opts [Hash] :prefs A hash with each entry consisting of the name of the preference and its value
40
- # @option opts [Array<String>] :extensions A list of paths to (.crx) Chrome extensions to install on startup
41
- # @option opts [Hash] :options A hash for raw options
42
- # @option opts [Hash] :emulation A hash for raw emulation options
43
- #
44
-
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
- @detach = opts.delete(:detach)
53
- @profile = opts.delete(:profile)
54
- @encoded_extensions = []
57
+ # @option opts [Array] encoded_extensions List of extensions that do not need to be Base64 encoded
58
+ # @option opts [Array<String>] args List of command-line arguments to use when starting Chrome
59
+ # @option opts [String] binary Path to the Chrome executable to use
60
+ # @option opts [Hash] prefs A hash with each entry consisting of the name of the preference and its value
61
+ # @option opts [Array<String>] extensions A list of paths to (.crx) Chrome extensions to install on startup
62
+ # @option opts [Hash] options A hash for raw options
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
71
+ #
72
+
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 { |ext| validate_extension(ext) }
55
91
  end
56
92
 
57
93
  #
@@ -65,10 +101,22 @@ module Selenium
65
101
  #
66
102
 
67
103
  def add_extension(path)
68
- raise Error::WebDriverError, "could not find extension at #{path.inspect}" unless File.file?(path)
69
- raise Error::WebDriverError, "file was not an extension #{path.inspect}" unless File.extname(path) == '.crx'
104
+ validate_extension(path)
105
+ end
70
106
 
71
- @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 { |ext| validate_extension(ext) }
72
120
  end
73
121
 
74
122
  #
@@ -96,22 +144,7 @@ module Selenium
96
144
  #
97
145
 
98
146
  def add_argument(arg)
99
- @args << arg
100
- end
101
-
102
- #
103
- # Add a new option not yet handled by bindings.
104
- #
105
- # @example Leave Chrome open when chromedriver is killed
106
- # options = Selenium::WebDriver::Chrome::Options.new
107
- # options.add_option(:detach, true)
108
- #
109
- # @param [String, Symbol] name Name of the option
110
- # @param [Boolean, String, Integer] value Value of the option
111
- #
112
-
113
- def add_option(name, value)
114
- @options[name] = value
147
+ @options[:args] << arg
115
148
  end
116
149
 
117
150
  #
@@ -126,7 +159,7 @@ module Selenium
126
159
  #
127
160
 
128
161
  def add_preference(name, value)
129
- prefs[name] = value
162
+ @options[:prefs][name] = value
130
163
  end
131
164
 
132
165
  #
@@ -142,7 +175,9 @@ module Selenium
142
175
  end
143
176
 
144
177
  #
145
- # Add an emulation device name
178
+ # Add emulation device information
179
+ #
180
+ # see: http://chromedriver.chromium.org/mobile-emulation
146
181
  #
147
182
  # @example Start Chrome in mobile emulation mode by device name
148
183
  # options = Selenium::WebDriver::Chrome::Options.new
@@ -152,37 +187,73 @@ module Selenium
152
187
  # options = Selenium::WebDriver::Chrome::Options.new
153
188
  # options.add_emulation(device_metrics: {width: 400, height: 800, pixelRatio: 1, touch: true})
154
189
  #
155
- # @param [String] device_name Name of the device or a hash containing width, height, pixelRatio, touch
156
- # @param [Hash] device_metrics Hash containing width, height, pixelRatio, touch
157
- # @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
158
194
  #
159
195
 
160
- def add_emulation(device_name: nil, device_metrics: nil, user_agent: nil)
161
- @emulation[:deviceName] = device_name if device_name
162
- @emulation[:deviceMetrics] = device_metrics if device_metrics
163
- @emulation[:userAgent] = user_agent if user_agent
196
+ def add_emulation(**opts)
197
+ @options[:emulation] = opts
164
198
  end
165
199
 
166
200
  #
167
- # @api private
201
+ # Enables mobile browser use on Android.
202
+ #
203
+ # @see https://chromedriver.chromium.org/getting-started/getting-started---android
168
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
169
218
 
170
- def as_json(*)
171
- extensions = @extensions.map do |crx_path|
172
- File.open(crx_path, 'rb') { |crx_file| Base64.strict_encode64 crx_file.read }
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?
227
+
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}"
173
233
  end
174
- extensions.concat(@encoded_extensions)
175
- add_argument("--user-data-dir=#{@profile[:directory]}") if @profile
176
-
177
- opts = @options
178
- opts[:binary] = @binary if @binary
179
- opts[:args] = @args.to_a if @args.any?
180
- opts[:extensions] = extensions if extensions.any?
181
- opts[:mobileEmulation] = @emulation unless @emulation.empty?
182
- opts[:prefs] = @prefs unless @prefs.empty?
183
- opts[:detach] = @detach if !@detach.nil? && @detach != false
184
-
185
- {KEY => generate_as_json(opts)}
234
+
235
+ return if (@encoded_extensions + @extensions).empty?
236
+
237
+ options['extensions'] = @encoded_extensions + @extensions.map { |ext| encode_extension(ext) }
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
254
+
255
+ def camelize?(key)
256
+ !%w[localState prefs].include?(key)
186
257
  end
187
258
  end # Options
188
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)
@@ -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