capybara 3.29.0 → 3.31.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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +40 -1
  3. data/README.md +1 -1
  4. data/lib/capybara/config.rb +7 -3
  5. data/lib/capybara/dsl.rb +10 -2
  6. data/lib/capybara/helpers.rb +3 -1
  7. data/lib/capybara/minitest.rb +18 -4
  8. data/lib/capybara/node/actions.rb +23 -19
  9. data/lib/capybara/node/document.rb +2 -2
  10. data/lib/capybara/node/document_matchers.rb +3 -3
  11. data/lib/capybara/node/element.rb +21 -16
  12. data/lib/capybara/node/finders.rb +17 -11
  13. data/lib/capybara/node/matchers.rb +60 -45
  14. data/lib/capybara/node/simple.rb +4 -2
  15. data/lib/capybara/queries/ancestor_query.rb +1 -1
  16. data/lib/capybara/queries/base_query.rb +2 -1
  17. data/lib/capybara/queries/selector_query.rb +17 -4
  18. data/lib/capybara/queries/sibling_query.rb +1 -1
  19. data/lib/capybara/rack_test/browser.rb +4 -1
  20. data/lib/capybara/rack_test/driver.rb +1 -1
  21. data/lib/capybara/rack_test/form.rb +1 -1
  22. data/lib/capybara/rack_test/node.rb +34 -9
  23. data/lib/capybara/result.rb +24 -4
  24. data/lib/capybara/rspec/matchers.rb +27 -27
  25. data/lib/capybara/rspec/matchers/base.rb +12 -6
  26. data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
  27. data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
  28. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  29. data/lib/capybara/rspec/matchers/have_selector.rb +15 -7
  30. data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
  31. data/lib/capybara/rspec/matchers/have_text.rb +2 -2
  32. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  33. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  34. data/lib/capybara/rspec/matchers/match_style.rb +2 -2
  35. data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
  36. data/lib/capybara/selector.rb +24 -16
  37. data/lib/capybara/selector/css.rb +1 -1
  38. data/lib/capybara/selector/definition.rb +2 -2
  39. data/lib/capybara/selector/definition/button.rb +7 -2
  40. data/lib/capybara/selector/definition/checkbox.rb +2 -2
  41. data/lib/capybara/selector/definition/css.rb +3 -1
  42. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  43. data/lib/capybara/selector/definition/datalist_option.rb +1 -1
  44. data/lib/capybara/selector/definition/element.rb +1 -1
  45. data/lib/capybara/selector/definition/field.rb +1 -1
  46. data/lib/capybara/selector/definition/file_field.rb +1 -1
  47. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  48. data/lib/capybara/selector/definition/label.rb +4 -2
  49. data/lib/capybara/selector/definition/radio_button.rb +2 -2
  50. data/lib/capybara/selector/definition/select.rb +32 -13
  51. data/lib/capybara/selector/definition/table.rb +5 -2
  52. data/lib/capybara/selector/filter_set.rb +11 -9
  53. data/lib/capybara/selector/filters/base.rb +6 -1
  54. data/lib/capybara/selector/filters/locator_filter.rb +1 -1
  55. data/lib/capybara/selector/selector.rb +4 -2
  56. data/lib/capybara/selenium/driver.rb +19 -11
  57. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
  58. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +2 -2
  59. data/lib/capybara/selenium/extensions/html5_drag.rb +30 -13
  60. data/lib/capybara/selenium/node.rb +29 -10
  61. data/lib/capybara/selenium/nodes/chrome_node.rb +11 -5
  62. data/lib/capybara/selenium/nodes/edge_node.rb +4 -2
  63. data/lib/capybara/selenium/nodes/firefox_node.rb +2 -2
  64. data/lib/capybara/server.rb +15 -3
  65. data/lib/capybara/server/checker.rb +1 -1
  66. data/lib/capybara/server/middleware.rb +20 -10
  67. data/lib/capybara/session.rb +40 -23
  68. data/lib/capybara/session/config.rb +6 -2
  69. data/lib/capybara/session/matchers.rb +6 -6
  70. data/lib/capybara/spec/public/test.js +51 -6
  71. data/lib/capybara/spec/session/all_spec.rb +60 -5
  72. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  73. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  74. data/lib/capybara/spec/session/click_button_spec.rb +5 -0
  75. data/lib/capybara/spec/session/fill_in_spec.rb +20 -0
  76. data/lib/capybara/spec/session/find_spec.rb +20 -0
  77. data/lib/capybara/spec/session/has_css_spec.rb +3 -3
  78. data/lib/capybara/spec/session/has_select_spec.rb +28 -0
  79. data/lib/capybara/spec/session/has_table_spec.rb +51 -5
  80. data/lib/capybara/spec/session/has_text_spec.rb +35 -0
  81. data/lib/capybara/spec/session/node_spec.rb +106 -2
  82. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  83. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  84. data/lib/capybara/spec/session/selectors_spec.rb +15 -2
  85. data/lib/capybara/spec/views/form.erb +11 -1
  86. data/lib/capybara/version.rb +1 -1
  87. data/spec/dsl_spec.rb +2 -2
  88. data/spec/minitest_spec_spec.rb +46 -46
  89. data/spec/rack_test_spec.rb +0 -1
  90. data/spec/regexp_dissassembler_spec.rb +45 -37
  91. data/spec/result_spec.rb +7 -3
  92. data/spec/rspec/features_spec.rb +1 -0
  93. data/spec/rspec/shared_spec_matchers.rb +3 -3
  94. data/spec/rspec_spec.rb +4 -4
  95. data/spec/selenium_spec_chrome.rb +5 -4
  96. data/spec/selenium_spec_firefox.rb +7 -2
  97. data/spec/server_spec.rb +42 -0
  98. data/spec/session_spec.rb +1 -1
  99. data/spec/shared_selenium_node.rb +3 -3
  100. data/spec/shared_selenium_session.rb +8 -7
  101. metadata +3 -3
@@ -108,7 +108,9 @@ module Capybara
108
108
  !find_xpath(VISIBILITY_XPATH)
109
109
  else
110
110
  # No need for an xpath if only checking the current element
111
- !(native.key?('hidden') || (/display:\s?none/.match? native[:style]) || %w[script head].include?(tag_name))
111
+ !(native.key?('hidden') ||
112
+ /display:\s?none/.match?(native[:style] || '') ||
113
+ %w[script head].include?(tag_name))
112
114
  end
113
115
  end
114
116
 
@@ -150,7 +152,7 @@ module Capybara
150
152
  yield # simple nodes don't need to wait
151
153
  end
152
154
 
153
- def allow_reload!
155
+ def allow_reload!(*)
154
156
  # no op
155
157
  end
156
158
 
@@ -12,7 +12,7 @@ module Capybara
12
12
  ancestors = node.find_xpath(XPath.ancestor.to_s)
13
13
  .map(&method(:to_element))
14
14
  .select { |el| match_results.include?(el) }
15
- Capybara::Result.new(ancestors, self)
15
+ Capybara::Result.new(ordered_results(ancestors), self)
16
16
  end
17
17
  end
18
18
 
@@ -79,7 +79,8 @@ module Capybara
79
79
  if count
80
80
  message << " #{occurrences count}"
81
81
  elsif between
82
- message << " between #{between.first} and #{between.end ? between.last : 'infinite'} times"
82
+ message << " between #{between.begin ? between.first : 1} and" \
83
+ " #{between.end ? between.last : 'infinite'} times"
83
84
  elsif maximum
84
85
  message << " at most #{occurrences maximum}"
85
86
  elsif minimum
@@ -16,11 +16,13 @@ module Capybara
16
16
  enable_aria_label: session_options.enable_aria_label,
17
17
  test_id: session_options.test_id,
18
18
  selector_format: nil,
19
+ order: nil,
19
20
  **options,
20
21
  &filter_block)
21
22
  @resolved_node = nil
22
23
  @resolved_count = 0
23
24
  @options = options.dup
25
+ @order = order
24
26
  @filter_cache = Hash.new { |hsh, key| hsh[key] = {} }
25
27
 
26
28
  super(@options)
@@ -37,7 +39,7 @@ module Capybara
37
39
 
38
40
  raise ArgumentError, "Unused parameters passed to #{self.class.name} : #{args}" unless args.empty?
39
41
 
40
- @expression = selector.call(@locator, @options)
42
+ @expression = selector.call(@locator, **@options)
41
43
 
42
44
  warn_exact_usage
43
45
 
@@ -77,7 +79,9 @@ module Capybara
77
79
  end
78
80
 
79
81
  %i[above below left_of right_of near].each do |spatial_filter|
80
- desc << " #{spatial_filter} #{options[spatial_filter] rescue '<ERROR>'}" if options[spatial_filter] && show_for[:spatial] # rubocop:disable Style/RescueModifier
82
+ if options[spatial_filter] && show_for[:spatial]
83
+ desc << " #{spatial_filter} #{options[spatial_filter] rescue '<ERROR>'}" # rubocop:disable Style/RescueModifier
84
+ end
81
85
  end
82
86
 
83
87
  desc << selector.description(node_filters: show_for[:node], **options)
@@ -148,7 +152,7 @@ module Capybara
148
152
 
149
153
  node.synchronize do
150
154
  children = find_nodes_by_selector_format(node, exact).map(&method(:to_element))
151
- Capybara::Result.new(children, self)
155
+ Capybara::Result.new(ordered_results(children), self)
152
156
  end
153
157
  end
154
158
 
@@ -311,6 +315,15 @@ module Capybara
311
315
  filters
312
316
  end
313
317
 
318
+ def ordered_results(results)
319
+ case @order
320
+ when :reverse
321
+ results.reverse
322
+ else
323
+ results
324
+ end
325
+ end
326
+
314
327
  def custom_keys
315
328
  @custom_keys ||= node_filters.keys + expression_filters.keys
316
329
  end
@@ -338,7 +351,7 @@ module Capybara
338
351
  conditions[:id] = options[:id] if use_default_id_filter?
339
352
  conditions[:class] = options[:class] if use_default_class_filter?
340
353
  conditions[:style] = options[:style] if use_default_style_filter? && !options[:style].is_a?(Hash)
341
- builder(expr).add_attribute_conditions(conditions)
354
+ builder(expr).add_attribute_conditions(**conditions)
342
355
  end
343
356
 
344
357
  def use_default_id_filter?
@@ -11,7 +11,7 @@ module Capybara
11
11
  siblings = node.find_xpath((XPath.preceding_sibling + XPath.following_sibling).to_s)
12
12
  .map(&method(:to_element))
13
13
  .select { |el| match_results.include?(el) }
14
- Capybara::Result.new(siblings, self)
14
+ Capybara::Result.new(ordered_results(siblings), self)
15
15
  end
16
16
  end
17
17
 
@@ -53,7 +53,10 @@ class Capybara::RackTest::Browser
53
53
  end
54
54
  end
55
55
  end
56
- raise Capybara::InfiniteRedirectError, "redirected more than #{driver.redirect_limit} times, check for infinite redirects." if last_response.redirect?
56
+
57
+ if last_response.redirect? # rubocop:disable Style/GuardClause
58
+ raise Capybara::InfiniteRedirectError, "redirected more than #{driver.redirect_limit} times, check for infinite redirects."
59
+ end
57
60
  end
58
61
 
59
62
  def process(method, path, attributes = {}, env = {})
@@ -42,7 +42,7 @@ class Capybara::RackTest::Driver < Capybara::Driver::Base
42
42
  end
43
43
 
44
44
  def visit(path, **attributes)
45
- browser.visit(path, attributes)
45
+ browser.visit(path, **attributes)
46
46
  end
47
47
 
48
48
  def refresh
@@ -56,7 +56,7 @@ private
56
56
  end
57
57
 
58
58
  def request_method
59
- /post/i.match?(self[:method]) ? :post : :get
59
+ /post/i.match?(self[:method] || '') ? :post : :get
60
60
  end
61
61
 
62
62
  def merge_param!(params, key, value)
@@ -45,6 +45,7 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
45
45
 
46
46
  if radio? then set_radio(value)
47
47
  elsif checkbox? then set_checkbox(value)
48
+ elsif range? then set_range(value)
48
49
  elsif input_field? then set_input(value)
49
50
  elsif textarea? then native['_capybara_raw_value'] = value.to_s
50
51
  end
@@ -76,8 +77,8 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
76
77
  set(!checked?)
77
78
  elsif tag_name == 'label'
78
79
  click_label
79
- elsif tag_name == 'details'
80
- toggle_details
80
+ elsif (details = native.xpath('.//ancestor-or-self::details').last)
81
+ toggle_details(details)
81
82
  end
82
83
  end
83
84
 
@@ -123,9 +124,18 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
123
124
  alias_method "unchecked_#{meth_name}", meth_name
124
125
  private "unchecked_#{meth_name}" # rubocop:disable Style/AccessModifierDeclarations
125
126
 
126
- define_method meth_name do |*args|
127
- stale_check
128
- send("unchecked_#{meth_name}", *args)
127
+ if RUBY_VERSION >= '2.7'
128
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
129
+ def #{meth_name}(...)
130
+ stale_check
131
+ method(:"unchecked_#{meth_name}").call(...)
132
+ end
133
+ METHOD
134
+ else
135
+ define_method meth_name do |*args|
136
+ stale_check
137
+ send("unchecked_#{meth_name}", *args)
138
+ end
129
139
  end
130
140
  end
131
141
 
@@ -199,6 +209,14 @@ private
199
209
  end
200
210
  end
201
211
 
212
+ def set_range(value) # rubocop:disable Naming/AccessorMethodName
213
+ min, max, step = (native['min'] || 0).to_f, (native['max'] || 100).to_f, (native['step'] || 1).to_f
214
+ value = value.to_f
215
+ value = value.clamp(min, max)
216
+ value = ((value - min) / step).round * step + min
217
+ native['value'] = value.clamp(min, max)
218
+ end
219
+
202
220
  def set_input(value) # rubocop:disable Naming/AccessorMethodName
203
221
  if text_or_password? && attribute_is_not_blank?(:maxlength)
204
222
  # Browser behavior for maxlength="0" is inconsistent, so we stick with
@@ -238,11 +256,14 @@ private
238
256
  labelled_control.set(!labelled_control.checked?) if checkbox_or_radio?(labelled_control)
239
257
  end
240
258
 
241
- def toggle_details
242
- if native.has_attribute?('open')
243
- native.remove_attribute('open')
259
+ def toggle_details(details = nil)
260
+ details ||= native.xpath('.//ancestor-or-self::details').last
261
+ return unless details
262
+
263
+ if details.has_attribute?('open')
264
+ details.remove_attribute('open')
244
265
  else
245
- native.set_attribute('open', 'open')
266
+ details.set_attribute('open', 'open')
246
267
  end
247
268
  end
248
269
 
@@ -284,6 +305,10 @@ protected
284
305
  tag_name == 'textarea'
285
306
  end
286
307
 
308
+ def range?
309
+ input_field? && type == 'range'
310
+ end
311
+
287
312
  OPTION_OWNER_XPATH = XPath.parent(:optgroup, :select, :datalist).to_s.freeze
288
313
  DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
289
314
  x.parent(:fieldset)[
@@ -31,6 +31,7 @@ module Capybara
31
31
  @filter_errors = []
32
32
  @results_enum = lazy_select_elements { |node| query.matches_filters?(node, @filter_errors) }
33
33
  @query = query
34
+ @allow_reload = false
34
35
  end
35
36
 
36
37
  def_delegators :full_results, :size, :length, :last, :values_at, :inspect, :sample
@@ -43,7 +44,7 @@ module Capybara
43
44
  @result_cache.each(&block)
44
45
  loop do
45
46
  next_result = @results_enum.next
46
- @result_cache << next_result
47
+ add_to_cache(next_result)
47
48
  yield next_result
48
49
  end
49
50
  self
@@ -59,7 +60,11 @@ module Capybara
59
60
  nil
60
61
  end
61
62
  when Range
62
- idx.end && idx.max # endless range will have end == nil
63
+ # idx.max is broken with beginless ranges
64
+ # idx.end && idx.max # endless range will have end == nil
65
+ max = idx.end
66
+ max -= 1 if max && idx.exclude_end?
67
+ max
63
68
  end
64
69
 
65
70
  if max_idx.nil?
@@ -94,7 +99,9 @@ module Capybara
94
99
  end
95
100
 
96
101
  if between
97
- min, max = between.min, (between.end && between.max)
102
+ min, max = (between.begin && between.min) || 1, between.end
103
+ max -= 1 if max && between.exclude_end?
104
+
98
105
  size = load_up_to(max ? max + 1 : min)
99
106
  return size <=> min unless between.include?(size)
100
107
  end
@@ -130,13 +137,26 @@ module Capybara
130
137
  @elements.length
131
138
  end
132
139
 
140
+ ##
141
+ # @api private
142
+ #
143
+ def allow_reload!
144
+ @allow_reload = true
145
+ self
146
+ end
147
+
133
148
  private
134
149
 
150
+ def add_to_cache(elem)
151
+ elem.allow_reload!(@result_cache.size) if @allow_reload
152
+ @result_cache << elem
153
+ end
154
+
135
155
  def load_up_to(num)
136
156
  loop do
137
157
  break if @result_cache.size >= num
138
158
 
139
- @result_cache << @results_enum.next
159
+ add_to_cache(@results_enum.next)
140
160
  end
141
161
  @result_cache.size
142
162
  end
@@ -15,45 +15,45 @@ module Capybara
15
15
  # RSpec matcher for whether the element(s) matching a given selector exist.
16
16
  #
17
17
  # @see Capybara::Node::Matchers#assert_selector
18
- def have_selector(*args, &optional_filter_block)
19
- Matchers::HaveSelector.new(*args, &optional_filter_block)
18
+ def have_selector(*args, **kw_args, &optional_filter_block)
19
+ Matchers::HaveSelector.new(*args, **kw_args, &optional_filter_block)
20
20
  end
21
21
 
22
22
  # RSpec matcher for whether the element(s) matching a group of selectors exist.
23
23
  #
24
24
  # @see Capybara::Node::Matchers#assert_all_of_selectors
25
- def have_all_of_selectors(*args, &optional_filter_block)
26
- Matchers::HaveAllSelectors.new(*args, &optional_filter_block)
25
+ def have_all_of_selectors(*args, **kw_args, &optional_filter_block)
26
+ Matchers::HaveAllSelectors.new(*args, **kw_args, &optional_filter_block)
27
27
  end
28
28
 
29
29
  # RSpec matcher for whether no element(s) matching a group of selectors exist.
30
30
  #
31
31
  # @see Capybara::Node::Matchers#assert_none_of_selectors
32
- def have_none_of_selectors(*args, &optional_filter_block)
33
- Matchers::HaveNoSelectors.new(*args, &optional_filter_block)
32
+ def have_none_of_selectors(*args, **kw_args, &optional_filter_block)
33
+ Matchers::HaveNoSelectors.new(*args, **kw_args, &optional_filter_block)
34
34
  end
35
35
 
36
36
  # RSpec matcher for whether the element(s) matching any of a group of selectors exist.
37
37
  #
38
38
  # @see Capybara::Node::Matchers#assert_any_of_selectors
39
- def have_any_of_selectors(*args, &optional_filter_block)
40
- Matchers::HaveAnySelectors.new(*args, &optional_filter_block)
39
+ def have_any_of_selectors(*args, **kw_args, &optional_filter_block)
40
+ Matchers::HaveAnySelectors.new(*args, **kw_args, &optional_filter_block)
41
41
  end
42
42
 
43
43
  # RSpec matcher for whether the current element matches a given selector.
44
44
  #
45
45
  # @see Capybara::Node::Matchers#assert_matches_selector
46
- def match_selector(*args, &optional_filter_block)
47
- Matchers::MatchSelector.new(*args, &optional_filter_block)
46
+ def match_selector(*args, **kw_args, &optional_filter_block)
47
+ Matchers::MatchSelector.new(*args, **kw_args, &optional_filter_block)
48
48
  end
49
49
 
50
50
  %i[css xpath].each do |selector|
51
51
  define_method "have_#{selector}" do |expr, **options, &optional_filter_block|
52
- Matchers::HaveSelector.new(selector, expr, options, &optional_filter_block)
52
+ Matchers::HaveSelector.new(selector, expr, **options, &optional_filter_block)
53
53
  end
54
54
 
55
55
  define_method "match_#{selector}" do |expr, **options, &optional_filter_block|
56
- Matchers::MatchSelector.new(selector, expr, options, &optional_filter_block)
56
+ Matchers::MatchSelector.new(selector, expr, **options, &optional_filter_block)
57
57
  end
58
58
  end
59
59
 
@@ -79,7 +79,7 @@ module Capybara
79
79
 
80
80
  %i[link button field select table].each do |selector|
81
81
  define_method "have_#{selector}" do |locator = nil, **options, &optional_filter_block|
82
- Matchers::HaveSelector.new(selector, locator, options, &optional_filter_block)
82
+ Matchers::HaveSelector.new(selector, locator, **options, &optional_filter_block)
83
83
  end
84
84
  end
85
85
 
@@ -110,7 +110,7 @@ module Capybara
110
110
 
111
111
  %i[checked unchecked].each do |state|
112
112
  define_method "have_#{state}_field" do |locator = nil, **options, &optional_filter_block|
113
- Matchers::HaveSelector.new(:field, locator, options.merge(state => true), &optional_filter_block)
113
+ Matchers::HaveSelector.new(:field, locator, **options.merge(state => true), &optional_filter_block)
114
114
  end
115
115
  end
116
116
 
@@ -127,27 +127,27 @@ module Capybara
127
127
  # RSpec matcher for text content.
128
128
  #
129
129
  # @see Capybara::Node::Matchers#assert_text
130
- def have_text(*args)
131
- Matchers::HaveText.new(*args)
130
+ def have_text(text_or_type, *args, **options)
131
+ Matchers::HaveText.new(text_or_type, *args, **options)
132
132
  end
133
133
  alias_method :have_content, :have_text
134
134
 
135
135
  def have_title(title, **options)
136
- Matchers::HaveTitle.new(title, options)
136
+ Matchers::HaveTitle.new(title, **options)
137
137
  end
138
138
 
139
139
  # RSpec matcher for the current path.
140
140
  #
141
141
  # @see Capybara::SessionMatchers#assert_current_path
142
142
  def have_current_path(path, **options)
143
- Matchers::HaveCurrentPath.new(path, options)
143
+ Matchers::HaveCurrentPath.new(path, **options)
144
144
  end
145
145
 
146
146
  # RSpec matcher for element style.
147
147
  #
148
148
  # @see Capybara::Node::Matchers#matches_style?
149
149
  def match_style(styles, **options)
150
- Matchers::MatchStyle.new(styles, options)
150
+ Matchers::MatchStyle.new(styles, **options)
151
151
  end
152
152
 
153
153
  ##
@@ -161,30 +161,30 @@ module Capybara
161
161
  %w[selector css xpath text title current_path link button
162
162
  field checked_field unchecked_field select table
163
163
  sibling ancestor].each do |matcher_type|
164
- define_method "have_no_#{matcher_type}" do |*args, &optional_filter_block|
165
- Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, &optional_filter_block))
164
+ define_method "have_no_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
165
+ Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, **kw_args, &optional_filter_block))
166
166
  end
167
167
  end
168
168
  alias_method :have_no_content, :have_no_text
169
169
 
170
170
  %w[selector css xpath].each do |matcher_type|
171
- define_method "not_match_#{matcher_type}" do |*args, &optional_filter_block|
172
- Matchers::NegatedMatcher.new(send("match_#{matcher_type}", *args, &optional_filter_block))
171
+ define_method "not_match_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
172
+ Matchers::NegatedMatcher.new(send("match_#{matcher_type}", *args, **kw_args, &optional_filter_block))
173
173
  end
174
174
  end
175
175
 
176
176
  # RSpec matcher for whether sibling element(s) matching a given selector exist.
177
177
  #
178
178
  # @see Capybara::Node::Matchers#assert_sibling
179
- def have_sibling(*args, &optional_filter_block)
180
- Matchers::HaveSibling.new(*args, &optional_filter_block)
179
+ def have_sibling(*args, **kw_args, &optional_filter_block)
180
+ Matchers::HaveSibling.new(*args, **kw_args, &optional_filter_block)
181
181
  end
182
182
 
183
183
  # RSpec matcher for whether ancestor element(s) matching a given selector exist.
184
184
  #
185
185
  # @see Capybara::Node::Matchers#assert_ancestor
186
- def have_ancestor(*args, &optional_filter_block)
187
- Matchers::HaveAncestor.new(*args, &optional_filter_block)
186
+ def have_ancestor(*args, **kw_args, &optional_filter_block)
187
+ Matchers::HaveAncestor.new(*args, **kw_args, &optional_filter_block)
188
188
  end
189
189
 
190
190
  ##
@@ -12,22 +12,28 @@ module Capybara
12
12
 
13
13
  attr_reader :failure_message, :failure_message_when_negated
14
14
 
15
- def initialize(*args, &filter_block)
15
+ def initialize(*args, **kw_args, &filter_block)
16
16
  @args = args.dup
17
+ @kw_args = kw_args || {}
17
18
  @filter_block = filter_block
18
19
  end
19
20
 
20
21
  private
21
22
 
22
23
  def session_query_args
23
- if @args.last.is_a? Hash
24
- @args.last[:session_options] = session_options
25
- else
26
- @args.push(session_options: session_options)
27
- end
24
+ # if @args.last.is_a? Hash
25
+ # @args.last[:session_options] = session_options
26
+ # else
27
+ # @args.push(session_options: session_options)
28
+ # end
28
29
  @args
29
30
  end
30
31
 
32
+ def session_query_options
33
+ @kw_args[:session_options] = session_options
34
+ @kw_args
35
+ end
36
+
31
37
  def session_options
32
38
  @context_el ||= nil
33
39
  if @context_el.respond_to? :session_options