capybara 3.32.2 → 3.35.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +97 -15
  3. data/README.md +9 -4
  4. data/lib/capybara.rb +18 -8
  5. data/lib/capybara/config.rb +4 -6
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/driver/base.rb +4 -0
  8. data/lib/capybara/helpers.rb +25 -1
  9. data/lib/capybara/minitest.rb +2 -3
  10. data/lib/capybara/minitest/spec.rb +14 -11
  11. data/lib/capybara/node/actions.rb +16 -21
  12. data/lib/capybara/node/base.rb +6 -6
  13. data/lib/capybara/node/element.rb +1 -5
  14. data/lib/capybara/node/finders.rb +7 -6
  15. data/lib/capybara/node/matchers.rb +12 -12
  16. data/lib/capybara/node/simple.rb +5 -1
  17. data/lib/capybara/queries/ancestor_query.rb +1 -1
  18. data/lib/capybara/queries/current_path_query.rb +14 -4
  19. data/lib/capybara/queries/selector_query.rb +40 -18
  20. data/lib/capybara/queries/sibling_query.rb +1 -1
  21. data/lib/capybara/queries/style_query.rb +1 -1
  22. data/lib/capybara/queries/text_query.rb +7 -1
  23. data/lib/capybara/rack_test/browser.rb +7 -3
  24. data/lib/capybara/rack_test/driver.rb +1 -0
  25. data/lib/capybara/rack_test/form.rb +1 -1
  26. data/lib/capybara/rack_test/node.rb +1 -1
  27. data/lib/capybara/registration_container.rb +44 -0
  28. data/lib/capybara/registrations/drivers.rb +18 -12
  29. data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
  30. data/lib/capybara/registrations/servers.rb +2 -1
  31. data/lib/capybara/result.rb +6 -10
  32. data/lib/capybara/rspec.rb +2 -0
  33. data/lib/capybara/rspec/matcher_proxies.rb +1 -1
  34. data/lib/capybara/rspec/matchers.rb +7 -6
  35. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  36. data/lib/capybara/rspec/matchers/match_style.rb +5 -0
  37. data/lib/capybara/selector.rb +12 -3
  38. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  39. data/lib/capybara/selector/builders/xpath_builder.rb +3 -1
  40. data/lib/capybara/selector/definition.rb +11 -9
  41. data/lib/capybara/selector/definition/button.rb +26 -14
  42. data/lib/capybara/selector/definition/css.rb +1 -1
  43. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  44. data/lib/capybara/selector/definition/element.rb +2 -1
  45. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  46. data/lib/capybara/selector/definition/label.rb +1 -1
  47. data/lib/capybara/selector/definition/link.rb +8 -0
  48. data/lib/capybara/selector/definition/select.rb +1 -1
  49. data/lib/capybara/selector/definition/table.rb +1 -1
  50. data/lib/capybara/selector/definition/table_row.rb +2 -2
  51. data/lib/capybara/selector/filter_set.rb +2 -2
  52. data/lib/capybara/selector/selector.rb +9 -1
  53. data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
  54. data/lib/capybara/selenium/driver.rb +48 -4
  55. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +9 -11
  56. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -11
  57. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +1 -1
  58. data/lib/capybara/selenium/extensions/find.rb +4 -4
  59. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  60. data/lib/capybara/selenium/logger_suppressor.rb +8 -2
  61. data/lib/capybara/selenium/node.rb +9 -5
  62. data/lib/capybara/selenium/nodes/chrome_node.rb +23 -5
  63. data/lib/capybara/selenium/nodes/firefox_node.rb +7 -2
  64. data/lib/capybara/selenium/nodes/safari_node.rb +1 -1
  65. data/lib/capybara/selenium/patches/atoms.rb +4 -4
  66. data/lib/capybara/selenium/patches/logs.rb +7 -9
  67. data/lib/capybara/server/animation_disabler.rb +8 -3
  68. data/lib/capybara/server/middleware.rb +4 -2
  69. data/lib/capybara/session.rb +23 -14
  70. data/lib/capybara/session/config.rb +3 -1
  71. data/lib/capybara/session/matchers.rb +11 -11
  72. data/lib/capybara/spec/public/test.js +13 -1
  73. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  74. data/lib/capybara/spec/session/check_spec.rb +6 -0
  75. data/lib/capybara/spec/session/click_button_spec.rb +11 -0
  76. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  77. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  78. data/lib/capybara/spec/session/has_button_spec.rb +51 -0
  79. data/lib/capybara/spec/session/has_css_spec.rb +2 -1
  80. data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
  81. data/lib/capybara/spec/session/has_field_spec.rb +16 -0
  82. data/lib/capybara/spec/session/has_select_spec.rb +4 -4
  83. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  84. data/lib/capybara/spec/session/has_text_spec.rb +0 -11
  85. data/lib/capybara/spec/session/html_spec.rb +1 -1
  86. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  87. data/lib/capybara/spec/session/node_spec.rb +29 -9
  88. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  89. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  90. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  91. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  92. data/lib/capybara/spec/session/window/window_spec.rb +1 -1
  93. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  94. data/lib/capybara/spec/spec_helper.rb +12 -12
  95. data/lib/capybara/spec/test_app.rb +23 -21
  96. data/lib/capybara/spec/views/form.erb +25 -2
  97. data/lib/capybara/spec/views/with_animation.erb +8 -0
  98. data/lib/capybara/spec/views/with_dragula.erb +3 -1
  99. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  100. data/lib/capybara/spec/views/with_js.erb +3 -0
  101. data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
  102. data/lib/capybara/version.rb +1 -1
  103. data/lib/capybara/window.rb +3 -7
  104. data/spec/basic_node_spec.rb +9 -8
  105. data/spec/capybara_spec.rb +1 -1
  106. data/spec/dsl_spec.rb +14 -1
  107. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  108. data/spec/minitest_spec.rb +3 -2
  109. data/spec/rack_test_spec.rb +16 -5
  110. data/spec/rspec/features_spec.rb +3 -1
  111. data/spec/rspec/scenarios_spec.rb +4 -0
  112. data/spec/rspec/shared_spec_matchers.rb +61 -49
  113. data/spec/rspec_spec.rb +4 -0
  114. data/spec/selector_spec.rb +17 -2
  115. data/spec/selenium_spec_chrome.rb +39 -20
  116. data/spec/selenium_spec_chrome_remote.rb +5 -1
  117. data/spec/selenium_spec_firefox.rb +15 -13
  118. data/spec/server_spec.rb +60 -49
  119. data/spec/shared_selenium_session.rb +83 -1
  120. data/spec/spec_helper.rb +1 -1
  121. metadata +49 -14
  122. data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -4,30 +4,30 @@ Capybara.add_selector(:button, locator_type: [String, Symbol]) do
4
4
  xpath(:value, :title, :type, :name) do |locator, **options|
5
5
  input_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).one_of('submit', 'reset', 'image', 'button')]
6
6
  btn_xpath = XPath.descendant(:button)
7
+ aria_btn_xpath = XPath.descendant[XPath.attr(:role).equals('button')]
7
8
  image_btn_xpath = XPath.descendant(:input)[XPath.attr(:type) == 'image']
8
9
 
9
10
  unless locator.nil?
10
11
  locator = locator.to_s
11
- locator_matchers = XPath.attr(:id).equals(locator) |
12
- XPath.attr(:name).equals(locator) |
13
- XPath.attr(:value).is(locator) |
14
- XPath.attr(:title).is(locator)
15
- locator_matchers |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
16
- locator_matchers |= XPath.attr(test_id) == locator if test_id
12
+ locator_matchers = combine_locators(locator, config: self)
13
+ btn_matchers = locator_matchers |
14
+ XPath.string.n.is(locator) |
15
+ XPath.descendant(:img)[XPath.attr(:alt).is(locator)]
17
16
 
18
- input_btn_xpath = input_btn_xpath[locator_matchers]
19
-
20
- btn_xpath = btn_xpath[locator_matchers |
21
- XPath.string.n.is(locator) |
22
- XPath.descendant(:img)[XPath.attr(:alt).is(locator)]]
17
+ input_btn_xpath = input_btn_xpath[locator_matchers] + locate_label(locator).descendant(input_btn_xpath)
18
+ btn_xpath = btn_xpath[btn_matchers] + locate_label(locator).descendant(btn_xpath)
19
+ aria_btn_xpath = aria_btn_xpath[btn_matchers]
23
20
 
24
21
  alt_matches = XPath.attr(:alt).is(locator)
25
22
  alt_matches |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
26
- image_btn_xpath = image_btn_xpath[alt_matches]
23
+ image_btn_xpath = image_btn_xpath[alt_matches] + locate_label(locator).descendant(image_btn_xpath)
27
24
  end
28
25
 
29
- %i[value title type].inject(input_btn_xpath.union(btn_xpath).union(image_btn_xpath)) do |memo, ef|
30
- memo[find_by_attr(ef, options[ef])]
26
+ btn_xpaths = [input_btn_xpath, btn_xpath, image_btn_xpath]
27
+ btn_xpaths << aria_btn_xpath if enable_aria_role
28
+
29
+ %i[value title type].inject(btn_xpaths.inject(&:union)) do |memo, ef|
30
+ memo.where(find_by_attr(ef, options[ef]))
31
31
  end
32
32
  end
33
33
 
@@ -48,4 +48,16 @@ Capybara.add_selector(:button, locator_type: [String, Symbol]) do
48
48
  describe_node_filters do |disabled: nil, **|
49
49
  ' that is disabled' if disabled == true
50
50
  end
51
+
52
+ def combine_locators(locator, config:)
53
+ [
54
+ XPath.attr(:id).equals(locator),
55
+ XPath.attr(:name).equals(locator),
56
+ XPath.attr(:value).is(locator),
57
+ XPath.attr(:title).is(locator),
58
+ (XPath.attr(:id) == XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for)),
59
+ (XPath.attr(:'aria-label').is(locator) if config.enable_aria_label),
60
+ (XPath.attr(config.test_id) == locator if config.test_id)
61
+ ].compact.inject(&:|)
62
+ end
51
63
  end
@@ -3,7 +3,7 @@
3
3
  Capybara.add_selector(:css, locator_type: [String, Symbol], raw_locator: true) do
4
4
  css do |css|
5
5
  if css.is_a? Symbol
6
- warn "DEPRECATED: Passing a symbol (#{css.inspect}) as the CSS locator is deprecated - please pass a string instead."
6
+ Capybara::Helpers.warn "DEPRECATED: Passing a symbol (#{css.inspect}) as the CSS locator is deprecated - please pass a string instead : #{Capybara::Helpers.filter_backtrace(caller)}"
7
7
  end
8
8
  css
9
9
  end
@@ -19,7 +19,7 @@ Capybara.add_selector(:datalist_input, locator_type: [String, Symbol]) do
19
19
 
20
20
  expression_filter(:with_options) do |expr, options|
21
21
  options.inject(expr) do |xpath, option|
22
- xpath[XPath.attr(:list) == XPath.anywhere(:datalist)[expression_for(:datalist_option, option)].attr(:id)]
22
+ xpath.where(XPath.attr(:list) == XPath.anywhere(:datalist)[expression_for(:datalist_option, option)].attr(:id))
23
23
  end
24
24
  end
25
25
 
@@ -18,7 +18,8 @@ Capybara.add_selector(:element, locator_type: [String, Symbol]) do
18
18
  end
19
19
 
20
20
  describe_expression_filters do |**options|
21
- booleans, values = options.partition { |_k, v| [true, false].include? v }.map(&:to_h)
21
+ boolean_values = [true, false]
22
+ booleans, values = options.partition { |_k, v| boolean_values.include? v }.map(&:to_h)
22
23
  desc = describe_all_expression_filters(**values)
23
24
  desc + booleans.map do |k, v|
24
25
  v ? " with #{k} attribute" : "without #{k} attribute"
@@ -18,7 +18,7 @@ Capybara.add_selector(:fillable_field, locator_type: [String, Symbol]) do
18
18
  end
19
19
  end
20
20
 
21
- filter_set(:_field, %i[disabled multiple name placeholder valid])
21
+ filter_set(:_field, %i[disabled multiple name placeholder valid validation_message])
22
22
 
23
23
  node_filter(:with) do |node, with|
24
24
  val = node.value
@@ -53,7 +53,7 @@ Capybara.add_selector(:label, locator_type: [String, Symbol]) do
53
53
  end
54
54
  end
55
55
  describe_node_filters do |**options|
56
- " for element #{options[:for]}" if options[:for]&.is_a?(Capybara::Node::Element)
56
+ " for element #{options[:for]}" if options[:for].is_a?(Capybara::Node::Element)
57
57
  end
58
58
 
59
59
  def labelable_elements
@@ -5,6 +5,13 @@ Capybara.add_selector(:link, locator_type: [String, Symbol]) do
5
5
  xpath = XPath.descendant(:a)
6
6
  xpath = builder(xpath).add_attribute_conditions(href: href) unless href == false
7
7
 
8
+ if enable_aria_role
9
+ role_path = XPath.descendant[XPath.attr(:role).equals('link')]
10
+ role_path = builder(role_path).add_attribute_conditions(href: href) unless [true, false].include? href
11
+
12
+ xpath += role_path
13
+ end
14
+
8
15
  unless locator.nil?
9
16
  locator = locator.to_s
10
17
  matchers = [XPath.attr(:id) == locator,
@@ -18,6 +25,7 @@ Capybara.add_selector(:link, locator_type: [String, Symbol]) do
18
25
 
19
26
  xpath = xpath[find_by_attr(:title, title)]
20
27
  xpath = xpath[XPath.descendant(:img)[XPath.attr(:alt) == alt]] if alt
28
+
21
29
  xpath
22
30
  end
23
31
 
@@ -33,7 +33,7 @@ Capybara.add_selector(:select, locator_type: [String, Symbol]) do
33
33
 
34
34
  expression_filter(:with_options) do |expr, options|
35
35
  options.inject(expr) do |xpath, option|
36
- xpath[expression_for(:option, option)]
36
+ xpath.where(expression_for(:option, option))
37
37
  end
38
38
  end
39
39
 
@@ -43,7 +43,7 @@ Capybara.add_selector(:table, locator_type: [String, Symbol]) do
43
43
  end
44
44
 
45
45
  expression_filter(:cols, valid_values: [Array]) do |xpath, cols|
46
- raise ArgumentError, ':cols must be an Array of Arrays' unless cols.all? { |col| col.is_a? Array }
46
+ raise ArgumentError, ':cols must be an Array of Arrays' unless cols.all?(Array)
47
47
 
48
48
  rows = cols.transpose
49
49
  col_conditions = rows.map { |row| match_row(row, match_size: true) }.reduce(:&)
@@ -9,12 +9,12 @@ Capybara.add_selector(:table_row, locator_type: [Array, Hash]) do
9
9
  cell_xp = XPath.descendant(:td)[
10
10
  XPath.string.n.is(cell) & XPath.position.equals(header_xp.preceding_sibling.count.plus(1))
11
11
  ]
12
- xp[cell_xp]
12
+ xp.where(cell_xp)
13
13
  end
14
14
  else
15
15
  initial_td = XPath.descendant(:td)[XPath.string.n.is(locator.shift)]
16
16
  tds = locator.reverse.map { |cell| XPath.following_sibling(:td)[XPath.string.n.is(cell)] }
17
- .reduce { |xp, cell| xp[cell] }
17
+ .reduce { |xp, cell| xp.where(cell) }
18
18
  xpath[initial_td[tds]]
19
19
  end
20
20
  end
@@ -12,7 +12,7 @@ module Capybara
12
12
  @node_filters = {}
13
13
  @expression_filters = {}
14
14
  @descriptions = Hash.new { |hsh, key| hsh[key] = [] }
15
- instance_eval(&block)
15
+ instance_eval(&block) if block
16
16
  end
17
17
 
18
18
  def node_filter(names, *types, **options, &block)
@@ -49,7 +49,7 @@ module Capybara
49
49
  end
50
50
 
51
51
  def descriptions
52
- warn 'DEPRECATED: FilterSet#descriptions is deprecated without replacement'
52
+ Capybara::Helpers.warn 'DEPRECATED: FilterSet#descriptions is deprecated without replacement'
53
53
  [undeclared_descriptions, node_filter_descriptions, expression_filter_descriptions].flatten
54
54
  end
55
55
 
@@ -48,6 +48,10 @@ module Capybara
48
48
  @config[:enable_aria_label]
49
49
  end
50
50
 
51
+ def enable_aria_role
52
+ @config[:enable_aria_role]
53
+ end
54
+
51
55
  def test_id
52
56
  @config[:test_id]
53
57
  end
@@ -128,7 +132,11 @@ module Capybara
128
132
  attr_matchers |= XPath.attr(test_id) == locator if test_id
129
133
 
130
134
  locate_xpath = locate_xpath[attr_matchers]
131
- locate_xpath + XPath.descendant(:label)[XPath.string.n.is(locator)].descendant(xpath)
135
+ locate_xpath + locate_label(locator).descendant(xpath)
136
+ end
137
+
138
+ def locate_label(locator)
139
+ XPath.descendant(:label)[XPath.string.n.is(locator)]
132
140
  end
133
141
 
134
142
  def find_by_attr(attribute, value)
@@ -158,7 +158,7 @@
158
158
  // the overflow style of the body, and the body is really overflow:visible.
159
159
  var overflowElem = e;
160
160
  if (htmlOverflowStyle == "visible") {
161
- // Note: bodyElem will be null/undefined in SVG documents.
161
+ // NOTE: bodyElem will be null/undefined in SVG documents.
162
162
  if (e == htmlElem && bodyElem) {
163
163
  overflowElem = bodyElem;
164
164
  } else if (e == bodyElem) {
@@ -12,20 +12,44 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
12
12
  clear_session_storage: nil
13
13
  }.freeze
14
14
  SPECIAL_OPTIONS = %i[browser clear_local_storage clear_session_storage timeout native_displayed].freeze
15
+ CAPS_VERSION = Gem::Requirement.new('~> 4.0.0.alpha6')
16
+
15
17
  attr_reader :app, :options
16
18
 
17
19
  class << self
20
+ attr_reader :selenium_webdriver_version
21
+
18
22
  def load_selenium
19
23
  require 'selenium-webdriver'
20
24
  require 'capybara/selenium/logger_suppressor'
21
25
  require 'capybara/selenium/patches/atoms'
22
26
  require 'capybara/selenium/patches/is_displayed'
23
27
  require 'capybara/selenium/patches/action_pauser'
24
- if Gem.loaded_specs['selenium-webdriver'].version < Gem::Version.new('3.5.0')
28
+
29
+ # Look up the version of `selenium-webdriver` to
30
+ # see if it's a version we support.
31
+ #
32
+ # By default, we use Gem.loaded_specs to determine
33
+ # the version number. However, in some cases, such
34
+ # as when loading `selenium-webdriver` outside of
35
+ # Rubygems, we fall back to referencing
36
+ # Selenium::WebDriver::VERSION. Ideally we'd
37
+ # use the constant in all cases, but earlier versions
38
+ # of `selenium-webdriver` didn't provide the constant.
39
+ @selenium_webdriver_version =
40
+ if Gem.loaded_specs['selenium-webdriver']
41
+ Gem.loaded_specs['selenium-webdriver'].version
42
+ else
43
+ Gem::Version.new(Selenium::WebDriver::VERSION)
44
+ end
45
+
46
+ unless Gem::Requirement.new('>= 3.5.0').satisfied_by? @selenium_webdriver_version
25
47
  warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade."
26
48
  end
49
+
50
+ @selenium_webdriver_version
27
51
  rescue LoadError => e
28
- raise e unless e.message.match?(/selenium-webdriver/)
52
+ raise e unless e.message.include?('selenium-webdriver')
29
53
 
30
54
  raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler."
31
55
  end
@@ -49,7 +73,15 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
49
73
  end
50
74
  end
51
75
  processed_options = options.reject { |key, _val| SPECIAL_OPTIONS.include?(key) }
52
- @browser = Selenium::WebDriver.for(options[:browser], processed_options)
76
+
77
+ @browser = if options[:browser] == :firefox &&
78
+ RUBY_VERSION >= '3.0' &&
79
+ Capybara::Selenium::Driver.selenium_webdriver_version <= Gem::Version.new('4.0.0.alpha1')
80
+ # selenium-webdriver 3.x doesn't correctly pass options through for Firefox with Ruby 3 so workaround that
81
+ Selenium::WebDriver::Firefox::Driver.new(**processed_options)
82
+ else
83
+ Selenium::WebDriver.for(options[:browser], processed_options)
84
+ end
53
85
 
54
86
  specialize_driver
55
87
  setup_exit_handler
@@ -58,6 +90,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
58
90
  end
59
91
 
60
92
  def initialize(app, **options)
93
+ super()
61
94
  self.class.load_selenium
62
95
  @app = app
63
96
  @browser = nil
@@ -85,6 +118,8 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
85
118
 
86
119
  def html
87
120
  browser.page_source
121
+ rescue Selenium::WebDriver::Error::JavascriptError => e
122
+ raise unless e.message.include?('documentElement is null')
88
123
  end
89
124
 
90
125
  def title
@@ -113,6 +148,10 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
113
148
  unwrap_script_result(result)
114
149
  end
115
150
 
151
+ def send_keys(*args)
152
+ active_element.send_keys(*args)
153
+ end
154
+
116
155
  def save_screenshot(path, **_options)
117
156
  browser.save_screenshot(path)
118
157
  end
@@ -241,7 +280,8 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
241
280
 
242
281
  def quit
243
282
  @browser&.quit
244
- rescue Selenium::WebDriver::Error::SessionNotCreatedError, Errno::ECONNREFUSED
283
+ rescue Selenium::WebDriver::Error::SessionNotCreatedError, Errno::ECONNREFUSED,
284
+ Selenium::WebDriver::Error::InvalidSessionIdError
245
285
  # Browser must have already gone
246
286
  rescue Selenium::WebDriver::Error::UnknownError => e
247
287
  unless silenced_unknown_error_message?(e.message) # Most likely already gone
@@ -435,6 +475,10 @@ private
435
475
  browser
436
476
  end
437
477
 
478
+ def active_element
479
+ browser.switch_to.active_element
480
+ end
481
+
438
482
  def build_node(native_node, initial_cache = {})
439
483
  ::Capybara::Selenium::Node.new(self, native_node, initial_cache)
440
484
  end
@@ -7,27 +7,25 @@ module Capybara::Selenium::Driver::ChromeDriver
7
7
  def self.extended(base)
8
8
  bridge = base.send(:bridge)
9
9
  bridge.extend Capybara::Selenium::ChromeLogs unless bridge.respond_to?(:log)
10
- bridge.extend Capybara::Selenium::IsDisplayed unless bridge.commands(:is_element_displayed)
10
+ bridge.extend Capybara::Selenium::IsDisplayed unless bridge.send(:commands, :is_element_displayed)
11
11
  base.options[:native_displayed] = false if base.options[:native_displayed].nil?
12
12
  end
13
13
 
14
14
  def fullscreen_window(handle)
15
15
  within_given_window(handle) do
16
- begin
17
- super
18
- rescue NoMethodError => e
19
- raise unless e.message.match?(/full_screen_window/)
20
-
21
- result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {})
22
- result['value']
23
- end
16
+ super
17
+ rescue NoMethodError => e
18
+ raise unless e.message.include?('full_screen_window')
19
+
20
+ result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {})
21
+ result['value']
24
22
  end
25
23
  end
26
24
 
27
25
  def resize_window_to(handle, width, height)
28
26
  super
29
27
  rescue Selenium::WebDriver::Error::UnknownError => e
30
- raise unless e.message.match?(/failed to change window state/)
28
+ raise unless e.message.include?('failed to change window state')
31
29
 
32
30
  # Chromedriver doesn't wait long enough for state to change when coming out of fullscreen
33
31
  # and raises unnecessary error. Wait a bit and try again.
@@ -65,7 +63,7 @@ private
65
63
  end
66
64
 
67
65
  def clear_all_storage?
68
- storage_clears.none? { |s| s == false }
66
+ storage_clears.none? false
69
67
  end
70
68
 
71
69
  def uniform_storage_clear?
@@ -5,7 +5,7 @@ require 'capybara/selenium/nodes/edge_node'
5
5
  module Capybara::Selenium::Driver::EdgeDriver
6
6
  def self.extended(base)
7
7
  bridge = base.send(:bridge)
8
- bridge.extend Capybara::Selenium::IsDisplayed unless bridge.commands(:is_element_displayed)
8
+ bridge.extend Capybara::Selenium::IsDisplayed unless bridge.send(:commands, :is_element_displayed)
9
9
  base.options[:native_displayed] = false if base.options[:native_displayed].nil?
10
10
  end
11
11
 
@@ -13,21 +13,19 @@ module Capybara::Selenium::Driver::EdgeDriver
13
13
  return super if edgedriver_version < 75
14
14
 
15
15
  within_given_window(handle) do
16
- begin
17
- super
18
- rescue NoMethodError => e
19
- raise unless e.message.match?(/full_screen_window/)
20
-
21
- result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {})
22
- result['value']
23
- end
16
+ super
17
+ rescue NoMethodError => e
18
+ raise unless e.message.include?('full_screen_window')
19
+
20
+ result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {})
21
+ result['value']
24
22
  end
25
23
  end
26
24
 
27
25
  def resize_window_to(handle, width, height)
28
26
  super
29
27
  rescue Selenium::WebDriver::Error::UnknownError => e
30
- raise unless e.message.match?(/failed to change window state/)
28
+ raise unless e.message.include?('failed to change window state')
31
29
 
32
30
  # Chromedriver doesn't wait long enough for state to change when coming out of fullscreen
33
31
  # and raises unnecessary error. Wait a bit and try again.
@@ -74,7 +72,7 @@ private
74
72
  end
75
73
 
76
74
  def clear_all_storage?
77
- storage_clears.none? { |s| s == false }
75
+ storage_clears.none? false
78
76
  end
79
77
 
80
78
  def uniform_storage_clear?
@@ -6,7 +6,7 @@ module Capybara::Selenium::Driver::FirefoxDriver
6
6
  def self.extended(driver)
7
7
  driver.extend Capybara::Selenium::Driver::W3CFirefoxDriver if w3c?(driver)
8
8
  bridge = driver.send(:bridge)
9
- bridge.extend Capybara::Selenium::IsDisplayed unless bridge.commands(:is_element_displayed)
9
+ bridge.extend Capybara::Selenium::IsDisplayed unless bridge.send(:commands, :is_element_displayed)
10
10
  end
11
11
 
12
12
  def self.w3c?(driver)
@@ -28,7 +28,7 @@ module Capybara
28
28
  hints_js, functions = build_hints_js(uses_visibility, styles, position)
29
29
  return [] unless functions.any?
30
30
 
31
- es_context.execute_script(hints_js, elements).map! do |results|
31
+ (es_context.execute_script(hints_js, elements) || []).map! do |results|
32
32
  hint = {}
33
33
  hint[:style] = results.pop if functions.include?(:style_func)
34
34
  hint[:position] = results.pop if functions.include?(:position_func)
@@ -100,9 +100,9 @@ module Capybara
100
100
  def is_displayed_atom # rubocop:disable Naming/PredicateName
101
101
  @@is_displayed_atom ||= begin # rubocop:disable Style/ClassVars
102
102
  browser.send(:bridge).send(:read_atom, 'isDisplayed')
103
- rescue StandardError
104
- # If the atom doesn't exist or other error
105
- ''
103
+ rescue StandardError
104
+ # If the atom doesn't exist or other error
105
+ ''
106
106
  end
107
107
  end
108
108
  end