capybara 3.3.1 → 3.4.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 (159) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +16 -0
  3. data/README.md +5 -7
  4. data/lib/capybara.rb +7 -6
  5. data/lib/capybara/config.rb +1 -1
  6. data/lib/capybara/dsl.rb +2 -2
  7. data/lib/capybara/helpers.rb +3 -3
  8. data/lib/capybara/minitest/spec.rb +3 -3
  9. data/lib/capybara/node/actions.rb +18 -18
  10. data/lib/capybara/node/base.rb +1 -1
  11. data/lib/capybara/node/element.rb +2 -2
  12. data/lib/capybara/node/finders.rb +6 -6
  13. data/lib/capybara/node/matchers.rb +5 -5
  14. data/lib/capybara/node/simple.rb +2 -2
  15. data/lib/capybara/queries/ancestor_query.rb +1 -1
  16. data/lib/capybara/queries/base_query.rb +12 -11
  17. data/lib/capybara/queries/current_path_query.rb +1 -1
  18. data/lib/capybara/queries/selector_query.rb +39 -15
  19. data/lib/capybara/queries/sibling_query.rb +1 -1
  20. data/lib/capybara/queries/text_query.rb +1 -1
  21. data/lib/capybara/rack_test/browser.rb +7 -7
  22. data/lib/capybara/rack_test/driver.rb +1 -1
  23. data/lib/capybara/rack_test/form.rb +7 -7
  24. data/lib/capybara/rack_test/node.rb +16 -16
  25. data/lib/capybara/rails.rb +1 -1
  26. data/lib/capybara/result.rb +8 -4
  27. data/lib/capybara/rspec/features.rb +4 -4
  28. data/lib/capybara/rspec/matchers.rb +6 -6
  29. data/lib/capybara/selector.rb +106 -90
  30. data/lib/capybara/selector/css.rb +4 -4
  31. data/lib/capybara/selector/filter_set.rb +52 -8
  32. data/lib/capybara/selector/selector.rb +39 -15
  33. data/lib/capybara/selenium/driver.rb +10 -10
  34. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +8 -0
  35. data/lib/capybara/selenium/node.rb +9 -10
  36. data/lib/capybara/selenium/nodes/chrome_node.rb +18 -0
  37. data/lib/capybara/selenium/nodes/marionette_node.rb +32 -7
  38. data/lib/capybara/server.rb +3 -3
  39. data/lib/capybara/server/animation_disabler.rb +1 -1
  40. data/lib/capybara/server/middleware.rb +1 -1
  41. data/lib/capybara/session.rb +23 -19
  42. data/lib/capybara/session/config.rb +18 -3
  43. data/lib/capybara/spec/public/test.js +1 -1
  44. data/lib/capybara/spec/session/accept_alert_spec.rb +10 -10
  45. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
  46. data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
  47. data/lib/capybara/spec/session/all_spec.rb +33 -32
  48. data/lib/capybara/spec/session/ancestor_spec.rb +19 -19
  49. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +38 -38
  50. data/lib/capybara/spec/session/assert_current_path_spec.rb +16 -16
  51. data/lib/capybara/spec/session/assert_selector_spec.rb +53 -53
  52. data/lib/capybara/spec/session/assert_style_spec.rb +3 -3
  53. data/lib/capybara/spec/session/assert_text_spec.rb +31 -30
  54. data/lib/capybara/spec/session/assert_title_spec.rb +12 -12
  55. data/lib/capybara/spec/session/attach_file_spec.rb +51 -52
  56. data/lib/capybara/spec/session/body_spec.rb +6 -6
  57. data/lib/capybara/spec/session/check_spec.rb +52 -47
  58. data/lib/capybara/spec/session/choose_spec.rb +32 -32
  59. data/lib/capybara/spec/session/click_button_spec.rb +103 -103
  60. data/lib/capybara/spec/session/click_link_or_button_spec.rb +24 -23
  61. data/lib/capybara/spec/session/click_link_spec.rb +49 -48
  62. data/lib/capybara/spec/session/current_scope_spec.rb +7 -7
  63. data/lib/capybara/spec/session/current_url_spec.rb +26 -27
  64. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
  65. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
  66. data/lib/capybara/spec/session/element/assert_match_selector_spec.rb +8 -8
  67. data/lib/capybara/spec/session/element/match_css_spec.rb +10 -10
  68. data/lib/capybara/spec/session/element/match_xpath_spec.rb +6 -6
  69. data/lib/capybara/spec/session/element/matches_selector_spec.rb +51 -51
  70. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
  71. data/lib/capybara/spec/session/evaluate_script_spec.rb +15 -8
  72. data/lib/capybara/spec/session/execute_script_spec.rb +7 -7
  73. data/lib/capybara/spec/session/fill_in_spec.rb +43 -42
  74. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  75. data/lib/capybara/spec/session/find_by_id_spec.rb +7 -7
  76. data/lib/capybara/spec/session/find_field_spec.rb +32 -30
  77. data/lib/capybara/spec/session/find_link_spec.rb +21 -21
  78. data/lib/capybara/spec/session/find_spec.rb +153 -135
  79. data/lib/capybara/spec/session/first_spec.rb +41 -41
  80. data/lib/capybara/spec/session/frame/frame_title_spec.rb +5 -5
  81. data/lib/capybara/spec/session/frame/frame_url_spec.rb +5 -5
  82. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +17 -17
  83. data/lib/capybara/spec/session/frame/within_frame_spec.rb +31 -17
  84. data/lib/capybara/spec/session/go_back_spec.rb +1 -1
  85. data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
  86. data/lib/capybara/spec/session/has_all_selectors_spec.rb +17 -17
  87. data/lib/capybara/spec/session/has_button_spec.rb +13 -13
  88. data/lib/capybara/spec/session/has_css_spec.rb +133 -131
  89. data/lib/capybara/spec/session/has_current_path_spec.rb +29 -29
  90. data/lib/capybara/spec/session/has_field_spec.rb +58 -58
  91. data/lib/capybara/spec/session/has_link_spec.rb +4 -4
  92. data/lib/capybara/spec/session/has_none_selectors_spec.rb +24 -24
  93. data/lib/capybara/spec/session/has_select_spec.rb +43 -43
  94. data/lib/capybara/spec/session/has_selector_spec.rb +71 -71
  95. data/lib/capybara/spec/session/has_style_spec.rb +3 -3
  96. data/lib/capybara/spec/session/has_table_spec.rb +4 -4
  97. data/lib/capybara/spec/session/has_text_spec.rb +53 -52
  98. data/lib/capybara/spec/session/has_title_spec.rb +14 -14
  99. data/lib/capybara/spec/session/has_xpath_spec.rb +39 -38
  100. data/lib/capybara/spec/session/headers_spec.rb +1 -1
  101. data/lib/capybara/spec/session/html_spec.rb +6 -6
  102. data/lib/capybara/spec/session/node_spec.rb +129 -123
  103. data/lib/capybara/spec/session/node_wrapper_spec.rb +10 -7
  104. data/lib/capybara/spec/session/refresh_spec.rb +4 -7
  105. data/lib/capybara/spec/session/reset_session_spec.rb +28 -28
  106. data/lib/capybara/spec/session/response_code_spec.rb +1 -1
  107. data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
  108. data/lib/capybara/spec/session/save_page_spec.rb +37 -37
  109. data/lib/capybara/spec/session/save_screenshot_spec.rb +6 -6
  110. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  111. data/lib/capybara/spec/session/select_spec.rb +81 -81
  112. data/lib/capybara/spec/session/selectors_spec.rb +17 -17
  113. data/lib/capybara/spec/session/sibling_spec.rb +9 -9
  114. data/lib/capybara/spec/session/text_spec.rb +23 -23
  115. data/lib/capybara/spec/session/title_spec.rb +5 -5
  116. data/lib/capybara/spec/session/uncheck_spec.rb +24 -20
  117. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  118. data/lib/capybara/spec/session/visit_spec.rb +48 -49
  119. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -1
  120. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +16 -16
  121. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -2
  122. data/lib/capybara/spec/session/window/window_spec.rb +4 -4
  123. data/lib/capybara/spec/session/window/within_window_spec.rb +14 -14
  124. data/lib/capybara/spec/session/within_spec.rb +41 -41
  125. data/lib/capybara/spec/spec_helper.rb +11 -9
  126. data/lib/capybara/spec/test_app.rb +18 -17
  127. data/lib/capybara/spec/views/form.erb +29 -31
  128. data/lib/capybara/spec/views/with_html.erb +2 -2
  129. data/lib/capybara/version.rb +1 -1
  130. data/spec/basic_node_spec.rb +23 -23
  131. data/spec/capybara_spec.rb +20 -20
  132. data/spec/css_splitter_spec.rb +7 -7
  133. data/spec/dsl_spec.rb +37 -32
  134. data/spec/filter_set_spec.rb +4 -4
  135. data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
  136. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  137. data/spec/minitest_spec.rb +4 -4
  138. data/spec/minitest_spec_spec.rb +23 -23
  139. data/spec/per_session_config_spec.rb +5 -5
  140. data/spec/rack_test_spec.rb +44 -44
  141. data/spec/result_spec.rb +14 -14
  142. data/spec/rspec/features_spec.rb +13 -13
  143. data/spec/rspec/scenarios_spec.rb +4 -4
  144. data/spec/rspec/shared_spec_matchers.rb +282 -281
  145. data/spec/rspec/views_spec.rb +3 -3
  146. data/spec/rspec_matchers_spec.rb +10 -10
  147. data/spec/rspec_spec.rb +29 -29
  148. data/spec/selector_spec.rb +64 -64
  149. data/spec/selenium_spec_chrome.rb +14 -22
  150. data/spec/selenium_spec_chrome_remote.rb +28 -8
  151. data/spec/selenium_spec_edge.rb +9 -4
  152. data/spec/selenium_spec_firefox_remote.rb +87 -0
  153. data/spec/selenium_spec_ie.rb +9 -4
  154. data/spec/selenium_spec_marionette.rb +42 -18
  155. data/spec/server_spec.rb +29 -27
  156. data/spec/session_spec.rb +17 -17
  157. data/spec/shared_selenium_session.rb +70 -52
  158. data/spec/spec_helper.rb +1 -1
  159. metadata +4 -2
@@ -10,7 +10,7 @@ module Capybara
10
10
  super(options)
11
11
  @expected_path = expected_path
12
12
  @options = {
13
- url: !@expected_path.is_a?(Regexp) && !::Addressable::URI.parse(@expected_path || "").hostname.nil?,
13
+ url: !@expected_path.is_a?(Regexp) && !::Addressable::URI.parse(@expected_path || '').hostname.nil?,
14
14
  ignore_query: false
15
15
  }.merge(options)
16
16
  assert_valid_keys
@@ -8,7 +8,12 @@ module Capybara
8
8
  VALID_KEYS = COUNT_KEYS + %i[text id class visible exact exact_text match wait filter_set]
9
9
  VALID_MATCH = %i[first smart prefer_exact one].freeze
10
10
 
11
- def initialize(*args, session_options:, **options, &filter_block)
11
+ def initialize(*args,
12
+ session_options:,
13
+ enable_aria_label: session_options.enable_aria_label,
14
+ test_id: session_options.test_id,
15
+ **options,
16
+ &filter_block)
12
17
  @resolved_node = nil
13
18
  @options = options.dup
14
19
  super(@options)
@@ -20,7 +25,7 @@ module Capybara
20
25
 
21
26
  raise ArgumentError, "Unused parameters passed to #{self.class.name} : #{args}" unless args.empty?
22
27
 
23
- @expression = @selector.call(@locator, @options.merge(enable_aria_label: session_options.enable_aria_label))
28
+ @expression = @selector.call(@locator, @options.merge(selector_config: { enable_aria_label: enable_aria_label, test_id: test_id }))
24
29
 
25
30
  warn_exact_usage
26
31
 
@@ -30,22 +35,31 @@ module Capybara
30
35
  def name; selector.name; end
31
36
  def label; selector.label || selector.name; end
32
37
 
33
- def description
34
- @description = +""
35
- @description << "visible " if visible == :visible
36
- @description << "non-visible " if visible == :hidden
38
+ def description(applied = false)
39
+ @description = +''
40
+ if !applied || @applied_filters
41
+ @description << 'visible ' if visible == :visible
42
+ @description << 'non-visible ' if visible == :hidden
43
+ end
37
44
  @description << "#{label} #{locator.inspect}"
38
- @description << " with#{' exact' if exact_text == true} text #{options[:text].inspect}" if options[:text]
39
- @description << " with exact text #{exact_text}" if exact_text.is_a?(String)
45
+ if !applied || @applied_filters
46
+ @description << " with#{' exact' if exact_text == true} text #{options[:text].inspect}" if options[:text]
47
+ @description << " with exact text #{exact_text}" if exact_text.is_a?(String)
48
+ end
40
49
  @description << " with id #{options[:id]}" if options[:id]
41
50
  @description << " with classes [#{Array(options[:class]).join(',')}]" if options[:class]
42
- @description << selector.description(options)
43
- @description << " that also matches the custom filter block" if @filter_block
51
+ @description << selector.description(node_filters: !applied || (@applied_filters == :node), **options)
52
+ @description << ' that also matches the custom filter block' if @filter_block && (!applied || (@applied_filters == :node))
44
53
  @description << " within #{@resolved_node.inspect}" if describe_within?
45
54
  @description
46
55
  end
47
56
 
57
+ def applied_description
58
+ description(true)
59
+ end
60
+
48
61
  def matches_filters?(node)
62
+ @applied_filters ||= :system
49
63
  return false if options[:text] && !matches_text_filter(node, options[:text])
50
64
  return false if exact_text.is_a?(String) && !matches_exact_text_filter(node, exact_text)
51
65
 
@@ -54,6 +68,7 @@ module Capybara
54
68
  when :hidden then return false if node.visible?
55
69
  end
56
70
 
71
+ @applied_filters = :node
57
72
  matches_node_filters?(node) && matches_filter_block?(node)
58
73
  rescue *(node.respond_to?(:session) ? node.session.driver.invalid_element_errors : [])
59
74
  false
@@ -88,6 +103,7 @@ module Capybara
88
103
 
89
104
  # @api private
90
105
  def resolve_for(node, exact = nil)
106
+ @applied_filters = false
91
107
  @resolved_node = node
92
108
  node.synchronize do
93
109
  children = if selector.format == :css
@@ -110,6 +126,14 @@ module Capybara
110
126
  @expression.respond_to? :to_xpath
111
127
  end
112
128
 
129
+ def failure_message
130
+ +"expected to find #{applied_description}" << count_message
131
+ end
132
+
133
+ def negative_failure_message
134
+ +"expected not to find #{applied_description}" << count_message
135
+ end
136
+
113
137
  private
114
138
 
115
139
  def find_selector(locator)
@@ -184,8 +208,8 @@ module Capybara
184
208
  end
185
209
 
186
210
  return if unhandled_options.empty?
187
- invalid_names = unhandled_options.map(&:inspect).join(", ")
188
- valid_names = valid_keys.map(&:inspect).join(", ")
211
+ invalid_names = unhandled_options.map(&:inspect).join(', ')
212
+ valid_names = valid_keys.map(&:inspect).join(', ')
189
213
  raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}"
190
214
  end
191
215
 
@@ -219,10 +243,10 @@ module Capybara
219
243
  process_class = options.key?(:class) && !custom_keys.include?(:class)
220
244
 
221
245
  if process_id && options[:id].is_a?(XPath::Expression)
222
- raise ArgumentError, "XPath expressions are not supported for the :id filter with CSS based selectors"
246
+ raise ArgumentError, 'XPath expressions are not supported for the :id filter with CSS based selectors'
223
247
  end
224
248
  if process_class && options[:class].is_a?(XPath::Expression)
225
- raise ArgumentError, "XPath expressions are not supported for the :class filter with CSS based selectors"
249
+ raise ArgumentError, 'XPath expressions are not supported for the :class filter with CSS based selectors'
226
250
  end
227
251
 
228
252
  if process_id || process_class
@@ -230,7 +254,7 @@ module Capybara
230
254
  sel += "##{::Capybara::Selector::CSS.escape(options[:id])}" if process_id
231
255
  sel += css_from_classes(Array(options[:class])) if process_class
232
256
  sel
233
- end.join(", ")
257
+ end.join(', ')
234
258
  end
235
259
 
236
260
  expr
@@ -14,7 +14,7 @@ module Capybara
14
14
  end
15
15
  end
16
16
 
17
- def description
17
+ def description(applied = false)
18
18
  desc = super
19
19
  sibling_query = @sibling_node&.instance_variable_get(:@query)
20
20
  desc += " that is a sibling of #{sibling_query.description}" if sibling_query
@@ -50,7 +50,7 @@ module Capybara
50
50
  end
51
51
 
52
52
  def build_message(report_on_invisible)
53
- message = +""
53
+ message = +''
54
54
  unless (COUNT_KEYS & @options.keys).empty?
55
55
  message << " but found #{@count} #{Capybara::Helpers.declension('time', 'times', @count)}"
56
56
  end
@@ -46,9 +46,9 @@ class Capybara::RackTest::Browser
46
46
  driver.redirect_limit.times do
47
47
  if last_response.redirect?
48
48
  if [307, 308].include? last_response.status
49
- process(last_request.request_method, last_response["Location"], last_request.params, env)
49
+ process(last_request.request_method, last_response['Location'], last_request.params, env)
50
50
  else
51
- process(:get, last_response["Location"], {}, env)
51
+ process(:get, last_response['Location'], {}, env)
52
52
  end
53
53
  end
54
54
  end
@@ -61,8 +61,8 @@ class Capybara::RackTest::Browser
61
61
  if path.empty?
62
62
  new_uri.path = request_path
63
63
  else
64
- new_uri.path = request_path if path.start_with?("?")
65
- new_uri.path = "/" if new_uri.path.empty?
64
+ new_uri.path = request_path if path.start_with?('?')
65
+ new_uri.path = '/' if new_uri.path.empty?
66
66
  new_uri.path = request_path.sub(%r{/[^/]*$}, '/') + new_uri.path unless new_uri.path.start_with?('/')
67
67
  end
68
68
  new_uri.scheme ||= @current_scheme
@@ -78,7 +78,7 @@ class Capybara::RackTest::Browser
78
78
  def current_url
79
79
  last_request.url
80
80
  rescue Rack::Test::Error
81
- ""
81
+ ''
82
82
  end
83
83
 
84
84
  def reset_host!
@@ -105,7 +105,7 @@ class Capybara::RackTest::Browser
105
105
  def html
106
106
  last_response.body
107
107
  rescue Rack::Test::Error
108
- ""
108
+ ''
109
109
  end
110
110
 
111
111
  def title
@@ -122,7 +122,7 @@ protected
122
122
  def request_path
123
123
  last_request.path
124
124
  rescue Rack::Test::Error
125
- "/"
125
+ '/'
126
126
  end
127
127
 
128
128
  private
@@ -15,7 +15,7 @@ class Capybara::RackTest::Driver < Capybara::Driver::Base
15
15
  attr_reader :app, :options
16
16
 
17
17
  def initialize(app, **options)
18
- raise ArgumentError, "rack-test requires a rack application, but none was given" unless app
18
+ raise ArgumentError, 'rack-test requires a rack application, but none was given' unless app
19
19
  @session = nil
20
20
  @app = app
21
21
  @options = DEFAULT_OPTIONS.merge(options)
@@ -7,15 +7,15 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
7
7
  # which should probably be provided to Rack::Test in its non-GET request methods.
8
8
  class NilUploadedFile < Rack::Test::UploadedFile
9
9
  def initialize
10
- @empty_file = Tempfile.new("nil_uploaded_file")
10
+ @empty_file = Tempfile.new('nil_uploaded_file')
11
11
  @empty_file.close
12
12
  end
13
13
 
14
- def original_filename; ""; end
15
- def content_type; "application/octet-stream"; end
14
+ def original_filename; ''; end
15
+ def content_type; 'application/octet-stream'; end
16
16
  def path; @empty_file.path; end
17
17
  def size; 0; end
18
- def read; ""; end
18
+ def read; ''; end
19
19
  end
20
20
 
21
21
  def params(button)
@@ -35,7 +35,7 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
35
35
  when 'textarea' then add_textarea_param(field, params)
36
36
  end
37
37
  end
38
- merge_param!(params, button[:name], button[:value] || "") if button[:name]
38
+ merge_param!(params, button[:name], button[:value] || '') if button[:name]
39
39
 
40
40
  params.to_params_hash
41
41
  end
@@ -47,7 +47,7 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
47
47
  end
48
48
 
49
49
  def multipart?
50
- self[:enctype] == "multipart/form-data"
50
+ self[:enctype] == 'multipart/form-data'
51
51
  end
52
52
 
53
53
  private
@@ -107,7 +107,7 @@ private
107
107
 
108
108
  def add_select_param(field, params)
109
109
  if field.has_attribute?('multiple')
110
- field.xpath(".//option[@selected]").each do |option|
110
+ field.xpath('.//option[@selected]').each do |option|
111
111
  merge_param!(params, field['name'], (option['value'] || option.text).to_s)
112
112
  end
113
113
  else
@@ -7,16 +7,16 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
7
7
  native.text
8
8
  .gsub(/[\u200b\u200e\u200f]/, '')
9
9
  .gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
10
- .gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
11
- .gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
10
+ .gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
11
+ .gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
12
12
  .tr("\u00a0", ' ')
13
13
  end
14
14
 
15
15
  def visible_text
16
16
  displayed_text.gsub(/\ +/, ' ')
17
17
  .gsub(/[\ \n]*\n[\ \n]*/, "\n")
18
- .gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
19
- .gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
18
+ .gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
19
+ .gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
20
20
  .tr("\u00a0", ' ')
21
21
  end
22
22
 
@@ -25,7 +25,7 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
25
25
  end
26
26
 
27
27
  def style(_styles)
28
- raise NotImplementedError, "The rack_test driver does not process CSS"
28
+ raise NotImplementedError, 'The rack_test driver does not process CSS'
29
29
  end
30
30
 
31
31
  def value
@@ -51,16 +51,16 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
51
51
  def select_option
52
52
  return if disabled?
53
53
  deselect_options unless select_node.multiple?
54
- native["selected"] = 'selected'
54
+ native['selected'] = 'selected'
55
55
  end
56
56
 
57
57
  def unselect_option
58
- raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box." unless select_node.multiple?
58
+ raise Capybara::UnselectNotAllowed, 'Cannot unselect option from single select box.' unless select_node.multiple?
59
59
  native.remove_attribute('selected')
60
60
  end
61
61
 
62
62
  def click(keys = [], **offset)
63
- raise ArgumentError, "The RackTest driver does not support click options" unless keys.empty? && offset.empty?
63
+ raise ArgumentError, 'The RackTest driver does not support click options' unless keys.empty? && offset.empty?
64
64
 
65
65
  if link?
66
66
  follow_link
@@ -94,9 +94,9 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
94
94
  return true if string_node.disabled?
95
95
 
96
96
  if %w[option optgroup].include? tag_name
97
- find_xpath("parent::*[self::optgroup or self::select or self::datalist]")[0].disabled?
97
+ find_xpath('parent::*[self::optgroup or self::select or self::datalist]')[0].disabled?
98
98
  else
99
- !find_xpath("parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]").empty?
99
+ !find_xpath('parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]').empty?
100
100
  end
101
101
  end
102
102
 
@@ -140,7 +140,7 @@ protected
140
140
  private
141
141
 
142
142
  def deselect_options
143
- select_node.find_xpath(".//option[@selected]").each { |node| node.native.remove_attribute("selected") }
143
+ select_node.find_xpath('.//option[@selected]').each { |node| node.native.remove_attribute('selected') }
144
144
  end
145
145
 
146
146
  def string_node
@@ -166,7 +166,7 @@ private
166
166
 
167
167
  def set_radio(_value) # rubocop:disable Naming/AccessorMethodName
168
168
  other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name) == self[:name]] }.to_s
169
- driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
169
+ driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute('checked') }
170
170
  native['checked'] = 'checked'
171
171
  end
172
172
 
@@ -202,7 +202,7 @@ private
202
202
  end
203
203
 
204
204
  def follow_link
205
- method = self["data-method"] if driver.options[:respect_data_method]
205
+ method = self['data-method'] if driver.options[:respect_data_method]
206
206
  method ||= :get
207
207
  driver.follow(method, self[:href].to_s)
208
208
  end
@@ -211,7 +211,7 @@ private
211
211
  labelled_control = if native[:for]
212
212
  find_xpath("//input[@id='#{native[:for]}']")
213
213
  else
214
- find_xpath(".//input")
214
+ find_xpath('.//input')
215
215
  end.first
216
216
 
217
217
  labelled_control.set(!labelled_control.checked?) if checkbox_or_radio?(labelled_control)
@@ -222,7 +222,7 @@ private
222
222
  end
223
223
 
224
224
  def submits?
225
- (tag_name == 'input' && %w[submit image].include?(type)) || (tag_name == 'button' && [nil, "submit"].include?(type))
225
+ (tag_name == 'input' && %w[submit image].include?(type)) || (tag_name == 'button' && [nil, 'submit'].include?(type))
226
226
  end
227
227
 
228
228
  def checkable?
@@ -252,6 +252,6 @@ protected
252
252
  end
253
253
 
254
254
  def textarea?
255
- tag_name == "textarea"
255
+ tag_name == 'textarea'
256
256
  end
257
257
  end
@@ -3,7 +3,7 @@
3
3
  require 'capybara/dsl'
4
4
 
5
5
  Capybara.app = Rack::Builder.new do
6
- map "/" do
6
+ map '/' do
7
7
  run Rails.application
8
8
  end
9
9
  end.to_app
@@ -123,13 +123,13 @@ module Capybara
123
123
  def failure_message
124
124
  message = @query.failure_message
125
125
  if count.zero?
126
- message << " but there were no matches"
126
+ message << ' but there were no matches'
127
127
  else
128
- message << ", found #{count} #{Capybara::Helpers.declension('match', 'matches', count)}: " << full_results.map(&:text).map(&:inspect).join(", ")
128
+ message << ", found #{count} #{Capybara::Helpers.declension('match', 'matches', count)}: " << full_results.map(&:text).map(&:inspect).join(', ')
129
129
  end
130
130
  unless rest.empty?
131
- elements = rest.map { |el| el.text rescue "<<ERROR>>" }.map(&:inspect).join(", ") # rubocop:disable Style/RescueModifier
132
- message << ". Also found " << elements << ", which matched the selector but not all filters."
131
+ elements = rest.map { |el| el.text rescue '<<ERROR>>' }.map(&:inspect).join(', ') # rubocop:disable Style/RescueModifier
132
+ message << '. Also found ' << elements << ', which matched the selector but not all filters.'
133
133
  end
134
134
  message
135
135
  end
@@ -138,6 +138,10 @@ module Capybara
138
138
  failure_message.sub(/(to find)/, 'not \1')
139
139
  end
140
140
 
141
+ def unfiltered_size
142
+ @elements.length
143
+ end
144
+
141
145
  private
142
146
 
143
147
  def full_results
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- RSpec.shared_context "Capybara Features", capybara_feature: true do
3
+ RSpec.shared_context 'Capybara Features', capybara_feature: true do
4
4
  instance_eval do
5
5
  alias background before
6
6
  alias given let
@@ -10,14 +10,14 @@ end
10
10
 
11
11
  # ensure shared_context is included if default shared_context_metadata_behavior is changed
12
12
  RSpec.configure do |config|
13
- config.include_context "Capybara Features", capybara_feature: true if config.respond_to?(:include_context)
13
+ config.include_context 'Capybara Features', capybara_feature: true if config.respond_to?(:include_context)
14
14
  end
15
15
 
16
16
  RSpec.configure do |config|
17
17
  config.alias_example_group_to :feature, capybara_feature: true, type: :feature
18
- config.alias_example_group_to :xfeature, capybara_feature: true, type: :feature, skip: "Temporarily disabled with xfeature"
18
+ config.alias_example_group_to :xfeature, capybara_feature: true, type: :feature, skip: 'Temporarily disabled with xfeature'
19
19
  config.alias_example_group_to :ffeature, capybara_feature: true, type: :feature, focus: true
20
20
  config.alias_example_to :scenario
21
- config.alias_example_to :xscenario, skip: "Temporarily disabled with xscenario"
21
+ config.alias_example_to :xscenario, skip: 'Temporarily disabled with xscenario'
22
22
  config.alias_example_to :fscenario, focus: true
23
23
  end
@@ -89,11 +89,11 @@ module Capybara
89
89
  end
90
90
 
91
91
  def does_not_match?(_actual)
92
- raise ArgumentError, "The have_all_selectors matcher does not support use with not_to/should_not"
92
+ raise ArgumentError, 'The have_all_selectors matcher does not support use with not_to/should_not'
93
93
  end
94
94
 
95
95
  def description
96
- "have all selectors"
96
+ 'have all selectors'
97
97
  end
98
98
  end
99
99
 
@@ -108,11 +108,11 @@ module Capybara
108
108
  end
109
109
 
110
110
  def does_not_match?(_actual)
111
- raise ArgumentError, "The have_none_of_selectors matcher does not support use with not_to/should_not"
111
+ raise ArgumentError, 'The have_none_of_selectors matcher does not support use with not_to/should_not'
112
112
  end
113
113
 
114
114
  def description
115
- "have no selectors"
115
+ 'have no selectors'
116
116
  end
117
117
  end
118
118
 
@@ -235,11 +235,11 @@ module Capybara
235
235
  end
236
236
 
237
237
  def does_not_match?(_actual)
238
- raise ArgumentError, "The have_style matcher does not support use with not_to/should_not"
238
+ raise ArgumentError, 'The have_style matcher does not support use with not_to/should_not'
239
239
  end
240
240
 
241
241
  def description
242
- "have style"
242
+ 'have style'
243
243
  end
244
244
  end
245
245