capybara 3.23.0 → 3.35.3

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 (183) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +264 -11
  3. data/README.md +10 -6
  4. data/lib/capybara.rb +20 -8
  5. data/lib/capybara/config.rb +10 -8
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/driver/base.rb +4 -0
  8. data/lib/capybara/driver/node.rb +4 -0
  9. data/lib/capybara/dsl.rb +10 -2
  10. data/lib/capybara/helpers.rb +28 -2
  11. data/lib/capybara/minitest.rb +232 -144
  12. data/lib/capybara/minitest/spec.rb +156 -97
  13. data/lib/capybara/node/actions.rb +36 -36
  14. data/lib/capybara/node/base.rb +6 -6
  15. data/lib/capybara/node/document.rb +2 -2
  16. data/lib/capybara/node/document_matchers.rb +3 -3
  17. data/lib/capybara/node/element.rb +77 -33
  18. data/lib/capybara/node/finders.rb +24 -17
  19. data/lib/capybara/node/matchers.rb +79 -64
  20. data/lib/capybara/node/simple.rb +11 -4
  21. data/lib/capybara/queries/ancestor_query.rb +6 -10
  22. data/lib/capybara/queries/base_query.rb +2 -1
  23. data/lib/capybara/queries/current_path_query.rb +14 -4
  24. data/lib/capybara/queries/selector_query.rb +259 -23
  25. data/lib/capybara/queries/sibling_query.rb +5 -11
  26. data/lib/capybara/queries/style_query.rb +1 -1
  27. data/lib/capybara/queries/text_query.rb +13 -1
  28. data/lib/capybara/rack_test/browser.rb +13 -4
  29. data/lib/capybara/rack_test/driver.rb +2 -1
  30. data/lib/capybara/rack_test/form.rb +2 -2
  31. data/lib/capybara/rack_test/node.rb +42 -6
  32. data/lib/capybara/registration_container.rb +44 -0
  33. data/lib/capybara/registrations/drivers.rb +18 -12
  34. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  35. data/lib/capybara/registrations/servers.rb +9 -2
  36. data/lib/capybara/result.rb +39 -19
  37. data/lib/capybara/rspec.rb +2 -0
  38. data/lib/capybara/rspec/matcher_proxies.rb +5 -5
  39. data/lib/capybara/rspec/matchers.rb +97 -74
  40. data/lib/capybara/rspec/matchers/base.rb +19 -6
  41. data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
  42. data/lib/capybara/rspec/matchers/have_ancestor.rb +5 -7
  43. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  44. data/lib/capybara/rspec/matchers/have_selector.rb +15 -10
  45. data/lib/capybara/rspec/matchers/have_sibling.rb +4 -7
  46. data/lib/capybara/rspec/matchers/have_text.rb +4 -7
  47. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  48. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  49. data/lib/capybara/rspec/matchers/match_style.rb +7 -2
  50. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  51. data/lib/capybara/selector.rb +46 -19
  52. data/lib/capybara/selector/builders/css_builder.rb +10 -6
  53. data/lib/capybara/selector/builders/xpath_builder.rb +4 -2
  54. data/lib/capybara/selector/css.rb +1 -1
  55. data/lib/capybara/selector/definition.rb +13 -11
  56. data/lib/capybara/selector/definition/button.rb +32 -15
  57. data/lib/capybara/selector/definition/checkbox.rb +2 -2
  58. data/lib/capybara/selector/definition/css.rb +3 -1
  59. data/lib/capybara/selector/definition/datalist_input.rb +2 -2
  60. data/lib/capybara/selector/definition/datalist_option.rb +1 -1
  61. data/lib/capybara/selector/definition/element.rb +3 -2
  62. data/lib/capybara/selector/definition/field.rb +1 -1
  63. data/lib/capybara/selector/definition/file_field.rb +1 -1
  64. data/lib/capybara/selector/definition/fillable_field.rb +2 -2
  65. data/lib/capybara/selector/definition/label.rb +5 -3
  66. data/lib/capybara/selector/definition/link.rb +8 -0
  67. data/lib/capybara/selector/definition/option.rb +1 -1
  68. data/lib/capybara/selector/definition/radio_button.rb +2 -2
  69. data/lib/capybara/selector/definition/select.rb +33 -14
  70. data/lib/capybara/selector/definition/table.rb +6 -3
  71. data/lib/capybara/selector/definition/table_row.rb +2 -2
  72. data/lib/capybara/selector/filter_set.rb +13 -11
  73. data/lib/capybara/selector/filters/base.rb +6 -1
  74. data/lib/capybara/selector/filters/locator_filter.rb +1 -1
  75. data/lib/capybara/selector/regexp_disassembler.rb +7 -0
  76. data/lib/capybara/selector/selector.rb +13 -3
  77. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
  78. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -1
  79. data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
  80. data/lib/capybara/selenium/atoms/src/isDisplayed.js +10 -10
  81. data/lib/capybara/selenium/driver.rb +86 -24
  82. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +24 -21
  83. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +21 -19
  84. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +17 -1
  85. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +0 -4
  86. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  87. data/lib/capybara/selenium/extensions/find.rb +37 -26
  88. data/lib/capybara/selenium/extensions/html5_drag.rb +55 -11
  89. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  90. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  91. data/lib/capybara/selenium/logger_suppressor.rb +8 -2
  92. data/lib/capybara/selenium/node.rb +160 -40
  93. data/lib/capybara/selenium/nodes/chrome_node.rb +72 -12
  94. data/lib/capybara/selenium/nodes/edge_node.rb +32 -14
  95. data/lib/capybara/selenium/nodes/firefox_node.rb +28 -32
  96. data/lib/capybara/selenium/nodes/safari_node.rb +5 -29
  97. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  98. data/lib/capybara/selenium/patches/atoms.rb +4 -4
  99. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  100. data/lib/capybara/selenium/patches/logs.rb +32 -7
  101. data/lib/capybara/server.rb +19 -3
  102. data/lib/capybara/server/animation_disabler.rb +8 -3
  103. data/lib/capybara/server/checker.rb +1 -1
  104. data/lib/capybara/server/middleware.rb +22 -10
  105. data/lib/capybara/session.rb +66 -40
  106. data/lib/capybara/session/config.rb +11 -3
  107. data/lib/capybara/session/matchers.rb +11 -11
  108. data/lib/capybara/spec/public/offset.js +6 -0
  109. data/lib/capybara/spec/public/test.js +75 -7
  110. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  111. data/lib/capybara/spec/session/all_spec.rb +60 -5
  112. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  113. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  114. data/lib/capybara/spec/session/check_spec.rb +6 -0
  115. data/lib/capybara/spec/session/click_button_spec.rb +16 -0
  116. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  117. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  118. data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
  119. data/lib/capybara/spec/session/find_spec.rb +55 -0
  120. data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -0
  121. data/lib/capybara/spec/session/has_button_spec.rb +51 -0
  122. data/lib/capybara/spec/session/has_css_spec.rb +26 -4
  123. data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
  124. data/lib/capybara/spec/session/has_field_spec.rb +34 -0
  125. data/lib/capybara/spec/session/has_select_spec.rb +32 -4
  126. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  127. data/lib/capybara/spec/session/has_table_spec.rb +51 -5
  128. data/lib/capybara/spec/session/has_text_spec.rb +30 -0
  129. data/lib/capybara/spec/session/html_spec.rb +1 -1
  130. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  131. data/lib/capybara/spec/session/node_spec.rb +394 -9
  132. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  133. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  134. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  135. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -15
  136. data/lib/capybara/spec/session/selectors_spec.rb +16 -3
  137. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  138. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  139. data/lib/capybara/spec/session/window/window_spec.rb +8 -8
  140. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  141. data/lib/capybara/spec/spec_helper.rb +14 -14
  142. data/lib/capybara/spec/test_app.rb +27 -21
  143. data/lib/capybara/spec/views/form.erb +47 -4
  144. data/lib/capybara/spec/views/offset.erb +32 -0
  145. data/lib/capybara/spec/views/spatial.erb +31 -0
  146. data/lib/capybara/spec/views/with_animation.erb +37 -1
  147. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  148. data/lib/capybara/spec/views/with_html.erb +24 -2
  149. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  150. data/lib/capybara/spec/views/with_js.erb +4 -1
  151. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  152. data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
  153. data/lib/capybara/version.rb +1 -1
  154. data/lib/capybara/window.rb +3 -7
  155. data/spec/basic_node_spec.rb +15 -14
  156. data/spec/capybara_spec.rb +28 -28
  157. data/spec/dsl_spec.rb +16 -3
  158. data/spec/filter_set_spec.rb +5 -5
  159. data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
  160. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  161. data/spec/minitest_spec.rb +3 -2
  162. data/spec/minitest_spec_spec.rb +46 -46
  163. data/spec/rack_test_spec.rb +38 -15
  164. data/spec/regexp_dissassembler_spec.rb +52 -38
  165. data/spec/result_spec.rb +43 -32
  166. data/spec/rspec/features_spec.rb +4 -1
  167. data/spec/rspec/scenarios_spec.rb +4 -0
  168. data/spec/rspec/shared_spec_matchers.rb +68 -56
  169. data/spec/rspec_spec.rb +9 -5
  170. data/spec/selector_spec.rb +32 -17
  171. data/spec/selenium_spec_chrome.rb +78 -11
  172. data/spec/selenium_spec_chrome_remote.rb +23 -6
  173. data/spec/selenium_spec_edge.rb +15 -12
  174. data/spec/selenium_spec_firefox.rb +24 -19
  175. data/spec/selenium_spec_firefox_remote.rb +0 -8
  176. data/spec/selenium_spec_ie.rb +1 -6
  177. data/spec/server_spec.rb +106 -44
  178. data/spec/session_spec.rb +5 -5
  179. data/spec/shared_selenium_node.rb +56 -2
  180. data/spec/shared_selenium_session.rb +122 -15
  181. data/spec/spec_helper.rb +2 -2
  182. metadata +63 -17
  183. data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -103,19 +103,19 @@ module Capybara
103
103
 
104
104
  # @api private
105
105
  def find_css(css, **options)
106
- if base.method(:find_css).arity != 1
107
- base.find_css(css, **options)
108
- else
106
+ if base.method(:find_css).arity == 1
109
107
  base.find_css(css)
108
+ else
109
+ base.find_css(css, **options)
110
110
  end
111
111
  end
112
112
 
113
113
  # @api private
114
114
  def find_xpath(xpath, **options)
115
- if base.method(:find_xpath).arity != 1
116
- base.find_xpath(xpath, **options)
117
- else
115
+ if base.method(:find_xpath).arity == 1
118
116
  base.find_xpath(xpath)
117
+ else
118
+ base.find_xpath(xpath, **options)
119
119
  end
120
120
  end
121
121
 
@@ -40,8 +40,8 @@ module Capybara
40
40
  find(:xpath, '/html').evaluate_script(*args)
41
41
  end
42
42
 
43
- def scroll_to(*args)
44
- find(:xpath, '//body').scroll_to(*args)
43
+ def scroll_to(*args, **options)
44
+ find(:xpath, '//body').scroll_to(*args, **options)
45
45
  end
46
46
  end
47
47
  end
@@ -42,7 +42,7 @@ module Capybara
42
42
  # @return [Boolean]
43
43
  #
44
44
  def has_title?(title, **options)
45
- make_predicate(options) { assert_title(title, options) }
45
+ make_predicate(options) { assert_title(title, **options) }
46
46
  end
47
47
 
48
48
  ##
@@ -52,13 +52,13 @@ module Capybara
52
52
  # @return [Boolean]
53
53
  #
54
54
  def has_no_title?(title, **options)
55
- make_predicate(options) { assert_no_title(title, options) }
55
+ make_predicate(options) { assert_no_title(title, **options) }
56
56
  end
57
57
 
58
58
  private
59
59
 
60
60
  def _verify_title(title, options)
61
- query = Capybara::Queries::TitleQuery.new(title, options)
61
+ query = Capybara::Queries::TitleQuery.new(title, **options)
62
62
  synchronize(query.wait) { yield(query) }
63
63
  true
64
64
  end
@@ -27,9 +27,11 @@ module Capybara
27
27
  @query_scope = query_scope
28
28
  @query = query
29
29
  @allow_reload = false
30
+ @query_idx = nil
30
31
  end
31
32
 
32
- def allow_reload!
33
+ def allow_reload!(idx = nil)
34
+ @query_idx = idx
33
35
  @allow_reload = true
34
36
  end
35
37
 
@@ -113,10 +115,12 @@ module Capybara
113
115
  #
114
116
  # @return [Capybara::Node::Element] The element
115
117
  def set(value, **options)
116
- raise Capybara::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}" if ENV['CAPYBARA_THOROUGH'] && readonly?
118
+ if ENV['CAPYBARA_THOROUGH'] && readonly?
119
+ raise Capybara::ReadOnlyElementError, "Attempt to set readonly element with value: #{value}"
120
+ end
117
121
 
118
122
  options = session_options.default_set_options.to_h.merge(options)
119
- synchronize { base.set(value, options) }
123
+ synchronize { base.set(value, **options) }
120
124
  self
121
125
  end
122
126
 
@@ -157,14 +161,16 @@ module Capybara
157
161
  # Both x: and y: must be specified if an offset is wanted, if not specified the click will occur at the middle of the element.
158
162
  # @overload $0(*modifier_keys, wait: nil, **offset)
159
163
  # @param *modifier_keys [:alt, :control, :meta, :shift] ([]) Keys to be held down when clicking
160
- # @option offset [Integer] x X coordinate to offset the click location from the top left corner of the element
161
- # @option offset [Integer] y Y coordinate to offset the click location from the top left corner of the element
164
+ # @option options [Integer] x X coordinate to offset the click location. If {Capybara.configure w3c_click_offset} is `true` the
165
+ # offset will be from the element center, otherwise it will be from the top left corner of the element
166
+ # @option options [Integer] y Y coordinate to offset the click location. If {Capybara.configure w3c_click_offset} is `true` the
167
+ # offset will be from the element center, otherwise it will be from the top left corner of the element
168
+ # @option options [Float] delay Delay between the mouse down and mouse up events in seconds (0)
162
169
  # @return [Capybara::Node::Element] The element
163
- def click(*keys, wait: nil, **offset)
164
- raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ offset[:x] ^ offset[:y]
165
-
166
- synchronize(wait) { base.click(Array(keys), offset) }
167
- self
170
+ def click(*keys, **options)
171
+ perform_click_action(keys, **options) do |k, opts|
172
+ base.click(k, **opts)
173
+ end
168
174
  end
169
175
 
170
176
  ##
@@ -173,12 +179,12 @@ module Capybara
173
179
  #
174
180
  # @macro action_waiting_behavior
175
181
  # @macro click_modifiers
182
+ # @option options [Float] delay Delay between the mouse down and mouse up events in seconds (0)
176
183
  # @return [Capybara::Node::Element] The element
177
- def right_click(*keys, wait: nil, **offset)
178
- raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ offset[:x] ^ offset[:y]
179
-
180
- synchronize(wait) { base.right_click(keys, offset) }
181
- self
184
+ def right_click(*keys, **options)
185
+ perform_click_action(keys, **options) do |k, opts|
186
+ base.right_click(k, **opts)
187
+ end
182
188
  end
183
189
 
184
190
  ##
@@ -188,11 +194,10 @@ module Capybara
188
194
  # @macro action_waiting_behavior
189
195
  # @macro click_modifiers
190
196
  # @return [Capybara::Node::Element] The element
191
- def double_click(*keys, wait: nil, **offset)
192
- raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ offset[:x] ^ offset[:y]
193
-
194
- synchronize(wait) { base.double_click(keys, offset) }
195
- self
197
+ def double_click(*keys, **options)
198
+ perform_click_action(keys, **options) do |k, opts|
199
+ base.double_click(k, **opts)
200
+ end
196
201
  end
197
202
 
198
203
  ##
@@ -372,6 +377,10 @@ module Capybara
372
377
  synchronize { base.path }
373
378
  end
374
379
 
380
+ def rect
381
+ synchronize { base.rect }
382
+ end
383
+
375
384
  ##
376
385
  #
377
386
  # Trigger any event on the current element, for example mouseover or focus
@@ -397,8 +406,15 @@ module Capybara
397
406
  #
398
407
  # @param [Capybara::Node::Element] node The element to drag to
399
408
  # @param [Hash] options Driver specific options for dragging. May not be supported by all drivers.
409
+ # @option options [Numeric] :delay (0.05) When using Chrome/Firefox with Selenium and HTML5 dragging this is the number
410
+ # of seconds between each stage of the drag.
411
+ # @option options [Boolean] :html5 When using Chrome/Firefox with Selenium enables to force the use of HTML5
412
+ # (true) or legacy (false) dragging. If not specified the driver will attempt to
413
+ # detect the correct method to use.
414
+ # @option options [Array<Symbol>,Symbol] :drop_modifiers Modifier keys which should be held while the dragged element is dropped.
400
415
  #
401
- # @return [Capybara::Node::Element] The element
416
+ #
417
+ # @return [Capybara::Node::Element] The dragged element
402
418
  def drag_to(node, **options)
403
419
  synchronize { base.drag_to(node.base, **options) }
404
420
  self
@@ -419,11 +435,7 @@ module Capybara
419
435
  #
420
436
  # @return [Capybara::Node::Element] The element
421
437
  def drop(*args)
422
- options = args.map do |arg|
423
- return arg.to_path if arg.respond_to?(:to_path)
424
-
425
- arg
426
- end
438
+ options = args.map { |arg| arg.respond_to?(:to_path) ? arg.to_path : arg }
427
439
  synchronize { base.drop(*options) }
428
440
  self
429
441
  end
@@ -511,15 +523,37 @@ module Capybara
511
523
  JS
512
524
  end
513
525
 
526
+ ##
527
+ #
528
+ # Toggle the elements background color between white and black for a period of time.
529
+ #
530
+ # @return [Capybara::Node::Element] The element
531
+ def flash
532
+ execute_script(<<~JS, 100)
533
+ async function flash(el, delay){
534
+ var old_bg = el.style.backgroundColor;
535
+ var colors = ["black", "white"];
536
+ for(var i=0; i<20; i++){
537
+ el.style.backgroundColor = colors[i % colors.length];
538
+ await new Promise(resolve => setTimeout(resolve, delay));
539
+ }
540
+ el.style.backgroundColor = old_bg;
541
+ }
542
+ flash(this, arguments[0]);
543
+ JS
544
+
545
+ self
546
+ end
547
+
514
548
  # @api private
515
549
  def reload
516
- if @allow_reload
517
- begin
518
- reloaded = query_scope.reload.first(@query.name, @query.locator, @query.options)
519
- @base = reloaded.base if reloaded
520
- rescue StandardError => e
521
- raise e unless catch_error?(e)
522
- end
550
+ return self unless @allow_reload
551
+
552
+ begin
553
+ reloaded = @query.resolve_for(query_scope.reload)[@query_idx.to_i]
554
+ @base = reloaded.base if reloaded
555
+ rescue StandardError => e
556
+ raise e unless catch_error?(e)
523
557
  end
524
558
  self
525
559
  end
@@ -553,6 +587,16 @@ module Capybara
553
587
  return result;
554
588
  }).apply(this, arguments)
555
589
  JS
590
+
591
+ private
592
+
593
+ def perform_click_action(keys, wait: nil, **options)
594
+ raise ArgumentError, 'You must specify both x: and y: for a click offset' if nil ^ options[:x] ^ options[:y]
595
+
596
+ options[:offset] ||= :center if session_options.w3c_click_offset
597
+ synchronize(wait) { yield keys, options }
598
+ self
599
+ end
556
600
  end
557
601
  end
558
602
  end
@@ -24,12 +24,13 @@ module Capybara
24
24
  # @option options [Boolean] normalize_ws
25
25
  # Whether the `text`/`exact_text` options are compared against elment text with whitespace normalized or as returned by the driver.
26
26
  # Defaults to {Capybara.configure default_normalize_ws}.
27
- # @option options [Boolean, Symbol] visible Only find elements with the specified visibility:
28
- # * true - only finds visible elements.
29
- # * false - finds invisible _and_ visible elements.
30
- # * :all - same as false; finds visible and invisible elements.
31
- # * :hidden - only finds invisible elements.
32
- # * :visible - same as true; only finds visible elements.
27
+ # @option options [Boolean, Symbol] visible
28
+ # Only find elements with the specified visibility. Defaults to behavior indicated by {Capybara.configure ignore_hidden_elements}.
29
+ # * true - only finds visible elements.
30
+ # * false - finds invisible _and_ visible elements.
31
+ # * :all - same as false; finds visible and invisible elements.
32
+ # * :hidden - only finds invisible elements.
33
+ # * :visible - same as true; only finds visible elements.
33
34
  # @option options [Boolean] obscured Only find elements with the specified obscured state:
34
35
  # * true - only find elements whose centerpoint is not in the viewport or is obscured by another non-descendant element.
35
36
  # * false - only find elements whose centerpoint is in the viewport and is not obscured by other non-descendant elements.
@@ -49,7 +50,7 @@ module Capybara
49
50
  #
50
51
  def find(*args, **options, &optional_filter_block)
51
52
  options[:session_options] = session_options
52
- synced_resolve Capybara::Queries::SelectorQuery.new(*args, options, &optional_filter_block)
53
+ synced_resolve Capybara::Queries::SelectorQuery.new(*args, **options, &optional_filter_block)
53
54
  end
54
55
 
55
56
  ##
@@ -72,7 +73,7 @@ module Capybara
72
73
  #
73
74
  def ancestor(*args, **options, &optional_filter_block)
74
75
  options[:session_options] = session_options
75
- synced_resolve Capybara::Queries::AncestorQuery.new(*args, options, &optional_filter_block)
76
+ synced_resolve Capybara::Queries::AncestorQuery.new(*args, **options, &optional_filter_block)
76
77
  end
77
78
 
78
79
  ##
@@ -95,7 +96,7 @@ module Capybara
95
96
  #
96
97
  def sibling(*args, **options, &optional_filter_block)
97
98
  options[:session_options] = session_options
98
- synced_resolve Capybara::Queries::SiblingQuery.new(*args, options, &optional_filter_block)
99
+ synced_resolve Capybara::Queries::SiblingQuery.new(*args, **options, &optional_filter_block)
99
100
  end
100
101
 
101
102
  ##
@@ -125,7 +126,7 @@ module Capybara
125
126
  # @return [Capybara::Node::Element] The found element
126
127
  #
127
128
  def find_field(locator = nil, **options, &optional_filter_block)
128
- find(:field, locator, options, &optional_filter_block)
129
+ find(:field, locator, **options, &optional_filter_block)
129
130
  end
130
131
 
131
132
  ##
@@ -145,7 +146,7 @@ module Capybara
145
146
  # @return [Capybara::Node::Element] The found element
146
147
  #
147
148
  def find_link(locator = nil, **options, &optional_filter_block)
148
- find(:link, locator, options, &optional_filter_block)
149
+ find(:link, locator, **options, &optional_filter_block)
149
150
  end
150
151
 
151
152
  ##
@@ -172,7 +173,7 @@ module Capybara
172
173
  # @return [Capybara::Node::Element] The found element
173
174
  #
174
175
  def find_button(locator = nil, **options, &optional_filter_block)
175
- find(:button, locator, options, &optional_filter_block)
176
+ find(:button, locator, **options, &optional_filter_block)
176
177
  end
177
178
 
178
179
  ##
@@ -186,7 +187,7 @@ module Capybara
186
187
  # @return [Capybara::Node::Element] The found element
187
188
  #
188
189
  def find_by_id(id, **options, &optional_filter_block)
189
- find(:id, id, options, &optional_filter_block)
190
+ find(:id, id, **options, &optional_filter_block)
190
191
  end
191
192
 
192
193
  ##
@@ -235,21 +236,25 @@ module Capybara
235
236
  # @option options [Integer] maximum Maximum number of matches that are expected to be found
236
237
  # @option options [Integer] minimum Minimum number of matches that are expected to be found
237
238
  # @option options [Range] between Number of matches found must be within the given range
239
+ # @option options [Boolean] allow_reload Beta feature - May be removed in any version.
240
+ # When `true` allows elements to be reloaded if they become stale. This is an advanced behavior and should only be used
241
+ # if you fully understand the potential ramifications. The results can be confusing on dynamic pages. Defaults to `false`
238
242
  # @overload all([kind = Capybara.default_selector], locator = nil, **options)
239
243
  # @overload all([kind = Capybara.default_selector], locator = nil, **options, &filter_block)
240
244
  # @yieldparam element [Capybara::Node::Element] The element being considered for inclusion in the results
241
245
  # @yieldreturn [Boolean] Should the element be considered in the results?
242
246
  # @return [Capybara::Result] A collection of found elements
243
247
  # @raise [Capybara::ExpectationNotMet] The number of elements found doesn't match the specified conditions
244
- def all(*args, **options, &optional_filter_block)
248
+ def all(*args, allow_reload: false, **options, &optional_filter_block)
245
249
  minimum_specified = options_include_minimum?(options)
246
250
  options = { minimum: 1 }.merge(options) unless minimum_specified
247
251
  options[:session_options] = session_options
248
- query = Capybara::Queries::SelectorQuery.new(*args, options, &optional_filter_block)
252
+ query = Capybara::Queries::SelectorQuery.new(*args, **options, &optional_filter_block)
249
253
  result = nil
250
254
  begin
251
255
  synchronize(query.wait) do
252
256
  result = query.resolve_for(self)
257
+ result.allow_reload! if allow_reload
253
258
  raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
254
259
 
255
260
  result
@@ -278,7 +283,7 @@ module Capybara
278
283
  #
279
284
  def first(*args, **options, &optional_filter_block)
280
285
  options = { minimum: 1 }.merge(options) unless options_include_minimum?(options)
281
- all(*args, options, &optional_filter_block).first
286
+ all(*args, **options, &optional_filter_block).first
282
287
  end
283
288
 
284
289
  private
@@ -292,7 +297,9 @@ module Capybara
292
297
  result = query.resolve_for(self)
293
298
  end
294
299
 
295
- raise Capybara::Ambiguous, "Ambiguous match, found #{result.size} elements matching #{query.applied_description}" if ambiguous?(query, result)
300
+ if ambiguous?(query, result)
301
+ raise Capybara::Ambiguous, "Ambiguous match, found #{result.size} elements matching #{query.applied_description}"
302
+ end
296
303
  raise Capybara::ElementNotFound, "Unable to find #{query.applied_description}" if result.empty?
297
304
 
298
305
  result.first
@@ -60,15 +60,16 @@ module Capybara
60
60
  # @param styles [Hash]
61
61
  # @return [Boolean] If the styles match
62
62
  #
63
- def matches_style?(styles, **options)
64
- make_predicate(options) { assert_matches_style(styles, options) }
63
+ def matches_style?(styles = nil, **options)
64
+ styles, options = options, {} if styles.nil?
65
+ make_predicate(options) { assert_matches_style(styles, **options) }
65
66
  end
66
67
 
67
68
  ##
68
69
  # @deprecated Use {#matches_style?} instead.
69
70
  #
70
- def has_style?(styles, **options)
71
- warn 'DEPRECATED: has_style? is deprecated, please use matches_style?'
71
+ def has_style?(styles = nil, **options)
72
+ Capybara::Helpers.warn "DEPRECATED: has_style? is deprecated, please use matches_style? : #{Capybara::Helpers.filter_backtrace(caller)}"
72
73
  matches_style?(styles, **options)
73
74
  end
74
75
 
@@ -107,7 +108,9 @@ module Capybara
107
108
  #
108
109
  def assert_selector(*args, &optional_filter_block)
109
110
  _verify_selector_result(args, optional_filter_block) do |result, query|
110
- raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count? && (result.any? || query.expects_none?)
111
+ unless result.matches_count? && (result.any? || query.expects_none?)
112
+ raise Capybara::ExpectationNotMet, result.failure_message
113
+ end
111
114
  end
112
115
  end
113
116
 
@@ -120,9 +123,10 @@ module Capybara
120
123
  # @param styles [Hash]
121
124
  # @raise [Capybara::ExpectationNotMet] If the element doesn't have the specified styles
122
125
  #
123
- def assert_matches_style(styles, **options)
124
- query_args = _set_query_session_options(styles, options)
125
- query = Capybara::Queries::StyleQuery.new(*query_args)
126
+ def assert_matches_style(styles = nil, **options)
127
+ styles, options = options, {} if styles.nil?
128
+ query_args, query_opts = _set_query_session_options(styles, options)
129
+ query = Capybara::Queries::StyleQuery.new(*query_args, **query_opts)
126
130
  synchronize(query.wait) do
127
131
  raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
128
132
  end
@@ -132,7 +136,7 @@ module Capybara
132
136
  ##
133
137
  # @deprecated Use {#assert_matches_style} instead.
134
138
  #
135
- def assert_style(styles, **options)
139
+ def assert_style(styles = nil, **options)
136
140
  warn 'assert_style is deprecated, please use assert_matches_style instead'
137
141
  assert_matches_style(styles, **options)
138
142
  end
@@ -141,8 +145,8 @@ module Capybara
141
145
  # or descendants of the current node. If options are provided, the assertion
142
146
  # will check that each locator is present with those options as well (other than `:wait`).
143
147
  #
144
- # page.assert_all_of_selectors(:custom, 'Tom', 'Joe', visible: all)
145
- # page.assert_all_of_selectors(:css, '#my_div', 'a.not_clicked')
148
+ # page.assert_all_of_selectors(:custom, 'Tom', 'Joe', visible: all)
149
+ # page.assert_all_of_selectors(:css, '#my_div', 'a.not_clicked')
146
150
  #
147
151
  # It accepts all options that {Capybara::Node::Finders#all} accepts,
148
152
  # such as `:text` and `:visible`.
@@ -153,7 +157,7 @@ module Capybara
153
157
  # @overload assert_all_of_selectors([kind = Capybara.default_selector], *locators, **options)
154
158
  #
155
159
  def assert_all_of_selectors(*args, **options, &optional_filter_block)
156
- _verify_multiple(*args, options) do |selector, locator, opts|
160
+ _verify_multiple(*args, **options) do |selector, locator, opts|
157
161
  assert_selector(selector, locator, opts, &optional_filter_block)
158
162
  end
159
163
  end
@@ -162,8 +166,8 @@ module Capybara
162
166
  # or descendants of the current node. If options are provided, the assertion
163
167
  # will check that each locator is not present with those options as well (other than `:wait`).
164
168
  #
165
- # page.assert_none_of_selectors(:custom, 'Tom', 'Joe', visible: all)
166
- # page.assert_none_of_selectors(:css, '#my_div', 'a.not_clicked')
169
+ # page.assert_none_of_selectors(:custom, 'Tom', 'Joe', visible: all)
170
+ # page.assert_none_of_selectors(:css, '#my_div', 'a.not_clicked')
167
171
  #
168
172
  # It accepts all options that {Capybara::Node::Finders#all} accepts,
169
173
  # such as `:text` and `:visible`.
@@ -174,7 +178,7 @@ module Capybara
174
178
  # @overload assert_none_of_selectors([kind = Capybara.default_selector], *locators, **options)
175
179
  #
176
180
  def assert_none_of_selectors(*args, **options, &optional_filter_block)
177
- _verify_multiple(*args, options) do |selector, locator, opts|
181
+ _verify_multiple(*args, **options) do |selector, locator, opts|
178
182
  assert_no_selector(selector, locator, opts, &optional_filter_block)
179
183
  end
180
184
  end
@@ -183,8 +187,8 @@ module Capybara
183
187
  # or descendants of the current node. If options are provided, the assertion
184
188
  # will check that each locator is present with those options as well (other than `:wait`).
185
189
  #
186
- # page.assert_any_of_selectors(:custom, 'Tom', 'Joe', visible: all)
187
- # page.assert_any_of_selectors(:css, '#my_div', 'a.not_clicked')
190
+ # page.assert_any_of_selectors(:custom, 'Tom', 'Joe', visible: all)
191
+ # page.assert_any_of_selectors(:css, '#my_div', 'a.not_clicked')
188
192
  #
189
193
  # It accepts all options that {Capybara::Node::Finders#all} accepts,
190
194
  # such as `:text` and `:visible`.
@@ -199,12 +203,10 @@ module Capybara
199
203
  selector = extract_selector(args)
200
204
  synchronize(wait) do
201
205
  res = args.map do |locator|
202
- begin
203
- assert_selector(selector, locator, options, &optional_filter_block)
204
- break nil
205
- rescue Capybara::ExpectationNotMet => e
206
- e.message
207
- end
206
+ assert_selector(selector, locator, options, &optional_filter_block)
207
+ break nil
208
+ rescue Capybara::ExpectationNotMet => e
209
+ e.message
208
210
  end
209
211
  raise Capybara::ExpectationNotMet, res.join(' or ') if res
210
212
 
@@ -266,7 +268,7 @@ module Capybara
266
268
  # @return [Boolean] If the expression exists
267
269
  #
268
270
  def has_xpath?(path, **options, &optional_filter_block)
269
- has_selector?(:xpath, path, options, &optional_filter_block)
271
+ has_selector?(:xpath, path, **options, &optional_filter_block)
270
272
  end
271
273
 
272
274
  ##
@@ -278,7 +280,7 @@ module Capybara
278
280
  # @return [Boolean]
279
281
  #
280
282
  def has_no_xpath?(path, **options, &optional_filter_block)
281
- has_no_selector?(:xpath, path, options, &optional_filter_block)
283
+ has_no_selector?(:xpath, path, **options, &optional_filter_block)
282
284
  end
283
285
 
284
286
  ##
@@ -305,7 +307,7 @@ module Capybara
305
307
  # @return [Boolean] If the selector exists
306
308
  #
307
309
  def has_css?(path, **options, &optional_filter_block)
308
- has_selector?(:css, path, options, &optional_filter_block)
310
+ has_selector?(:css, path, **options, &optional_filter_block)
309
311
  end
310
312
 
311
313
  ##
@@ -317,7 +319,7 @@ module Capybara
317
319
  # @return [Boolean]
318
320
  #
319
321
  def has_no_css?(path, **options, &optional_filter_block)
320
- has_no_selector?(:css, path, options, &optional_filter_block)
322
+ has_no_selector?(:css, path, **options, &optional_filter_block)
321
323
  end
322
324
 
323
325
  ##
@@ -330,7 +332,7 @@ module Capybara
330
332
  # @return [Boolean] Whether it exists
331
333
  #
332
334
  def has_link?(locator = nil, **options, &optional_filter_block)
333
- has_selector?(:link, locator, options, &optional_filter_block)
335
+ has_selector?(:link, locator, **options, &optional_filter_block)
334
336
  end
335
337
 
336
338
  ##
@@ -342,7 +344,7 @@ module Capybara
342
344
  # @return [Boolean] Whether it doesn't exist
343
345
  #
344
346
  def has_no_link?(locator = nil, **options, &optional_filter_block)
345
- has_no_selector?(:link, locator, options, &optional_filter_block)
347
+ has_no_selector?(:link, locator, **options, &optional_filter_block)
346
348
  end
347
349
 
348
350
  ##
@@ -354,7 +356,7 @@ module Capybara
354
356
  # @return [Boolean] Whether it exists
355
357
  #
356
358
  def has_button?(locator = nil, **options, &optional_filter_block)
357
- has_selector?(:button, locator, options, &optional_filter_block)
359
+ has_selector?(:button, locator, **options, &optional_filter_block)
358
360
  end
359
361
 
360
362
  ##
@@ -366,7 +368,7 @@ module Capybara
366
368
  # @return [Boolean] Whether it doesn't exist
367
369
  #
368
370
  def has_no_button?(locator = nil, **options, &optional_filter_block)
369
- has_no_selector?(:button, locator, options, &optional_filter_block)
371
+ has_no_selector?(:button, locator, **options, &optional_filter_block)
370
372
  end
371
373
 
372
374
  ##
@@ -384,7 +386,7 @@ module Capybara
384
386
  #
385
387
  # page.has_field?('Email', type: 'email')
386
388
  #
387
- # Note: 'textarea' and 'select' are valid type values, matching the associated tag names.
389
+ # NOTE: 'textarea' and 'select' are valid type values, matching the associated tag names.
388
390
  #
389
391
  # @param [String] locator The label, name or id of a field to check for
390
392
  # @option options [String, Regexp] :with The text content of the field or a Regexp to match
@@ -392,7 +394,7 @@ module Capybara
392
394
  # @return [Boolean] Whether it exists
393
395
  #
394
396
  def has_field?(locator = nil, **options, &optional_filter_block)
395
- has_selector?(:field, locator, options, &optional_filter_block)
397
+ has_selector?(:field, locator, **options, &optional_filter_block)
396
398
  end
397
399
 
398
400
  ##
@@ -406,7 +408,7 @@ module Capybara
406
408
  # @return [Boolean] Whether it doesn't exist
407
409
  #
408
410
  def has_no_field?(locator = nil, **options, &optional_filter_block)
409
- has_no_selector?(:field, locator, options, &optional_filter_block)
411
+ has_no_selector?(:field, locator, **options, &optional_filter_block)
410
412
  end
411
413
 
412
414
  ##
@@ -419,7 +421,7 @@ module Capybara
419
421
  # @return [Boolean] Whether it exists
420
422
  #
421
423
  def has_checked_field?(locator = nil, **options, &optional_filter_block)
422
- has_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
424
+ has_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
423
425
  end
424
426
 
425
427
  ##
@@ -432,7 +434,7 @@ module Capybara
432
434
  # @return [Boolean] Whether it doesn't exist
433
435
  #
434
436
  def has_no_checked_field?(locator = nil, **options, &optional_filter_block)
435
- has_no_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
437
+ has_no_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
436
438
  end
437
439
 
438
440
  ##
@@ -445,7 +447,7 @@ module Capybara
445
447
  # @return [Boolean] Whether it exists
446
448
  #
447
449
  def has_unchecked_field?(locator = nil, **options, &optional_filter_block)
448
- has_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
450
+ has_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
449
451
  end
450
452
 
451
453
  ##
@@ -458,7 +460,7 @@ module Capybara
458
460
  # @return [Boolean] Whether it doesn't exist
459
461
  #
460
462
  def has_no_unchecked_field?(locator = nil, **options, &optional_filter_block)
461
- has_no_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
463
+ has_no_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
462
464
  end
463
465
 
464
466
  ##
@@ -491,7 +493,7 @@ module Capybara
491
493
  # @return [Boolean] Whether it exists
492
494
  #
493
495
  def has_select?(locator = nil, **options, &optional_filter_block)
494
- has_selector?(:select, locator, options, &optional_filter_block)
496
+ has_selector?(:select, locator, **options, &optional_filter_block)
495
497
  end
496
498
 
497
499
  ##
@@ -503,7 +505,7 @@ module Capybara
503
505
  # @return [Boolean] Whether it doesn't exist
504
506
  #
505
507
  def has_no_select?(locator = nil, **options, &optional_filter_block)
506
- has_no_selector?(:select, locator, options, &optional_filter_block)
508
+ has_no_selector?(:select, locator, **options, &optional_filter_block)
507
509
  end
508
510
 
509
511
  ##
@@ -525,7 +527,7 @@ module Capybara
525
527
  # @return [Boolean] Whether it exists
526
528
  #
527
529
  def has_table?(locator = nil, **options, &optional_filter_block)
528
- has_selector?(:table, locator, options, &optional_filter_block)
530
+ has_selector?(:table, locator, **options, &optional_filter_block)
529
531
  end
530
532
 
531
533
  ##
@@ -537,7 +539,7 @@ module Capybara
537
539
  # @return [Boolean] Whether it doesn't exist
538
540
  #
539
541
  def has_no_table?(locator = nil, **options, &optional_filter_block)
540
- has_no_selector?(:table, locator, options, &optional_filter_block)
542
+ has_no_selector?(:table, locator, **options, &optional_filter_block)
541
543
  end
542
544
 
543
545
  ##
@@ -595,7 +597,7 @@ module Capybara
595
597
  # @return [Boolean]
596
598
  #
597
599
  def matches_xpath?(xpath, **options, &optional_filter_block)
598
- matches_selector?(:xpath, xpath, options, &optional_filter_block)
600
+ matches_selector?(:xpath, xpath, **options, &optional_filter_block)
599
601
  end
600
602
 
601
603
  ##
@@ -606,7 +608,7 @@ module Capybara
606
608
  # @return [Boolean]
607
609
  #
608
610
  def matches_css?(css, **options, &optional_filter_block)
609
- matches_selector?(:css, css, options, &optional_filter_block)
611
+ matches_selector?(:css, css, **options, &optional_filter_block)
610
612
  end
611
613
 
612
614
  ##
@@ -629,7 +631,7 @@ module Capybara
629
631
  # @return [Boolean]
630
632
  #
631
633
  def not_matches_xpath?(xpath, **options, &optional_filter_block)
632
- not_matches_selector?(:xpath, xpath, options, &optional_filter_block)
634
+ not_matches_selector?(:xpath, xpath, **options, &optional_filter_block)
633
635
  end
634
636
 
635
637
  ##
@@ -640,7 +642,7 @@ module Capybara
640
642
  # @return [Boolean]
641
643
  #
642
644
  def not_matches_css?(css, **options, &optional_filter_block)
643
- not_matches_selector?(:css, css, options, &optional_filter_block)
645
+ not_matches_selector?(:css, css, **options, &optional_filter_block)
644
646
  end
645
647
 
646
648
  ##
@@ -670,8 +672,8 @@ module Capybara
670
672
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
671
673
  # @return [true]
672
674
  #
673
- def assert_text(*args)
674
- _verify_text(args) do |count, query|
675
+ def assert_text(type_or_text, *args, **opts)
676
+ _verify_text(type_or_text, *args, **opts) do |count, query|
675
677
  unless query.matches_count?(count) && (count.positive? || query.expects_none?)
676
678
  raise Capybara::ExpectationNotMet, query.failure_message
677
679
  end
@@ -686,8 +688,8 @@ module Capybara
686
688
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
687
689
  # @return [true]
688
690
  #
689
- def assert_no_text(*args)
690
- _verify_text(args) do |count, query|
691
+ def assert_no_text(type_or_text, *args, **opts)
692
+ _verify_text(type_or_text, *args, **opts) do |count, query|
691
693
  if query.matches_count?(count) && (count.positive? || query.expects_none?)
692
694
  raise Capybara::ExpectationNotMet, query.negative_failure_message
693
695
  end
@@ -709,7 +711,7 @@ module Capybara
709
711
  # @return [Boolean] Whether it exists
710
712
  #
711
713
  def has_text?(*args, **options)
712
- make_predicate(options) { assert_text(*args, options) }
714
+ make_predicate(options) { assert_text(*args, **options) }
713
715
  end
714
716
  alias_method :has_content?, :has_text?
715
717
 
@@ -721,7 +723,7 @@ module Capybara
721
723
  # @return [Boolean] Whether it doesn't exist
722
724
  #
723
725
  def has_no_text?(*args, **options)
724
- make_predicate(options) { assert_no_text(*args, options) }
726
+ make_predicate(options) { assert_no_text(*args, **options) }
725
727
  end
726
728
  alias_method :has_no_content?, :has_no_text?
727
729
 
@@ -738,12 +740,14 @@ module Capybara
738
740
  #
739
741
  def assert_ancestor(*args, &optional_filter_block)
740
742
  _verify_selector_result(args, optional_filter_block, Capybara::Queries::AncestorQuery) do |result, query|
741
- raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count? && (result.any? || query.expects_none?)
743
+ unless result.matches_count? && (result.any? || query.expects_none?)
744
+ raise Capybara::ExpectationNotMet, result.failure_message
745
+ end
742
746
  end
743
747
  end
744
748
 
745
749
  def assert_no_ancestor(*args, &optional_filter_block)
746
- _verify_selector_result(args, optional_filter_block, Capybara::Queries::SiblingQuery) do |result, query|
750
+ _verify_selector_result(args, optional_filter_block, Capybara::Queries::AncestorQuery) do |result, query|
747
751
  if result.matches_count? && (!result.empty? || query.expects_none?)
748
752
  raise Capybara::ExpectationNotMet, result.negative_failure_message
749
753
  end
@@ -779,7 +783,9 @@ module Capybara
779
783
  #
780
784
  def assert_sibling(*args, &optional_filter_block)
781
785
  _verify_selector_result(args, optional_filter_block, Capybara::Queries::SiblingQuery) do |result, query|
782
- raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count? && (result.any? || query.expects_none?)
786
+ unless result.matches_count? && (result.any? || query.expects_none?)
787
+ raise Capybara::ExpectationNotMet, result.failure_message
788
+ end
783
789
  end
784
790
  end
785
791
 
@@ -826,8 +832,14 @@ module Capybara
826
832
  end
827
833
 
828
834
  def _verify_selector_result(query_args, optional_filter_block, query_type = Capybara::Queries::SelectorQuery)
829
- query_args = _set_query_session_options(*query_args)
830
- query = query_type.new(*query_args, &optional_filter_block)
835
+ # query_args, query_opts = if query_args[0].is_a? Symbol
836
+ # a,o = _set_query_session_options(*query_args.slice(2..))
837
+ # [query_args.slice(0..1).concat(a), o]
838
+ # else
839
+ # _set_query_session_options(*query_args)
840
+ # end
841
+ query_args, query_opts = _set_query_session_options(*query_args)
842
+ query = query_type.new(*query_args, **query_opts, &optional_filter_block)
831
843
  synchronize(query.wait) do
832
844
  yield query.resolve_for(self), query
833
845
  end
@@ -835,26 +847,29 @@ module Capybara
835
847
  end
836
848
 
837
849
  def _verify_match_result(query_args, optional_filter_block)
838
- query_args = _set_query_session_options(*query_args)
839
- query = Capybara::Queries::MatchQuery.new(*query_args, &optional_filter_block)
850
+ query_args, query_opts = _set_query_session_options(*query_args)
851
+ query = Capybara::Queries::MatchQuery.new(*query_args, **query_opts, &optional_filter_block)
840
852
  synchronize(query.wait) do
841
853
  yield query.resolve_for(parent || session&.document || query_scope)
842
854
  end
843
855
  true
844
856
  end
845
857
 
846
- def _verify_text(query_args)
847
- query_args = _set_query_session_options(*query_args)
848
- query = Capybara::Queries::TextQuery.new(*query_args)
858
+ def _verify_text(type = nil, expected_text, **query_options) # rubocop:disable Style/OptionalArguments
859
+ query_options[:session_options] = session_options
860
+ query = Capybara::Queries::TextQuery.new(type, expected_text, **query_options)
849
861
  synchronize(query.wait) do
850
862
  yield query.resolve_for(self), query
851
863
  end
852
864
  true
853
865
  end
854
866
 
855
- def _set_query_session_options(*query_args, **query_options)
867
+ def _set_query_session_options(*query_args)
868
+ query_args, query_options = query_args.dup, {}
869
+ # query_options = query_args.pop if query_options.empty? && query_args.last.is_a?(Hash)
870
+ query_options = query_args.pop if query_args.last.is_a?(Hash)
856
871
  query_options[:session_options] = session_options
857
- query_args.push(query_options)
872
+ [query_args, query_options]
858
873
  end
859
874
 
860
875
  def make_predicate(options)