selenium-webdriver 4.0.0.alpha4 → 4.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/lib/selenium/devtools.rb +30 -0
  3. data/lib/selenium/server.rb +18 -26
  4. data/lib/selenium/webdriver.rb +1 -3
  5. data/lib/selenium/webdriver/atoms/findElements.js +93 -93
  6. data/lib/selenium/webdriver/atoms/getAttribute.js +75 -59
  7. data/lib/selenium/webdriver/atoms/isDisplayed.js +72 -72
  8. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  9. data/lib/selenium/webdriver/chrome.rb +1 -1
  10. data/lib/selenium/webdriver/chrome/driver.rb +17 -6
  11. data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +6 -8
  12. data/lib/selenium/webdriver/chrome/options.rb +54 -37
  13. data/lib/selenium/webdriver/chrome/profile.rb +1 -1
  14. data/lib/selenium/webdriver/chrome/service.rb +4 -2
  15. data/lib/selenium/webdriver/common.rb +7 -2
  16. data/lib/selenium/webdriver/common/driver.rb +86 -26
  17. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  18. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +23 -1
  19. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  20. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +149 -0
  21. data/lib/selenium/webdriver/{edge_chrome/bridge.rb → common/driver_extensions/has_logs.rb} +7 -7
  22. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  23. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +67 -0
  24. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  25. data/lib/selenium/webdriver/common/driver_extensions/prints_page.rb +32 -0
  26. data/lib/selenium/webdriver/common/element.rb +46 -12
  27. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  28. data/lib/selenium/webdriver/common/logger.rb +6 -3
  29. data/lib/selenium/webdriver/common/manager.rb +11 -1
  30. data/lib/selenium/webdriver/common/options.rb +85 -11
  31. data/lib/selenium/webdriver/common/platform.rb +3 -1
  32. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  33. data/lib/selenium/webdriver/common/proxy.rb +4 -1
  34. data/lib/selenium/webdriver/common/search_context.rb +4 -1
  35. data/lib/selenium/webdriver/common/service.rb +13 -114
  36. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  37. data/lib/selenium/webdriver/common/takes_screenshot.rb +63 -0
  38. data/lib/selenium/webdriver/common/target_locator.rb +4 -4
  39. data/lib/selenium/webdriver/devtools.rb +144 -0
  40. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  41. data/lib/selenium/webdriver/{edge_html/driver.rb → devtools/exception_event.rb} +10 -13
  42. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  43. data/lib/selenium/webdriver/devtools/request.rb +57 -0
  44. data/lib/selenium/webdriver/edge.rb +7 -29
  45. data/lib/selenium/webdriver/{edge_chrome → edge}/driver.rb +10 -4
  46. data/lib/selenium/webdriver/edge/features.rb +39 -0
  47. data/lib/selenium/webdriver/{edge_chrome → edge}/options.rb +12 -3
  48. data/lib/selenium/webdriver/{edge_chrome → edge}/profile.rb +2 -2
  49. data/lib/selenium/webdriver/{edge_chrome → edge}/service.rb +2 -2
  50. data/lib/selenium/webdriver/firefox.rb +5 -1
  51. data/lib/selenium/webdriver/firefox/driver.rb +12 -3
  52. data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +3 -3
  53. data/lib/selenium/webdriver/firefox/options.rb +25 -31
  54. data/lib/selenium/webdriver/firefox/profile.rb +12 -2
  55. data/lib/selenium/webdriver/firefox/service.rb +1 -1
  56. data/lib/selenium/webdriver/ie/driver.rb +1 -2
  57. data/lib/selenium/webdriver/ie/options.rb +7 -20
  58. data/lib/selenium/webdriver/ie/service.rb +4 -2
  59. data/lib/selenium/webdriver/remote/bridge.rb +37 -42
  60. data/lib/selenium/webdriver/remote/capabilities.rb +37 -34
  61. data/lib/selenium/webdriver/remote/commands.rb +1 -0
  62. data/lib/selenium/webdriver/remote/driver.rb +12 -3
  63. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  64. data/lib/selenium/webdriver/remote/http/default.rb +8 -7
  65. data/lib/selenium/webdriver/remote/http/persistent.rb +6 -0
  66. data/lib/selenium/webdriver/safari.rb +8 -1
  67. data/lib/selenium/webdriver/safari/driver.rb +3 -4
  68. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
  69. data/lib/selenium/webdriver/safari/options.rb +1 -33
  70. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  71. data/lib/selenium/webdriver/support/color.rb +2 -2
  72. data/lib/selenium/webdriver/support/event_firing_bridge.rb +1 -1
  73. data/lib/selenium/webdriver/support/guards.rb +95 -0
  74. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  75. data/lib/selenium/webdriver/support/guards/guard_condition.rb +52 -0
  76. data/lib/selenium/webdriver/support/select.rb +2 -2
  77. data/lib/selenium/webdriver/version.rb +1 -1
  78. metadata +69 -32
  79. data/CHANGES +0 -1719
  80. data/Gemfile +0 -4
  81. data/LICENSE +0 -202
  82. data/README.md +0 -35
  83. data/lib/selenium/webdriver/common/driver_extensions/rotatable.rb +0 -61
  84. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -65
  85. data/lib/selenium/webdriver/edge_html/options.rb +0 -91
  86. data/lib/selenium/webdriver/edge_html/service.rb +0 -47
  87. data/selenium-webdriver.gemspec +0 -48
@@ -21,13 +21,13 @@ require 'selenium/webdriver/chrome/profile'
21
21
 
22
22
  module Selenium
23
23
  module WebDriver
24
- module EdgeChrome
24
+ module Edge
25
25
  #
26
26
  # @private
27
27
  #
28
28
 
29
29
  class Profile < Selenium::WebDriver::Chrome::Profile
30
30
  end # Profile
31
- end # EdgeChrome
31
+ end # Edge
32
32
  end # WebDriver
33
33
  end # Selenium
@@ -21,7 +21,7 @@ require 'selenium/webdriver/chrome/service'
21
21
 
22
22
  module Selenium
23
23
  module WebDriver
24
- module EdgeChrome
24
+ module Edge
25
25
  class Service < Selenium::WebDriver::Chrome::Service
26
26
  DEFAULT_PORT = 9515
27
27
  EXECUTABLE = 'msedgedriver'
@@ -31,6 +31,6 @@ module Selenium
31
31
  ERROR
32
32
  SHUTDOWN_SUPPORTED = true
33
33
  end # Service
34
- end # EdgeChrome
34
+ end # Edge
35
35
  end # WebDriver
36
36
  end # Selenium
@@ -27,7 +27,7 @@ module Selenium
27
27
  autoload :Extension, 'selenium/webdriver/firefox/extension'
28
28
  autoload :ProfilesIni, 'selenium/webdriver/firefox/profiles_ini'
29
29
  autoload :Profile, 'selenium/webdriver/firefox/profile'
30
- autoload :Bridge, 'selenium/webdriver/firefox/bridge'
30
+ autoload :Features, 'selenium/webdriver/firefox/features'
31
31
  autoload :Driver, 'selenium/webdriver/firefox/driver'
32
32
  autoload :Options, 'selenium/webdriver/firefox/options'
33
33
  autoload :Service, 'selenium/webdriver/firefox/service'
@@ -38,6 +38,10 @@ module Selenium
38
38
  DEFAULT_ASSUME_UNTRUSTED_ISSUER = true
39
39
  DEFAULT_LOAD_NO_FOCUS_LIB = false
40
40
 
41
+ # Mozilla Automation Team asked to only support 85
42
+ # until WebDriver Bidi is available.
43
+ DEVTOOLS_VERSION = 85
44
+
41
45
  def self.driver_path=(path)
42
46
  WebDriver.logger.deprecate 'Selenium::WebDriver::Firefox#driver_path=',
43
47
  'Selenium::WebDriver::Firefox::Service#driver_path=',
@@ -27,13 +27,22 @@ module Selenium
27
27
  #
28
28
 
29
29
  class Driver < WebDriver::Driver
30
- include DriverExtensions::HasAddons
31
- include DriverExtensions::HasWebStorage
32
- include DriverExtensions::TakesScreenshot
30
+ EXTENSIONS = [DriverExtensions::HasAddons,
31
+ DriverExtensions::HasDevTools,
32
+ DriverExtensions::HasLogEvents,
33
+ DriverExtensions::HasNetworkInterception,
34
+ DriverExtensions::HasWebStorage,
35
+ DriverExtensions::PrintsPage].freeze
33
36
 
34
37
  def browser
35
38
  :firefox
36
39
  end
40
+
41
+ private
42
+
43
+ def devtools_address
44
+ "http://#{capabilities['moz:debuggerAddress']}"
45
+ end
37
46
  end # Driver
38
47
  end # Firefox
39
48
  end # WebDriver
@@ -20,15 +20,15 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Firefox
23
- module Bridge
23
+ module Features
24
24
 
25
- COMMANDS = {
25
+ FIREFOX_COMMANDS = {
26
26
  install_addon: [:post, 'session/:session_id/moz/addon/install'],
27
27
  uninstall_addon: [:post, 'session/:session_id/moz/addon/uninstall']
28
28
  }.freeze
29
29
 
30
30
  def commands(command)
31
- COMMANDS[command] || super
31
+ FIREFOX_COMMANDS[command] || self.class::COMMANDS[command]
32
32
  end
33
33
 
34
34
  def install_addon(path, temporary)
@@ -21,24 +21,19 @@ module Selenium
21
21
  module WebDriver
22
22
  module Firefox
23
23
  class Options < WebDriver::Options
24
+ attr_accessor :debugger_address
25
+
24
26
  KEY = 'moz:firefoxOptions'
25
27
 
26
28
  # see: https://firefox-source-docs.mozilla.org/testing/geckodriver/Capabilities.html
27
29
  CAPABILITIES = {binary: 'binary',
28
30
  args: 'args',
29
- profile: 'profile',
30
31
  log: 'log',
31
32
  prefs: 'prefs'}.freeze
33
+ BROWSER = 'firefox'
32
34
 
33
- CAPABILITIES.each_key do |key|
34
- define_method key do
35
- @options[key]
36
- end
37
-
38
- define_method "#{key}=" do |value|
39
- @options[key] = value
40
- end
41
- end
35
+ # NOTE: special handling of 'profile' to validate when set instead of when used
36
+ attr_reader :profile
42
37
 
43
38
  #
44
39
  # Create a new Options instance, only for W3C-capable versions of Firefox.
@@ -57,10 +52,15 @@ module Selenium
57
52
  #
58
53
 
59
54
  def initialize(log_level: nil, **opts)
60
- super(opts)
55
+ @debugger_address = opts.delete(:debugger_address)
56
+
57
+ super(**opts)
61
58
 
59
+ @options[:args] ||= []
60
+ @options[:prefs] ||= {}
62
61
  @options[:log] ||= {level: log_level} if log_level
63
- process_profile(@options[:profile]) if @options.key?(:profile)
62
+
63
+ process_profile(@options.delete(:profile))
64
64
  end
65
65
 
66
66
  #
@@ -74,7 +74,6 @@ module Selenium
74
74
  #
75
75
 
76
76
  def add_argument(arg)
77
- @options[:args] ||= []
78
77
  @options[:args] << arg
79
78
  end
80
79
 
@@ -90,7 +89,6 @@ module Selenium
90
89
  #
91
90
 
92
91
  def add_preference(name, value)
93
- @options[:prefs] ||= {}
94
92
  @options[:prefs][name] = value
95
93
  end
96
94
 
@@ -121,7 +119,6 @@ module Selenium
121
119
  # @param [Profile, String] profile Profile to be used
122
120
  #
123
121
 
124
- undef profile=
125
122
  def profile=(profile)
126
123
  process_profile(profile)
127
124
  end
@@ -134,27 +131,24 @@ module Selenium
134
131
  @options[:log] = {level: level}
135
132
  end
136
133
 
137
- #
138
- # @api private
139
- #
134
+ private
140
135
 
141
- def as_json(*)
142
- options = super
136
+ def process_browser_options(browser_options)
137
+ browser_options['moz:debuggerAddress'] = true if @debugger_address
138
+ options = browser_options[KEY]
143
139
  options['binary'] ||= Firefox.path if Firefox.path
144
-
145
- {KEY => generate_as_json(options)}
140
+ options['profile'] = @profile if @profile
146
141
  end
147
142
 
148
- private
149
-
150
143
  def process_profile(profile)
151
- @options[:profile] = if profile.nil?
152
- nil
153
- elsif profile.is_a? Profile
154
- profile
155
- else
156
- Profile.from_name(profile)
157
- end
144
+ @profile = case profile
145
+ when nil
146
+ nil
147
+ when Profile
148
+ profile
149
+ else
150
+ Profile.from_name(profile)
151
+ end
158
152
  end
159
153
  end # Options
160
154
  end # Firefox
@@ -25,6 +25,14 @@ module Selenium
25
25
 
26
26
  VALID_PREFERENCE_TYPES = [TrueClass, FalseClass, Integer, Float, String].freeze
27
27
 
28
+ DEFAULT_PREFERENCES = {
29
+ "browser.newtabpage.enabled" => false,
30
+ "browser.startup.homepage" => "about:blank",
31
+ "browser.usedOnWindows10.introURL" => "about:blank",
32
+ "network.captive-portal-service.enabled" => false,
33
+ "security.csp.enable" => false
34
+ }.freeze
35
+
28
36
  attr_reader :name, :log_file
29
37
  attr_writer :secure_ssl, :load_no_focus_lib
30
38
 
@@ -179,10 +187,12 @@ module Selenium
179
187
 
180
188
  def update_user_prefs_in(directory)
181
189
  path = File.join(directory, 'user.js')
182
- prefs = read_user_prefs(path).merge(@additional_prefs)
190
+ prefs = read_user_prefs(path)
191
+ prefs.merge! self.class::DEFAULT_PREFERENCES
192
+ prefs.merge!(@additional_prefs)
183
193
 
184
194
  # If the user sets the home page, we should also start up there
185
- prefs['startup.homepage_welcome_url'] = prefs['browser.startup.homepage']
195
+ prefs['startup.homepage_welcome_url'] ||= prefs['browser.startup.homepage']
186
196
 
187
197
  write_prefs prefs, path
188
198
  end
@@ -32,7 +32,7 @@ module Selenium
32
32
 
33
33
  private
34
34
 
35
- # Note: This processing is deprecated
35
+ # NOTE: This processing is deprecated
36
36
  def extract_service_args(driver_opts)
37
37
  driver_args = super
38
38
  driver_opts = driver_opts.dup
@@ -28,8 +28,7 @@ module Selenium
28
28
  #
29
29
 
30
30
  class Driver < WebDriver::Driver
31
- include DriverExtensions::HasWebStorage
32
- include DriverExtensions::TakesScreenshot
31
+ EXTENSIONS = [DriverExtensions::HasWebStorage].freeze
33
32
 
34
33
  def browser
35
34
  :internet_explorer
@@ -41,16 +41,7 @@ module Selenium
41
41
  use_per_process_proxy: 'ie.usePerProcessProxy',
42
42
  validate_cookie_document_type: 'ie.validateCookieDocumentType'
43
43
  }.freeze
44
-
45
- CAPABILITIES.each_key do |key|
46
- define_method key do
47
- @options[key]
48
- end
49
-
50
- define_method "#{key}=" do |value|
51
- @options[key] = value
52
- end
53
- end
44
+ BROWSER = 'internet explorer'
54
45
 
55
46
  attr_reader :args
56
47
 
@@ -85,10 +76,10 @@ module Selenium
85
76
  # @option opts [Boolean] validate_cookie_document_type
86
77
  #
87
78
 
88
- def initialize(args: nil, **opts)
89
- super(opts)
79
+ def initialize(**opts)
80
+ @args = (opts.delete(:args) || []).to_set
81
+ super(**opts)
90
82
 
91
- @args = (args || []).to_set
92
83
  @options[:native_events] = true if @options[:native_events].nil?
93
84
  end
94
85
 
@@ -102,15 +93,11 @@ module Selenium
102
93
  @args << arg
103
94
  end
104
95
 
105
- #
106
- # @api private
107
- #
96
+ private
108
97
 
109
- def as_json(*)
110
- options = super
98
+ def process_browser_options(browser_options)
99
+ options = browser_options[KEY]
111
100
  options['ie.browserCommandLineSwitches'] = @args.to_a.join(' ') if @args.any?
112
-
113
- {KEY => generate_as_json(options)}
114
101
  end
115
102
  end # Options
116
103
  end # IE
@@ -32,13 +32,15 @@ module Selenium
32
32
 
33
33
  private
34
34
 
35
- # Note: This processing is deprecated
35
+ # NOTE: This processing is deprecated
36
36
  def extract_service_args(driver_opts)
37
37
  driver_args = super
38
38
  driver_opts = driver_opts.dup
39
39
  driver_args << "--log-level=#{driver_opts[:log_level].to_s.upcase}" if driver_opts.key?(:log_level)
40
40
  driver_args << "--log-file=#{driver_opts[:log_file]}" if driver_opts.key?(:log_file)
41
- driver_args << "--implementation=#{driver_opts[:implementation].to_s.upcase}" if driver_opts.key?(:implementation)
41
+ if driver_opts.key?(:implementation)
42
+ driver_args << "--implementation=#{driver_opts[:implementation].to_s.upcase}"
43
+ end
42
44
  driver_args << "--host=#{driver_opts[:host]}" if driver_opts.key?(:host)
43
45
  driver_args << "--extract_path=#{driver_opts[:extract_path]}" if driver_opts.key?(:extract_path)
44
46
  driver_args << "--silent" if driver_opts[:silent] == true
@@ -35,9 +35,9 @@ module Selenium
35
35
  # @api private
36
36
  #
37
37
 
38
- def initialize(http_client: nil, url:)
38
+ def initialize(url:, http_client: nil)
39
39
  uri = url.is_a?(URI) ? url : URI.parse(url)
40
- uri.path += '/' unless %r{\/$}.match?(uri.path)
40
+ uri.path += '/' unless uri.path.end_with?('/')
41
41
 
42
42
  @http = http_client || Http::Default.new
43
43
  @http.server_url = uri
@@ -48,8 +48,8 @@ module Selenium
48
48
  # Creates session.
49
49
  #
50
50
 
51
- def create_session(desired_capabilities, options = nil)
52
- response = execute(:new_session, {}, merged_capabilities(desired_capabilities, options))
51
+ def create_session(capabilities)
52
+ response = execute(:new_session, {}, {capabilities: {firstMatch: [capabilities]}})
53
53
 
54
54
  @session_id = response['sessionId']
55
55
  capabilities = response['capabilities']
@@ -57,6 +57,17 @@ module Selenium
57
57
  raise Error::WebDriverError, 'no sessionId in returned payload' unless @session_id
58
58
 
59
59
  @capabilities = Capabilities.json_create(capabilities)
60
+
61
+ case @capabilities[:browser_name]
62
+ when 'chrome'
63
+ extend(WebDriver::Chrome::Features)
64
+ when 'firefox'
65
+ extend(WebDriver::Firefox::Features)
66
+ when 'msedge'
67
+ extend(WebDriver::Edge::Features)
68
+ when 'Safari', 'Safari Technology Preview'
69
+ extend(WebDriver::Safari::Features)
70
+ end
60
71
  end
61
72
 
62
73
  #
@@ -70,7 +81,7 @@ module Selenium
70
81
  def browser
71
82
  @browser ||= begin
72
83
  name = @capabilities.browser_name
73
- name ? name.tr(' ', '_').to_sym : 'unknown'
84
+ name ? name.tr(' ', '_').downcase.to_sym : 'unknown'
74
85
  end
75
86
  end
76
87
 
@@ -207,7 +218,10 @@ module Selenium
207
218
  end
208
219
 
209
220
  def window_size(handle = :current)
210
- raise Error::UnsupportedOperationError, 'Switch to desired window before getting its size' unless handle == :current
221
+ unless handle == :current
222
+ raise Error::UnsupportedOperationError,
223
+ 'Switch to desired window before getting its size'
224
+ end
211
225
 
212
226
  data = execute :get_window_rect
213
227
  Dimension.new data['width'], data['height']
@@ -218,7 +232,10 @@ module Selenium
218
232
  end
219
233
 
220
234
  def maximize_window(handle = :current)
221
- raise Error::UnsupportedOperationError, 'Switch to desired window before changing its size' unless handle == :current
235
+ unless handle == :current
236
+ raise Error::UnsupportedOperationError,
237
+ 'Switch to desired window before changing its size'
238
+ end
222
239
 
223
240
  execute :maximize_window
224
241
  end
@@ -251,6 +268,10 @@ module Selenium
251
268
  execute :take_screenshot
252
269
  end
253
270
 
271
+ def element_screenshot(element)
272
+ execute :take_element_screenshot, id: element.ref
273
+ end
274
+
254
275
  #
255
276
  # HTML 5
256
277
  #
@@ -303,22 +324,6 @@ module Selenium
303
324
  execute_script('return sessionStorage.length')
304
325
  end
305
326
 
306
- def location
307
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting location'
308
- end
309
-
310
- def set_location(_lat, _lon, _alt)
311
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting location'
312
- end
313
-
314
- def network_connection
315
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting network connection'
316
- end
317
-
318
- def network_connection=(_type)
319
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting network connection'
320
- end
321
-
322
327
  #
323
328
  # javascript execution
324
329
  #
@@ -389,6 +394,10 @@ module Selenium
389
394
  execute :release_actions
390
395
  end
391
396
 
397
+ def print_page(options = {})
398
+ execute :print_page, {}, {options: options}
399
+ end
400
+
392
401
  def click_element(element)
393
402
  execute :element_click, id: element
394
403
  end
@@ -428,14 +437,6 @@ module Selenium
428
437
  'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }', form.as_json)
429
438
  end
430
439
 
431
- def screen_orientation=(orientation)
432
- execute :set_screen_orientation, {}, {orientation: orientation}
433
- end
434
-
435
- def screen_orientation
436
- execute :get_screen_orientation
437
- end
438
-
439
440
  #
440
441
  # element properties
441
442
  #
@@ -449,6 +450,10 @@ module Selenium
449
450
  execute_atom :getAttribute, element, name
450
451
  end
451
452
 
453
+ def element_dom_attribute(element, name)
454
+ execute :get_element_attribute, id: element.ref, name: name
455
+ end
456
+
452
457
  def element_property(element, name)
453
458
  execute :get_element_property, id: element.ref, name: name
454
459
  end
@@ -571,16 +576,6 @@ module Selenium
571
576
  COMMANDS[command]
572
577
  end
573
578
 
574
- def merged_capabilities(capabilities, options = nil)
575
- capabilities.merge!(options.as_json) if options
576
-
577
- {
578
- capabilities: {
579
- firstMatch: [capabilities]
580
- }
581
- }
582
- end
583
-
584
579
  def unwrap_script_result(arg)
585
580
  case arg
586
581
  when Array
@@ -626,7 +621,7 @@ module Selenium
626
621
  [how, what]
627
622
  end
628
623
 
629
- ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]\(\)])/.freeze
624
+ ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/.freeze
630
625
  UNICODE_CODE_POINT = 30
631
626
 
632
627
  # Escapes invalid characters in CSS selector.