selenium-webdriver 4.17.0 → 4.26.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +92 -0
  3. data/Gemfile +1 -0
  4. data/README.md +2 -2
  5. data/bin/linux/selenium-manager +0 -0
  6. data/bin/macos/selenium-manager +0 -0
  7. data/bin/windows/selenium-manager.exe +0 -0
  8. data/lib/selenium/server.rb +2 -1
  9. data/lib/selenium/webdriver/atoms/findElements.js +26 -26
  10. data/lib/selenium/webdriver/atoms/getAttribute.js +2 -2
  11. data/lib/selenium/webdriver/atoms/isDisplayed.js +24 -97
  12. data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +1 -1
  13. data/lib/selenium/webdriver/bidi/log_handler.rb +63 -0
  14. data/lib/selenium/webdriver/bidi/log_inspector.rb +5 -1
  15. data/lib/selenium/webdriver/bidi/session.rb +7 -7
  16. data/lib/selenium/webdriver/bidi/struct.rb +44 -0
  17. data/lib/selenium/webdriver/bidi.rb +10 -0
  18. data/lib/selenium/webdriver/chrome/service.rb +1 -0
  19. data/lib/selenium/webdriver/chromium/driver.rb +1 -0
  20. data/lib/selenium/webdriver/common/child_process.rb +8 -2
  21. data/lib/selenium/webdriver/common/driver.rb +21 -15
  22. data/lib/selenium/webdriver/common/driver_extensions/has_bidi.rb +1 -1
  23. data/lib/selenium/webdriver/common/driver_extensions/has_fedcm_dialog.rb +55 -0
  24. data/lib/selenium/webdriver/common/driver_finder.rb +66 -14
  25. data/lib/selenium/webdriver/common/error.rb +21 -21
  26. data/lib/selenium/webdriver/common/fedcm/account.rb +50 -0
  27. data/lib/selenium/webdriver/common/fedcm/dialog.rb +74 -0
  28. data/lib/selenium/webdriver/common/fedcm.rb +27 -0
  29. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +1 -1
  30. data/lib/selenium/webdriver/common/interactions/wheel_input.rb +1 -1
  31. data/lib/selenium/webdriver/common/local_driver.rb +8 -1
  32. data/lib/selenium/webdriver/common/logger.rb +2 -2
  33. data/lib/selenium/webdriver/common/manager.rb +1 -1
  34. data/lib/selenium/webdriver/common/options.rb +1 -1
  35. data/lib/selenium/webdriver/common/platform.rb +3 -1
  36. data/lib/selenium/webdriver/common/script.rb +45 -0
  37. data/lib/selenium/webdriver/common/search_context.rb +10 -2
  38. data/lib/selenium/webdriver/common/selenium_manager.rb +36 -73
  39. data/lib/selenium/webdriver/common/service.rb +11 -4
  40. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  41. data/lib/selenium/webdriver/common/target_locator.rb +1 -2
  42. data/lib/selenium/webdriver/common/wait.rb +1 -1
  43. data/lib/selenium/webdriver/common/websocket_connection.rb +12 -0
  44. data/lib/selenium/webdriver/common.rb +4 -0
  45. data/lib/selenium/webdriver/devtools/network_interceptor.rb +1 -1
  46. data/lib/selenium/webdriver/edge/service.rb +1 -1
  47. data/lib/selenium/webdriver/firefox/options.rb +3 -0
  48. data/lib/selenium/webdriver/firefox/profile.rb +11 -5
  49. data/lib/selenium/webdriver/firefox/profiles_ini.rb +1 -1
  50. data/lib/selenium/webdriver/firefox/service.rb +1 -0
  51. data/lib/selenium/webdriver/ie/options.rb +3 -2
  52. data/lib/selenium/webdriver/ie/service.rb +1 -0
  53. data/lib/selenium/webdriver/remote/bidi_bridge.rb +44 -0
  54. data/lib/selenium/webdriver/remote/bridge/commands.rb +13 -1
  55. data/lib/selenium/webdriver/remote/bridge/locator_converter.rb +76 -0
  56. data/lib/selenium/webdriver/remote/bridge.rb +87 -46
  57. data/lib/selenium/webdriver/remote/capabilities.rb +1 -1
  58. data/lib/selenium/webdriver/remote/http/common.rb +21 -3
  59. data/lib/selenium/webdriver/remote/http/curb.rb +11 -5
  60. data/lib/selenium/webdriver/remote/response.rb +12 -19
  61. data/lib/selenium/webdriver/remote/server_error.rb +1 -1
  62. data/lib/selenium/webdriver/remote.rb +2 -1
  63. data/lib/selenium/webdriver/safari/service.rb +1 -1
  64. data/lib/selenium/webdriver/support/guards/guard.rb +8 -9
  65. data/lib/selenium/webdriver/version.rb +1 -1
  66. data/lib/selenium/webdriver.rb +1 -1
  67. data/selenium-webdriver.gemspec +9 -6
  68. metadata +70 -7
@@ -22,6 +22,8 @@ module Selenium
22
22
  module Remote
23
23
  class Bridge
24
24
  autoload :COMMANDS, 'selenium/webdriver/remote/bridge/commands'
25
+ autoload :LocatorConverter, 'selenium/webdriver/remote/bridge/locator_converter'
26
+
25
27
  include Atoms
26
28
 
27
29
  PORT = 4444
@@ -29,6 +31,25 @@ module Selenium
29
31
  attr_accessor :http, :file_detector
30
32
  attr_reader :capabilities
31
33
 
34
+ class << self
35
+ attr_reader :extra_commands
36
+ attr_writer :element_class, :locator_converter
37
+
38
+ def add_command(name, verb, url, &block)
39
+ @extra_commands ||= {}
40
+ @extra_commands[name] = [verb, url]
41
+ define_method(name, &block)
42
+ end
43
+
44
+ def locator_converter
45
+ @locator_converter ||= LocatorConverter.new
46
+ end
47
+
48
+ def element_class
49
+ @element_class ||= Element
50
+ end
51
+ end
52
+
32
53
  #
33
54
  # Initializes the bridge with the given server URL
34
55
  # @param [String, URI] url url for the remote server
@@ -43,6 +64,8 @@ module Selenium
43
64
  @http = http_client || Http::Default.new
44
65
  @http.server_url = uri
45
66
  @file_detector = nil
67
+
68
+ @locator_converter = self.class.locator_converter
46
69
  end
47
70
 
48
71
  #
@@ -278,6 +301,7 @@ module Selenium
278
301
  #
279
302
 
280
303
  def local_storage_item(key, value = nil)
304
+ WebDriver.logger.deprecate('local_storage_item(key, value)', id: :local_storage_item)
281
305
  if value
282
306
  execute_script("localStorage.setItem('#{key}', '#{value}')")
283
307
  else
@@ -286,22 +310,27 @@ module Selenium
286
310
  end
287
311
 
288
312
  def remove_local_storage_item(key)
313
+ WebDriver.logger.deprecate('remove_local_storage_item(key)', id: :remove_local_storage_item)
289
314
  execute_script("localStorage.removeItem('#{key}')")
290
315
  end
291
316
 
292
317
  def local_storage_keys
318
+ WebDriver.logger.deprecate('local_storage_keys', id: :local_storage_keys)
293
319
  execute_script('return Object.keys(localStorage)')
294
320
  end
295
321
 
296
322
  def clear_local_storage
323
+ WebDriver.logger.deprecate('clear_local_storage', id: :clear_local_storage)
297
324
  execute_script('localStorage.clear()')
298
325
  end
299
326
 
300
327
  def local_storage_size
328
+ WebDriver.logger.deprecate('local_storage_size', id: :local_storage_size)
301
329
  execute_script('return localStorage.length')
302
330
  end
303
331
 
304
332
  def session_storage_item(key, value = nil)
333
+ WebDriver.logger.deprecate('session_storage_item(key, value)', id: :session_storage_item)
305
334
  if value
306
335
  execute_script("sessionStorage.setItem('#{key}', '#{value}')")
307
336
  else
@@ -310,18 +339,22 @@ module Selenium
310
339
  end
311
340
 
312
341
  def remove_session_storage_item(key)
342
+ WebDriver.logger.deprecate('remove_session_storage_item(key)', id: :remove_session_storage_item)
313
343
  execute_script("sessionStorage.removeItem('#{key}')")
314
344
  end
315
345
 
316
346
  def session_storage_keys
347
+ WebDriver.logger.deprecate('session_storage_keys', id: :session_storage_keys)
317
348
  execute_script('return Object.keys(sessionStorage)')
318
349
  end
319
350
 
320
351
  def clear_session_storage
352
+ WebDriver.logger.deprecate('clear_session_storage', id: :clear_session_storage)
321
353
  execute_script('sessionStorage.clear()')
322
354
  end
323
355
 
324
356
  def session_storage_size
357
+ WebDriver.logger.deprecate('session_storage_size', id: :session_storage_size)
325
358
  execute_script('return sessionStorage.length')
326
359
  end
327
360
 
@@ -413,7 +446,7 @@ module Selenium
413
446
  "e.initEvent('submit', true, true);\n" \
414
447
  "if (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n"
415
448
 
416
- execute_script(script, Element::ELEMENT_KEY => element)
449
+ execute_script(script, Bridge.element_class::ELEMENT_KEY => element)
417
450
  rescue Error::JavascriptError
418
451
  raise Error::UnsupportedOperationError, 'To submit an element, it must be nested inside a form element'
419
452
  end
@@ -500,13 +533,13 @@ module Selenium
500
533
  #
501
534
 
502
535
  def active_element
503
- Element.new self, element_id_from(execute(:get_active_element))
536
+ Bridge.element_class.new self, element_id_from(execute(:get_active_element))
504
537
  end
505
538
 
506
539
  alias switch_to_active_element active_element
507
540
 
508
541
  def find_element_by(how, what, parent_ref = [])
509
- how, what = convert_locator(how, what)
542
+ how, what = @locator_converter.convert(how, what)
510
543
 
511
544
  return execute_atom(:findElements, Support::RelativeLocator.new(what).as_json).first if how == 'relative'
512
545
 
@@ -520,11 +553,11 @@ module Selenium
520
553
  execute :find_element, {}, {using: how, value: what.to_s}
521
554
  end
522
555
 
523
- Element.new self, element_id_from(id)
556
+ Bridge.element_class.new self, element_id_from(id)
524
557
  end
525
558
 
526
559
  def find_elements_by(how, what, parent_ref = [])
527
- how, what = convert_locator(how, what)
560
+ how, what = @locator_converter.convert(how, what)
528
561
 
529
562
  return execute_atom :findElements, Support::RelativeLocator.new(what).as_json if how == 'relative'
530
563
 
@@ -538,7 +571,7 @@ module Selenium
538
571
  execute :find_elements, {}, {using: how, value: what.to_s}
539
572
  end
540
573
 
541
- ids.map { |id| Element.new self, element_id_from(id) }
574
+ ids.map { |id| Bridge.element_class.new self, element_id_from(id) }
542
575
  end
543
576
 
544
577
  def shadow_root(element)
@@ -579,6 +612,51 @@ module Selenium
579
612
  execute :set_user_verified, {authenticatorId: authenticator_id}, {isUserVerified: verified}
580
613
  end
581
614
 
615
+ #
616
+ # federated-credential management
617
+ #
618
+
619
+ def cancel_fedcm_dialog
620
+ execute :cancel_fedcm_dialog
621
+ end
622
+
623
+ def select_fedcm_account(index)
624
+ execute :select_fedcm_account, {}, {accountIndex: index}
625
+ end
626
+
627
+ def fedcm_dialog_type
628
+ execute :get_fedcm_dialog_type
629
+ end
630
+
631
+ def fedcm_title
632
+ execute(:get_fedcm_title).fetch('title')
633
+ end
634
+
635
+ def fedcm_subtitle
636
+ execute(:get_fedcm_title).fetch('subtitle', nil)
637
+ end
638
+
639
+ def fedcm_account_list
640
+ execute :get_fedcm_account_list
641
+ end
642
+
643
+ def fedcm_delay(enabled)
644
+ execute :set_fedcm_delay, {}, {enabled: enabled}
645
+ end
646
+
647
+ def reset_fedcm_cooldown
648
+ execute :reset_fedcm_cooldown
649
+ end
650
+
651
+ def click_fedcm_dialog_button
652
+ execute :click_fedcm_dialog_button, {}, {dialogButton: 'ConfirmIdpLoginContinue'}
653
+ end
654
+
655
+ def bidi
656
+ msg = 'BiDi must be enabled by setting #web_socket_url to true in options class'
657
+ raise(WebDriver::Error::WebDriverError, msg)
658
+ end
659
+
582
660
  def command_list
583
661
  COMMANDS
584
662
  end
@@ -612,7 +690,7 @@ module Selenium
612
690
  end
613
691
 
614
692
  def commands(command)
615
- command_list[command]
693
+ command_list[command] || Bridge.extra_commands[command]
616
694
  end
617
695
 
618
696
  def unwrap_script_result(arg)
@@ -621,7 +699,7 @@ module Selenium
621
699
  arg.map { |e| unwrap_script_result(e) }
622
700
  when Hash
623
701
  element_id = element_id_from(arg)
624
- return Element.new(self, element_id) if element_id
702
+ return Bridge.element_class.new(self, element_id) if element_id
625
703
 
626
704
  shadow_root_id = shadow_root_id_from(arg)
627
705
  return ShadowRoot.new self, shadow_root_id if shadow_root_id
@@ -633,7 +711,7 @@ module Selenium
633
711
  end
634
712
 
635
713
  def element_id_from(id)
636
- id['ELEMENT'] || id[Element::ELEMENT_KEY]
714
+ id['ELEMENT'] || id[Bridge.element_class::ELEMENT_KEY]
637
715
  end
638
716
 
639
717
  def shadow_root_id_from(id)
@@ -644,43 +722,6 @@ module Selenium
644
722
  capabilities = {alwaysMatch: capabilities} if !capabilities['alwaysMatch'] && !capabilities['firstMatch']
645
723
  {capabilities: capabilities}
646
724
  end
647
-
648
- def convert_locator(how, what)
649
- how = SearchContext::FINDERS[how.to_sym] || how
650
-
651
- case how
652
- when 'class name'
653
- how = 'css selector'
654
- what = ".#{escape_css(what.to_s)}"
655
- when 'id'
656
- how = 'css selector'
657
- what = "##{escape_css(what.to_s)}"
658
- when 'name'
659
- how = 'css selector'
660
- what = "*[name='#{escape_css(what.to_s)}']"
661
- end
662
-
663
- if what.is_a?(Hash)
664
- what = what.each_with_object({}) do |(h, w), hash|
665
- h, w = convert_locator(h.to_s, w)
666
- hash[h] = w
667
- end
668
- end
669
-
670
- [how, what]
671
- end
672
-
673
- ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/
674
- UNICODE_CODE_POINT = 30
675
-
676
- # Escapes invalid characters in CSS selector.
677
- # @see https://mathiasbynens.be/notes/css-escapes
678
- def escape_css(string)
679
- string = string.gsub(ESCAPE_CSS_REGEXP) { |match| "\\#{match}" }
680
- string = "\\#{UNICODE_CODE_POINT + Integer(string[0])} #{string[1..]}" if string[0]&.match?(/[[:digit:]]/)
681
-
682
- string
683
- end
684
725
  end # Bridge
685
726
  end # Remote
686
727
  end # WebDriver
@@ -99,7 +99,7 @@ module Selenium
99
99
  end
100
100
 
101
101
  def camel_case(str_or_sym)
102
- str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
102
+ str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1)&.upcase }
103
103
  end
104
104
 
105
105
  private
@@ -26,10 +26,18 @@ module Selenium
26
26
  CONTENT_TYPE = 'application/json'
27
27
  DEFAULT_HEADERS = {
28
28
  'Accept' => CONTENT_TYPE,
29
- 'Content-Type' => "#{CONTENT_TYPE}; charset=UTF-8",
30
- 'User-Agent' => "selenium/#{WebDriver::VERSION} (ruby #{Platform.os})"
29
+ 'Content-Type' => "#{CONTENT_TYPE}; charset=UTF-8"
31
30
  }.freeze
32
31
 
32
+ class << self
33
+ attr_accessor :extra_headers
34
+ attr_writer :user_agent
35
+
36
+ def user_agent
37
+ @user_agent ||= "selenium/#{WebDriver::VERSION} (ruby #{Platform.os})"
38
+ end
39
+ end
40
+
33
41
  attr_writer :server_url
34
42
 
35
43
  def quit_errors
@@ -42,7 +50,7 @@ module Selenium
42
50
 
43
51
  def call(verb, url, command_hash)
44
52
  url = server_url.merge(url) unless url.is_a?(URI)
45
- headers = DEFAULT_HEADERS.dup
53
+ headers = common_headers.dup
46
54
  headers['Cache-Control'] = 'no-cache' if verb == :get
47
55
 
48
56
  if command_hash
@@ -61,6 +69,16 @@ module Selenium
61
69
 
62
70
  private
63
71
 
72
+ def common_headers
73
+ @common_headers ||= begin
74
+ headers = DEFAULT_HEADERS.dup
75
+ headers['User-Agent'] = Common.user_agent
76
+ headers = headers.merge(Common.extra_headers || {})
77
+
78
+ headers
79
+ end
80
+ end
81
+
64
82
  def server_url
65
83
  return @server_url if @server_url
66
84
 
@@ -37,6 +37,13 @@ module Selenium
37
37
  #
38
38
 
39
39
  class Curb < Common
40
+ attr_accessor :timeout
41
+
42
+ def initialize(timeout: nil)
43
+ @timeout = timeout
44
+ super()
45
+ end
46
+
40
47
  def quit_errors
41
48
  [Curl::Err::RecvError] + super
42
49
  end
@@ -53,7 +60,7 @@ module Selenium
53
60
  client.headers = headers
54
61
 
55
62
  # http://github.com/taf2/curb/issues/issue/33
56
- client.head = false
63
+ client.head = false
57
64
  client.delete = false
58
65
 
59
66
  case verb
@@ -80,11 +87,10 @@ module Selenium
80
87
  @client ||= begin
81
88
  c = Curl::Easy.new
82
89
 
83
- c.max_redirects = MAX_REDIRECTS
90
+ c.max_redirects = MAX_REDIRECTS
84
91
  c.follow_location = true
85
- c.timeout = @timeout if @timeout
86
- c.verbose = WebDriver.logger.debug?
87
-
92
+ c.timeout = timeout if timeout
93
+ c.verbose = WebDriver.logger.debug?
88
94
  c
89
95
  end
90
96
  end
@@ -28,7 +28,7 @@ module Selenium
28
28
  attr_reader :code, :payload
29
29
 
30
30
  def initialize(code, payload = nil)
31
- @code = code
31
+ @code = code
32
32
  @payload = payload || {}
33
33
 
34
34
  assert_ok
@@ -37,11 +37,8 @@ module Selenium
37
37
  def error
38
38
  error, message, backtrace = process_error
39
39
  klass = Error.for_error(error) || return
40
-
41
40
  ex = klass.new(message)
42
- ex.set_backtrace(caller)
43
- add_backtrace ex, backtrace
44
-
41
+ add_cause(ex, error, backtrace)
45
42
  ex
46
43
  end
47
44
 
@@ -59,17 +56,13 @@ module Selenium
59
56
  raise Error::ServerError, self
60
57
  end
61
58
 
62
- def add_backtrace(ex, server_trace)
63
- return unless server_trace
64
-
65
- backtrace = case server_trace
66
- when Array
67
- backtrace_from_remote(server_trace)
68
- when String
69
- server_trace.split("\n")
70
- end
71
-
72
- ex.set_backtrace(backtrace + ex.backtrace)
59
+ def add_cause(ex, error, backtrace)
60
+ cause = Error::WebDriverError.new
61
+ backtrace = backtrace_from_remote(backtrace) if backtrace.is_a?(Array)
62
+ cause.set_backtrace(backtrace)
63
+ raise ex, cause: cause
64
+ rescue Error.for_error(error)
65
+ ex
73
66
  end
74
67
 
75
68
  def backtrace_from_remote(server_trace)
@@ -78,14 +71,14 @@ module Selenium
78
71
 
79
72
  file = frame['fileName']
80
73
  line = frame['lineNumber']
81
- meth = frame['methodName']
74
+ method = frame['methodName']
82
75
 
83
76
  class_name = frame['className']
84
77
  file = "#{class_name}(#{file})" if class_name
85
78
 
86
- meth = 'unknown' if meth.nil? || meth.empty?
79
+ method = 'unknown' if method.nil? || method.empty?
87
80
 
88
- "[remote server] #{file}:#{line}:in `#{meth}'"
81
+ "[remote server] #{file}:#{line}:in `#{method}'"
89
82
  end
90
83
  end
91
84
 
@@ -23,7 +23,7 @@ module Selenium
23
23
  class ServerError < StandardError
24
24
  def initialize(response)
25
25
  if response.is_a? String
26
- super(response)
26
+ super
27
27
  else
28
28
  super("status code #{response.code}; payload #{response.payload}")
29
29
  end
@@ -25,12 +25,13 @@ module Selenium
25
25
  module Remote
26
26
  autoload :Features, 'selenium/webdriver/remote/features'
27
27
  autoload :Bridge, 'selenium/webdriver/remote/bridge'
28
+ autoload :BiDiBridge, 'selenium/webdriver/remote/bidi_bridge'
28
29
  autoload :Driver, 'selenium/webdriver/remote/driver'
29
30
  autoload :Response, 'selenium/webdriver/remote/response'
30
31
  autoload :Capabilities, 'selenium/webdriver/remote/capabilities'
31
32
 
32
33
  module Http
33
- autoload :Common, 'selenium/webdriver/remote/http/common'
34
+ autoload :Common, 'selenium/webdriver/remote/http/common'
34
35
  autoload :Default, 'selenium/webdriver/remote/http/default'
35
36
  end
36
37
  end
@@ -24,7 +24,7 @@ module Selenium
24
24
  DEFAULT_PORT = 7050
25
25
  EXECUTABLE = 'safaridriver'
26
26
  SHUTDOWN_SUPPORTED = false
27
-
27
+ DRIVER_PATH_ENV_KEY = 'SE_SAFARIDRIVER'
28
28
  def initialize(path: nil, port: nil, log: nil, args: nil)
29
29
  raise Error::WebDriverError, 'Safari Service does not support setting log output' if log
30
30
 
@@ -27,7 +27,7 @@ module Selenium
27
27
  #
28
28
 
29
29
  class Guard
30
- attr_reader :guarded, :type, :messages, :reason
30
+ attr_reader :guarded, :type, :messages, :reason, :tracker
31
31
 
32
32
  def initialize(guarded, type, guards = nil)
33
33
  @guarded = guarded
@@ -36,22 +36,21 @@ module Selenium
36
36
  @messages[:unknown] = 'TODO: Investigate why this is failing and file a bug report'
37
37
  @type = type
38
38
 
39
- @reason = @guarded.delete(:reason)
39
+ @reason = @guarded[:reason] || 'No reason given'
40
+ @guarded[:reason] = @reason
40
41
  end
41
42
 
42
43
  def message
43
- details = case @reason
44
+ details = case reason
44
45
  when Integer
45
- "Bug Filed: #{@tracker}/#{@reason}"
46
+ "Bug Filed: #{tracker}/#{reason}"
46
47
  when Symbol
47
- @messages[@reason]
48
- when String
49
- @reason
48
+ messages[reason]
50
49
  else
51
- 'no reason given'
50
+ "Guarded by #{guarded};"
52
51
  end
53
52
 
54
- case @type
53
+ case type
55
54
  when :exclude
56
55
  "Test skipped because it breaks test run; #{details}"
57
56
  when :flaky
@@ -19,6 +19,6 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
- VERSION = '4.17.0'
22
+ VERSION = '4.26.0'
23
23
  end # WebDriver
24
24
  end # Selenium
@@ -49,7 +49,7 @@ module Selenium
49
49
  # @api private
50
50
 
51
51
  def self.root
52
- @root ||= File.expand_path('..', __dir__)
52
+ @root ||= File.expand_path('..', __dir__.to_s)
53
53
  end
54
54
 
55
55
  #
@@ -47,18 +47,21 @@ Gem::Specification.new do |s|
47
47
  s.bindir = 'bin'
48
48
  s.require_paths = ['lib']
49
49
 
50
- s.add_runtime_dependency 'base64', ['~> 0.2']
51
- s.add_runtime_dependency 'rexml', ['~> 3.2', '>= 3.2.5']
52
- s.add_runtime_dependency 'rubyzip', ['>= 1.2.2', '< 3.0']
53
- s.add_runtime_dependency 'websocket', ['~> 1.0']
50
+ s.add_dependency 'base64', ['~> 0.2']
51
+ s.add_dependency 'logger', ['~> 1.4']
52
+ s.add_dependency 'rexml', ['~> 3.2', '>= 3.2.5']
53
+ s.add_dependency 'rubyzip', ['>= 1.2.2', '< 3.0']
54
+ s.add_dependency 'websocket', ['~> 1.0']
54
55
 
56
+ s.add_development_dependency 'git', ['~> 1.19']
55
57
  s.add_development_dependency 'rack', ['~> 2.0']
56
58
  s.add_development_dependency 'rake', ['~> 13.0']
57
59
  s.add_development_dependency 'rspec', ['~> 3.0']
58
- s.add_development_dependency 'rubocop', ['~> 1.42']
60
+ s.add_development_dependency 'rubocop', ['~> 1.60', '>=1.60.2']
59
61
  s.add_development_dependency 'rubocop-performance', ['~> 1.15']
62
+ s.add_development_dependency 'rubocop-rake', ['~> 0.6.0']
60
63
  s.add_development_dependency 'rubocop-rspec', ['~> 2.16']
61
64
  s.add_development_dependency 'webmock', ['~> 3.5']
62
65
  s.add_development_dependency 'webrick', ['~> 1.7']
63
- s.add_development_dependency 'yard', ['~> 0.9.11']
66
+ s.add_development_dependency 'yard', ['~> 0.9.11', '>= 0.9.36']
64
67
  end