capybara 3.3.0 → 3.40.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 (308) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +803 -13
  4. data/License.txt +1 -1
  5. data/README.md +257 -84
  6. data/lib/capybara/config.rb +25 -9
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/base.rb +17 -3
  9. data/lib/capybara/driver/node.rb +31 -6
  10. data/lib/capybara/dsl.rb +9 -7
  11. data/lib/capybara/helpers.rb +31 -7
  12. data/lib/capybara/minitest/spec.rb +180 -88
  13. data/lib/capybara/minitest.rb +262 -149
  14. data/lib/capybara/node/actions.rb +202 -116
  15. data/lib/capybara/node/base.rb +34 -19
  16. data/lib/capybara/node/document.rb +14 -2
  17. data/lib/capybara/node/document_matchers.rb +10 -12
  18. data/lib/capybara/node/element.rb +269 -115
  19. data/lib/capybara/node/finders.rb +99 -77
  20. data/lib/capybara/node/matchers.rb +327 -151
  21. data/lib/capybara/node/simple.rb +48 -13
  22. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  23. data/lib/capybara/queries/active_element_query.rb +18 -0
  24. data/lib/capybara/queries/ancestor_query.rb +8 -9
  25. data/lib/capybara/queries/base_query.rb +23 -16
  26. data/lib/capybara/queries/current_path_query.rb +16 -6
  27. data/lib/capybara/queries/match_query.rb +1 -0
  28. data/lib/capybara/queries/selector_query.rb +587 -130
  29. data/lib/capybara/queries/sibling_query.rb +8 -6
  30. data/lib/capybara/queries/style_query.rb +6 -2
  31. data/lib/capybara/queries/text_query.rb +28 -14
  32. data/lib/capybara/queries/title_query.rb +2 -2
  33. data/lib/capybara/rack_test/browser.rb +92 -25
  34. data/lib/capybara/rack_test/driver.rb +16 -7
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +68 -41
  37. data/lib/capybara/rack_test/node.rb +106 -39
  38. data/lib/capybara/rails.rb +1 -1
  39. data/lib/capybara/registration_container.rb +41 -0
  40. data/lib/capybara/registrations/drivers.rb +42 -0
  41. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  42. data/lib/capybara/registrations/servers.rb +66 -0
  43. data/lib/capybara/result.rb +75 -52
  44. data/lib/capybara/rspec/features.rb +7 -7
  45. data/lib/capybara/rspec/matcher_proxies.rb +39 -18
  46. data/lib/capybara/rspec/matchers/base.rb +113 -0
  47. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  48. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  49. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  50. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  51. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  52. data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  53. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  54. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  55. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  56. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  57. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  58. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  59. data/lib/capybara/rspec/matchers.rb +141 -339
  60. data/lib/capybara/rspec.rb +2 -0
  61. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  62. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  63. data/lib/capybara/selector/css.rb +27 -25
  64. data/lib/capybara/selector/definition/button.rb +68 -0
  65. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  66. data/lib/capybara/selector/definition/css.rb +10 -0
  67. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  68. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  69. data/lib/capybara/selector/definition/element.rb +28 -0
  70. data/lib/capybara/selector/definition/field.rb +40 -0
  71. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  72. data/lib/capybara/selector/definition/file_field.rb +13 -0
  73. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  74. data/lib/capybara/selector/definition/frame.rb +17 -0
  75. data/lib/capybara/selector/definition/id.rb +6 -0
  76. data/lib/capybara/selector/definition/label.rb +62 -0
  77. data/lib/capybara/selector/definition/link.rb +55 -0
  78. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  79. data/lib/capybara/selector/definition/option.rb +27 -0
  80. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  81. data/lib/capybara/selector/definition/select.rb +81 -0
  82. data/lib/capybara/selector/definition/table.rb +109 -0
  83. data/lib/capybara/selector/definition/table_row.rb +21 -0
  84. data/lib/capybara/selector/definition/xpath.rb +5 -0
  85. data/lib/capybara/selector/definition.rb +280 -0
  86. data/lib/capybara/selector/filter.rb +1 -0
  87. data/lib/capybara/selector/filter_set.rb +73 -25
  88. data/lib/capybara/selector/filters/base.rb +24 -5
  89. data/lib/capybara/selector/filters/expression_filter.rb +3 -3
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +16 -2
  92. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  93. data/lib/capybara/selector/selector.rb +85 -348
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selector.rb +474 -447
  96. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  97. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  98. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  99. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  100. data/lib/capybara/selenium/driver.rb +255 -143
  101. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +93 -11
  102. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  103. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
  104. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  105. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  106. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  107. data/lib/capybara/selenium/extensions/find.rb +110 -0
  108. data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
  109. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  110. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  111. data/lib/capybara/selenium/node.rb +436 -134
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  114. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  115. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  116. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  117. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  118. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  119. data/lib/capybara/selenium/patches/logs.rb +45 -0
  120. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  121. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  122. data/lib/capybara/server/animation_disabler.rb +56 -19
  123. data/lib/capybara/server/checker.rb +9 -3
  124. data/lib/capybara/server/middleware.rb +28 -12
  125. data/lib/capybara/server.rb +33 -10
  126. data/lib/capybara/session/config.rb +34 -10
  127. data/lib/capybara/session/matchers.rb +23 -16
  128. data/lib/capybara/session.rb +230 -170
  129. data/lib/capybara/spec/public/jquery.js +5 -5
  130. data/lib/capybara/spec/public/offset.js +6 -0
  131. data/lib/capybara/spec/public/test.js +121 -8
  132. data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
  133. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
  134. data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
  135. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  136. data/lib/capybara/spec/session/all_spec.rb +127 -40
  137. data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
  138. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
  139. data/lib/capybara/spec/session/assert_current_path_spec.rb +21 -18
  140. data/lib/capybara/spec/session/assert_selector_spec.rb +52 -58
  141. data/lib/capybara/spec/session/assert_style_spec.rb +7 -7
  142. data/lib/capybara/spec/session/assert_text_spec.rb +74 -50
  143. data/lib/capybara/spec/session/assert_title_spec.rb +12 -12
  144. data/lib/capybara/spec/session/attach_file_spec.rb +126 -72
  145. data/lib/capybara/spec/session/body_spec.rb +6 -6
  146. data/lib/capybara/spec/session/check_spec.rb +102 -47
  147. data/lib/capybara/spec/session/choose_spec.rb +58 -32
  148. data/lib/capybara/spec/session/click_button_spec.rb +219 -163
  149. data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -23
  150. data/lib/capybara/spec/session/click_link_spec.rb +77 -54
  151. data/lib/capybara/spec/session/current_scope_spec.rb +8 -8
  152. data/lib/capybara/spec/session/current_url_spec.rb +38 -29
  153. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
  154. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
  155. data/lib/capybara/spec/session/element/assert_match_selector_spec.rb +8 -8
  156. data/lib/capybara/spec/session/element/match_css_spec.rb +16 -10
  157. data/lib/capybara/spec/session/element/match_xpath_spec.rb +6 -6
  158. data/lib/capybara/spec/session/element/matches_selector_spec.rb +68 -56
  159. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
  160. data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
  161. data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
  162. data/lib/capybara/spec/session/fill_in_spec.rb +101 -46
  163. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  164. data/lib/capybara/spec/session/find_by_id_spec.rb +7 -7
  165. data/lib/capybara/spec/session/find_field_spec.rb +32 -30
  166. data/lib/capybara/spec/session/find_link_spec.rb +31 -21
  167. data/lib/capybara/spec/session/find_spec.rb +244 -141
  168. data/lib/capybara/spec/session/first_spec.rb +43 -43
  169. data/lib/capybara/spec/session/frame/frame_title_spec.rb +5 -5
  170. data/lib/capybara/spec/session/frame/frame_url_spec.rb +5 -5
  171. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +30 -18
  172. data/lib/capybara/spec/session/frame/within_frame_spec.rb +45 -18
  173. data/lib/capybara/spec/session/go_back_spec.rb +1 -1
  174. data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
  175. data/lib/capybara/spec/session/has_all_selectors_spec.rb +23 -23
  176. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  177. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  178. data/lib/capybara/spec/session/has_button_spec.rb +94 -13
  179. data/lib/capybara/spec/session/has_css_spec.rb +272 -132
  180. data/lib/capybara/spec/session/has_current_path_spec.rb +50 -35
  181. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  182. data/lib/capybara/spec/session/has_field_spec.rb +137 -58
  183. data/lib/capybara/spec/session/has_link_spec.rb +44 -4
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +31 -31
  185. data/lib/capybara/spec/session/has_select_spec.rb +84 -50
  186. data/lib/capybara/spec/session/has_selector_spec.rb +111 -71
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +181 -4
  189. data/lib/capybara/spec/session/has_text_spec.rb +101 -53
  190. data/lib/capybara/spec/session/has_title_spec.rb +19 -14
  191. data/lib/capybara/spec/session/has_xpath_spec.rb +56 -38
  192. data/lib/capybara/spec/session/headers_spec.rb +1 -1
  193. data/lib/capybara/spec/session/html_spec.rb +13 -6
  194. data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
  195. data/lib/capybara/spec/session/node_spec.rb +894 -142
  196. data/lib/capybara/spec/session/node_wrapper_spec.rb +10 -7
  197. data/lib/capybara/spec/session/refresh_spec.rb +9 -7
  198. data/lib/capybara/spec/session/reset_session_spec.rb +63 -35
  199. data/lib/capybara/spec/session/response_code_spec.rb +1 -1
  200. data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
  201. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  202. data/lib/capybara/spec/session/save_page_spec.rb +37 -37
  203. data/lib/capybara/spec/session/save_screenshot_spec.rb +10 -10
  204. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  205. data/lib/capybara/spec/session/scroll_spec.rb +119 -0
  206. data/lib/capybara/spec/session/select_spec.rb +85 -85
  207. data/lib/capybara/spec/session/selectors_spec.rb +49 -18
  208. data/lib/capybara/spec/session/sibling_spec.rb +9 -9
  209. data/lib/capybara/spec/session/text_spec.rb +25 -24
  210. data/lib/capybara/spec/session/title_spec.rb +7 -6
  211. data/lib/capybara/spec/session/uncheck_spec.rb +33 -21
  212. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  213. data/lib/capybara/spec/session/visit_spec.rb +68 -49
  214. data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
  215. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -1
  216. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +20 -16
  217. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +6 -2
  218. data/lib/capybara/spec/session/window/window_spec.rb +62 -63
  219. data/lib/capybara/spec/session/window/windows_spec.rb +5 -1
  220. data/lib/capybara/spec/session/window/within_window_spec.rb +14 -14
  221. data/lib/capybara/spec/session/within_spec.rb +79 -42
  222. data/lib/capybara/spec/spec_helper.rb +41 -53
  223. data/lib/capybara/spec/test_app.rb +132 -43
  224. data/lib/capybara/spec/views/animated.erb +49 -0
  225. data/lib/capybara/spec/views/form.erb +139 -42
  226. data/lib/capybara/spec/views/frame_child.erb +4 -3
  227. data/lib/capybara/spec/views/frame_one.erb +2 -1
  228. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  229. data/lib/capybara/spec/views/frame_two.erb +1 -1
  230. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  231. data/lib/capybara/spec/views/layout.erb +10 -0
  232. data/lib/capybara/spec/views/obscured.erb +47 -0
  233. data/lib/capybara/spec/views/offset.erb +33 -0
  234. data/lib/capybara/spec/views/path.erb +2 -2
  235. data/lib/capybara/spec/views/popup_one.erb +1 -1
  236. data/lib/capybara/spec/views/popup_two.erb +1 -1
  237. data/lib/capybara/spec/views/react.erb +45 -0
  238. data/lib/capybara/spec/views/scroll.erb +21 -0
  239. data/lib/capybara/spec/views/spatial.erb +31 -0
  240. data/lib/capybara/spec/views/tables.erb +67 -0
  241. data/lib/capybara/spec/views/with_animation.erb +39 -4
  242. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  243. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  244. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  245. data/lib/capybara/spec/views/with_hover.erb +3 -2
  246. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  247. data/lib/capybara/spec/views/with_html.erb +37 -9
  248. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  249. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  250. data/lib/capybara/spec/views/with_js.erb +26 -5
  251. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  252. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  253. data/lib/capybara/spec/views/with_scope.erb +2 -2
  254. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  255. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  256. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  257. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  258. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  259. data/lib/capybara/spec/views/with_windows.erb +1 -1
  260. data/lib/capybara/spec/views/within_frames.erb +1 -1
  261. data/lib/capybara/version.rb +1 -1
  262. data/lib/capybara/window.rb +19 -25
  263. data/lib/capybara.rb +126 -111
  264. data/spec/basic_node_spec.rb +59 -34
  265. data/spec/capybara_spec.rb +56 -44
  266. data/spec/counter_spec.rb +35 -0
  267. data/spec/css_builder_spec.rb +101 -0
  268. data/spec/css_splitter_spec.rb +8 -8
  269. data/spec/dsl_spec.rb +79 -52
  270. data/spec/filter_set_spec.rb +9 -9
  271. data/spec/fixtures/selenium_driver_rspec_failure.rb +4 -4
  272. data/spec/fixtures/selenium_driver_rspec_success.rb +4 -4
  273. data/spec/minitest_spec.rb +45 -7
  274. data/spec/minitest_spec_spec.rb +87 -64
  275. data/spec/per_session_config_spec.rb +6 -6
  276. data/spec/rack_test_spec.rb +172 -116
  277. data/spec/regexp_dissassembler_spec.rb +250 -0
  278. data/spec/result_spec.rb +80 -72
  279. data/spec/rspec/features_spec.rb +21 -16
  280. data/spec/rspec/scenarios_spec.rb +10 -6
  281. data/spec/rspec/shared_spec_matchers.rb +407 -365
  282. data/spec/rspec/views_spec.rb +3 -3
  283. data/spec/rspec_matchers_spec.rb +35 -10
  284. data/spec/rspec_spec.rb +63 -41
  285. data/spec/sauce_spec_chrome.rb +43 -0
  286. data/spec/selector_spec.rb +334 -89
  287. data/spec/selenium_spec_chrome.rb +176 -62
  288. data/spec/selenium_spec_chrome_remote.rb +54 -14
  289. data/spec/selenium_spec_edge.rb +41 -8
  290. data/spec/selenium_spec_firefox.rb +228 -0
  291. data/spec/selenium_spec_firefox_remote.rb +94 -0
  292. data/spec/selenium_spec_ie.rb +129 -11
  293. data/spec/selenium_spec_safari.rb +162 -0
  294. data/spec/server_spec.rb +171 -97
  295. data/spec/session_spec.rb +34 -18
  296. data/spec/shared_selenium_node.rb +79 -0
  297. data/spec/shared_selenium_session.rb +344 -80
  298. data/spec/spec_helper.rb +124 -2
  299. data/spec/whitespace_normalizer_spec.rb +54 -0
  300. data/spec/xpath_builder_spec.rb +93 -0
  301. metadata +326 -28
  302. data/lib/capybara/rspec/compound.rb +0 -94
  303. data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +0 -31
  304. data/lib/capybara/selenium/nodes/marionette_node.rb +0 -31
  305. data/lib/capybara/spec/session/has_style_spec.rb +0 -25
  306. data/lib/capybara/spec/session/source_spec.rb +0 -0
  307. data/lib/capybara/spec/views/with_title.erb +0 -5
  308. data/spec/selenium_spec_marionette.rb +0 -167
@@ -19,56 +19,58 @@ module Capybara
19
19
  # This will check if the expression occurs exactly 4 times.
20
20
  #
21
21
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
22
- # such as :text and :visible.
22
+ # such as `:text` and `:visible`.
23
23
  #
24
24
  # page.has_selector?('li', text: 'Horse', visible: true)
25
25
  #
26
- # has_selector? can also accept XPath expressions generated by the
26
+ # {#has_selector?} can also accept XPath expressions generated by the
27
27
  # XPath gem:
28
28
  #
29
29
  # page.has_selector?(:xpath, XPath.descendant(:p))
30
30
  #
31
31
  # @param (see Capybara::Node::Finders#all)
32
- # @param args
33
- # @option args [Integer] :count (nil) Number of times the text should occur
34
- # @option args [Integer] :minimum (nil) Minimum number of times the text should occur
35
- # @option args [Integer] :maximum (nil) Maximum number of times the text should occur
36
- # @option args [Range] :between (nil) Range of times that should contain number of times text occurs
32
+ # @option options [Integer] :count (nil) Number of matching elements that should exist
33
+ # @option options [Integer] :minimum (nil) Minimum number of matching elements that should exist
34
+ # @option options [Integer] :maximum (nil) Maximum number of matching elements that should exist
35
+ # @option options [Range] :between (nil) Range of number of matching elements that should exist
37
36
  # @return [Boolean] If the expression exists
38
37
  #
39
- def has_selector?(*args, &optional_filter_block)
40
- assert_selector(*args, &optional_filter_block)
41
- rescue Capybara::ExpectationNotMet
42
- false
38
+ def has_selector?(*args, **options, &optional_filter_block)
39
+ make_predicate(options) { assert_selector(*args, options, &optional_filter_block) }
43
40
  end
44
41
 
45
42
  ##
46
43
  #
47
44
  # Checks if a given selector is not on the page or a descendant of the current node.
48
- # Usage is identical to Capybara::Node::Matchers#has_selector?
45
+ # Usage is identical to {#has_selector?}.
49
46
  #
50
- # @param (see Capybara::Node::Finders#has_selector?)
47
+ # @param (see #has_selector?)
51
48
  # @return [Boolean]
52
49
  #
53
- def has_no_selector?(*args, &optional_filter_block)
54
- assert_no_selector(*args, &optional_filter_block)
55
- rescue Capybara::ExpectationNotMet
56
- false
50
+ def has_no_selector?(*args, **options, &optional_filter_block)
51
+ make_predicate(options) { assert_no_selector(*args, options, &optional_filter_block) }
57
52
  end
58
53
 
59
54
  ##
60
55
  #
61
- # Checks if a an element has the specified CSS styles
56
+ # Checks if a an element has the specified CSS styles.
62
57
  #
63
- # element.has_style?( 'color' => 'rgb(0,0,255)', 'font-size' => /px/ )
58
+ # element.matches_style?( 'color' => 'rgb(0,0,255)', 'font-size' => /px/ )
64
59
  #
65
60
  # @param styles [Hash]
66
61
  # @return [Boolean] If the styles match
67
62
  #
68
- def has_style?(styles, **options)
69
- assert_style(styles, **options)
70
- rescue Capybara::ExpectationNotMet
71
- false
63
+ def matches_style?(styles = nil, **options)
64
+ styles, options = options, {} if styles.nil?
65
+ make_predicate(options) { assert_matches_style(styles, **options) }
66
+ end
67
+
68
+ ##
69
+ # @deprecated Use {#matches_style?} instead.
70
+ #
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)}"
73
+ matches_style?(styles, **options)
72
74
  end
73
75
 
74
76
  ##
@@ -87,15 +89,15 @@ module Capybara
87
89
  # This will check if the expression occurs exactly 4 times. See
88
90
  # {Capybara::Node::Finders#all} for other available result size options.
89
91
  #
90
- # If a :count of 0 is specified, it will behave like {#assert_no_selector};
92
+ # If a `:count` of 0 is specified, it will behave like {#assert_no_selector};
91
93
  # however, use of that method is preferred over this one.
92
94
  #
93
95
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
94
- # such as :text and :visible.
96
+ # such as `:text` and `:visible`.
95
97
  #
96
98
  # page.assert_selector('li', text: 'Horse', visible: true)
97
99
  #
98
- # `assert_selector` can also accept XPath expressions generated by the
100
+ # {#assert_selector} can also accept XPath expressions generated by the
99
101
  # XPath gem:
100
102
  #
101
103
  # page.assert_selector(:xpath, XPath.descendant(:p))
@@ -114,86 +116,118 @@ module Capybara
114
116
 
115
117
  ##
116
118
  #
117
- # Asserts that an element has the specified CSS styles
119
+ # Asserts that an element has the specified CSS styles.
118
120
  #
119
- # element.assert_style( 'color' => 'rgb(0,0,255)', 'font-size' => /px/ )
121
+ # element.assert_matches_style( 'color' => 'rgb(0,0,255)', 'font-size' => /px/ )
120
122
  #
121
123
  # @param styles [Hash]
122
124
  # @raise [Capybara::ExpectationNotMet] If the element doesn't have the specified styles
123
125
  #
124
- def assert_style(styles, **options)
125
- query_args = _set_query_session_options(styles, options)
126
- 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)
127
130
  synchronize(query.wait) do
128
131
  raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
129
132
  end
130
133
  true
131
134
  end
132
135
 
136
+ ##
137
+ # @deprecated Use {#assert_matches_style} instead.
138
+ #
139
+ def assert_style(styles = nil, **options)
140
+ warn 'assert_style is deprecated, please use assert_matches_style instead'
141
+ assert_matches_style(styles, **options)
142
+ end
143
+
133
144
  # Asserts that all of the provided selectors are present on the given page
134
145
  # or descendants of the current node. If options are provided, the assertion
135
- # will check that each locator is present with those options as well (other than :wait).
146
+ # will check that each locator is present with those options as well (other than `:wait`).
136
147
  #
137
- # page.assert_all_of_selectors(:custom, 'Tom', 'Joe', visible: all)
138
- # 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')
139
150
  #
140
151
  # It accepts all options that {Capybara::Node::Finders#all} accepts,
141
- # such as :text and :visible.
152
+ # such as `:text` and `:visible`.
142
153
  #
143
- # The :wait option applies to all of the selectors as a group, so all of the locators must be present
144
- # within :wait (Defaults to Capybara.default_max_wait_time) seconds.
154
+ # The `:wait` option applies to all of the selectors as a group, so all of the locators must be present
155
+ # within `:wait` (defaults to {Capybara.configure default_max_wait_time}) seconds.
145
156
  #
146
157
  # @overload assert_all_of_selectors([kind = Capybara.default_selector], *locators, **options)
147
158
  #
148
- def assert_all_of_selectors(*args, wait: nil, **options, &optional_filter_block)
149
- wait = session_options.default_max_wait_time if wait.nil?
150
- selector = extract_selector(args)
151
- synchronize(wait) do
152
- args.each do |locator|
153
- assert_selector(selector, locator, options, &optional_filter_block)
154
- end
159
+ def assert_all_of_selectors(*args, **options, &optional_filter_block)
160
+ _verify_multiple(*args, **options) do |selector, locator, opts|
161
+ assert_selector(selector, locator, opts, &optional_filter_block)
155
162
  end
156
163
  end
157
164
 
158
165
  # Asserts that none of the provided selectors are present on the given page
159
166
  # or descendants of the current node. If options are provided, the assertion
160
- # will check that each locator is present with those options as well (other than :wait).
167
+ # will check that each locator is not present with those options as well (other than `:wait`).
161
168
  #
162
- # page.assert_none_of_selectors(:custom, 'Tom', 'Joe', visible: all)
163
- # 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')
164
171
  #
165
172
  # It accepts all options that {Capybara::Node::Finders#all} accepts,
166
- # such as :text and :visible.
173
+ # such as `:text` and `:visible`.
167
174
  #
168
- # The :wait option applies to all of the selectors as a group, so none of the locators must be present
169
- # within :wait (Defaults to Capybara.default_max_wait_time) seconds.
175
+ # The `:wait` option applies to all of the selectors as a group, so none of the locators must be present
176
+ # within `:wait` (defaults to {Capybara.configure default_max_wait_time}) seconds.
170
177
  #
171
178
  # @overload assert_none_of_selectors([kind = Capybara.default_selector], *locators, **options)
172
179
  #
173
- def assert_none_of_selectors(*args, wait: nil, **options, &optional_filter_block)
180
+ def assert_none_of_selectors(*args, **options, &optional_filter_block)
181
+ _verify_multiple(*args, **options) do |selector, locator, opts|
182
+ assert_no_selector(selector, locator, opts, &optional_filter_block)
183
+ end
184
+ end
185
+
186
+ # Asserts that any of the provided selectors are present on the given page
187
+ # or descendants of the current node. If options are provided, the assertion
188
+ # will check that each locator is present with those options as well (other than `:wait`).
189
+ #
190
+ # page.assert_any_of_selectors(:custom, 'Tom', 'Joe', visible: all)
191
+ # page.assert_any_of_selectors(:css, '#my_div', 'a.not_clicked')
192
+ #
193
+ # It accepts all options that {Capybara::Node::Finders#all} accepts,
194
+ # such as `:text` and `:visible`.
195
+ #
196
+ # The `:wait` option applies to all of the selectors as a group, so any of the locators must be present
197
+ # within `:wait` (defaults to {Capybara.configure default_max_wait_time}) seconds.
198
+ #
199
+ # @overload assert_any_of_selectors([kind = Capybara.default_selector], *locators, **options)
200
+ #
201
+ def assert_any_of_selectors(*args, wait: nil, **options, &optional_filter_block)
174
202
  wait = session_options.default_max_wait_time if wait.nil?
175
203
  selector = extract_selector(args)
176
204
  synchronize(wait) do
177
- args.each do |locator|
178
- assert_no_selector(selector, locator, options, &optional_filter_block)
205
+ res = args.map do |locator|
206
+ assert_selector(selector, locator, options, &optional_filter_block)
207
+ break nil
208
+ rescue Capybara::ExpectationNotMet => e
209
+ e.message
179
210
  end
211
+ raise Capybara::ExpectationNotMet, res.join(' or ') if res
212
+
213
+ true
180
214
  end
181
215
  end
182
216
 
183
217
  ##
184
218
  #
185
219
  # Asserts that a given selector is not on the page or a descendant of the current node.
186
- # Usage is identical to Capybara::Node::Matchers#assert_selector
220
+ # Usage is identical to {#assert_selector}.
187
221
  #
188
- # Query options such as :count, :minimum, :maximum, and :between are
222
+ # Query options such as `:count`, `:minimum`, `:maximum`, and `:between` are
189
223
  # considered to be an integral part of the selector. This will return
190
- # true, for example, if a page contains 4 anchors but the query expects 5:
224
+ # `true`, for example, if a page contains 4 anchors but the query expects 5:
191
225
  #
192
226
  # page.assert_no_selector('a', minimum: 1) # Found, raises Capybara::ExpectationNotMet
193
227
  # page.assert_no_selector('a', count: 4) # Found, raises Capybara::ExpectationNotMet
194
228
  # page.assert_no_selector('a', count: 5) # Not Found, returns true
195
229
  #
196
- # @param (see Capybara::Node::Finders#assert_selector)
230
+ # @param (see #assert_selector)
197
231
  # @raise [Capybara::ExpectationNotMet] If the selector exists
198
232
  #
199
233
  def assert_no_selector(*args, &optional_filter_block)
@@ -203,7 +237,6 @@ module Capybara
203
237
  end
204
238
  end
205
239
  end
206
- alias_method :refute_selector, :assert_no_selector
207
240
 
208
241
  ##
209
242
  #
@@ -219,11 +252,11 @@ module Capybara
219
252
  # This will check if the expression occurs exactly 4 times.
220
253
  #
221
254
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
222
- # such as :text and :visible.
255
+ # such as `:text` and `:visible`.
223
256
  #
224
257
  # page.has_xpath?('.//li', text: 'Horse', visible: true)
225
258
  #
226
- # has_xpath? can also accept XPath expressions generate by the
259
+ # {#has_xpath?} can also accept XPath expressions generated by the
227
260
  # XPath gem:
228
261
  #
229
262
  # xpath = XPath.generate { |x| x.descendant(:p) }
@@ -235,19 +268,19 @@ module Capybara
235
268
  # @return [Boolean] If the expression exists
236
269
  #
237
270
  def has_xpath?(path, **options, &optional_filter_block)
238
- has_selector?(:xpath, path, options, &optional_filter_block)
271
+ has_selector?(:xpath, path, **options, &optional_filter_block)
239
272
  end
240
273
 
241
274
  ##
242
275
  #
243
276
  # Checks if a given XPath expression is not on the page or a descendant of the current node.
244
- # Usage is identical to Capybara::Node::Matchers#has_xpath?
277
+ # Usage is identical to {#has_xpath?}.
245
278
  #
246
- # @param (see Capybara::Node::Finders#has_xpath?)
279
+ # @param (see #has_xpath?)
247
280
  # @return [Boolean]
248
281
  #
249
282
  def has_no_xpath?(path, **options, &optional_filter_block)
250
- has_no_selector?(:xpath, path, options, &optional_filter_block)
283
+ has_no_selector?(:xpath, path, **options, &optional_filter_block)
251
284
  end
252
285
 
253
286
  ##
@@ -264,7 +297,7 @@ module Capybara
264
297
  # This will check if the selector occurs exactly 4 times.
265
298
  #
266
299
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
267
- # such as :text and :visible.
300
+ # such as `:text` and `:visible`.
268
301
  #
269
302
  # page.has_css?('li', text: 'Horse', visible: true)
270
303
  #
@@ -274,19 +307,44 @@ module Capybara
274
307
  # @return [Boolean] If the selector exists
275
308
  #
276
309
  def has_css?(path, **options, &optional_filter_block)
277
- has_selector?(:css, path, options, &optional_filter_block)
310
+ has_selector?(:css, path, **options, &optional_filter_block)
278
311
  end
279
312
 
280
313
  ##
281
314
  #
282
315
  # Checks if a given CSS selector is not on the page or a descendant of the current node.
283
- # Usage is identical to Capybara::Node::Matchers#has_css?
316
+ # Usage is identical to {#has_css?}.
284
317
  #
285
- # @param (see Capybara::Node::Finders#has_css?)
318
+ # @param (see #has_css?)
286
319
  # @return [Boolean]
287
320
  #
288
321
  def has_no_css?(path, **options, &optional_filter_block)
289
- has_no_selector?(:css, path, options, &optional_filter_block)
322
+ has_no_selector?(:css, path, **options, &optional_filter_block)
323
+ end
324
+
325
+ ##
326
+ #
327
+ # Checks if the page or current node has a element with the given
328
+ # local name.
329
+ #
330
+ # @param [String] locator The local name of a element to check for
331
+ # @option options [String, Regexp] The attributes values of matching elements
332
+ # @return [Boolean] Whether it exists
333
+ #
334
+ def has_element?(locator = nil, **options, &optional_filter_block)
335
+ has_selector?(:element, locator, **options, &optional_filter_block)
336
+ end
337
+
338
+ ##
339
+ #
340
+ # Checks if the page or current node has no element with the given
341
+ # local name.
342
+ #
343
+ # @param (see #has_element?)
344
+ # @return [Boolean] Whether it doesn't exist
345
+ #
346
+ def has_no_element?(locator = nil, **options, &optional_filter_block)
347
+ has_no_selector?(:element, locator, **options, &optional_filter_block)
290
348
  end
291
349
 
292
350
  ##
@@ -295,12 +353,11 @@ module Capybara
295
353
  # text or id.
296
354
  #
297
355
  # @param [String] locator The text or id of a link to check for
298
- # @param options
299
356
  # @option options [String, Regexp] :href The value the href attribute must be
300
357
  # @return [Boolean] Whether it exists
301
358
  #
302
359
  def has_link?(locator = nil, **options, &optional_filter_block)
303
- has_selector?(:link, locator, options, &optional_filter_block)
360
+ has_selector?(:link, locator, **options, &optional_filter_block)
304
361
  end
305
362
 
306
363
  ##
@@ -308,11 +365,11 @@ module Capybara
308
365
  # Checks if the page or current node has no link with the given
309
366
  # text or id.
310
367
  #
311
- # @param (see Capybara::Node::Finders#has_link?)
368
+ # @param (see #has_link?)
312
369
  # @return [Boolean] Whether it doesn't exist
313
370
  #
314
371
  def has_no_link?(locator = nil, **options, &optional_filter_block)
315
- has_no_selector?(:link, locator, options, &optional_filter_block)
372
+ has_no_selector?(:link, locator, **options, &optional_filter_block)
316
373
  end
317
374
 
318
375
  ##
@@ -324,7 +381,7 @@ module Capybara
324
381
  # @return [Boolean] Whether it exists
325
382
  #
326
383
  def has_button?(locator = nil, **options, &optional_filter_block)
327
- has_selector?(:button, locator, options, &optional_filter_block)
384
+ has_selector?(:button, locator, **options, &optional_filter_block)
328
385
  end
329
386
 
330
387
  ##
@@ -336,7 +393,7 @@ module Capybara
336
393
  # @return [Boolean] Whether it doesn't exist
337
394
  #
338
395
  def has_no_button?(locator = nil, **options, &optional_filter_block)
339
- has_no_selector?(:button, locator, options, &optional_filter_block)
396
+ has_no_selector?(:button, locator, **options, &optional_filter_block)
340
397
  end
341
398
 
342
399
  ##
@@ -345,7 +402,7 @@ module Capybara
345
402
  # label, name or id.
346
403
  #
347
404
  # For text fields and other textual fields, such as textareas and
348
- # HTML5 email/url/etc. fields, it's possible to specify a :with
405
+ # HTML5 email/url/etc. fields, it's possible to specify a `:with`
349
406
  # option to specify the text the field should contain:
350
407
  #
351
408
  # page.has_field?('Name', with: 'Jonas')
@@ -354,7 +411,7 @@ module Capybara
354
411
  #
355
412
  # page.has_field?('Email', type: 'email')
356
413
  #
357
- # Note: 'textarea' and 'select' are valid type values, matching the associated tag names.
414
+ # NOTE: 'textarea' and 'select' are valid type values, matching the associated tag names.
358
415
  #
359
416
  # @param [String] locator The label, name or id of a field to check for
360
417
  # @option options [String, Regexp] :with The text content of the field or a Regexp to match
@@ -362,13 +419,13 @@ module Capybara
362
419
  # @return [Boolean] Whether it exists
363
420
  #
364
421
  def has_field?(locator = nil, **options, &optional_filter_block)
365
- has_selector?(:field, locator, options, &optional_filter_block)
422
+ has_selector?(:field, locator, **options, &optional_filter_block)
366
423
  end
367
424
 
368
425
  ##
369
426
  #
370
427
  # Checks if the page or current node has no form field with the given
371
- # label, name or id. See {Capybara::Node::Matchers#has_field?}.
428
+ # label, name or id. See {#has_field?}.
372
429
  #
373
430
  # @param [String] locator The label, name or id of a field to check for
374
431
  # @option options [String, Regexp] :with The text content of the field or a Regexp to match
@@ -376,59 +433,59 @@ module Capybara
376
433
  # @return [Boolean] Whether it doesn't exist
377
434
  #
378
435
  def has_no_field?(locator = nil, **options, &optional_filter_block)
379
- has_no_selector?(:field, locator, options, &optional_filter_block)
436
+ has_no_selector?(:field, locator, **options, &optional_filter_block)
380
437
  end
381
438
 
382
439
  ##
383
440
  #
384
441
  # Checks if the page or current node has a radio button or
385
- # checkbox with the given label, value or id, that is currently
442
+ # checkbox with the given label, value, id, or {Capybara.configure test_id} attribute that is currently
386
443
  # checked.
387
444
  #
388
445
  # @param [String] locator The label, name or id of a checked field
389
446
  # @return [Boolean] Whether it exists
390
447
  #
391
448
  def has_checked_field?(locator = nil, **options, &optional_filter_block)
392
- has_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
449
+ has_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
393
450
  end
394
451
 
395
452
  ##
396
453
  #
397
454
  # Checks if the page or current node has no radio button or
398
- # checkbox with the given label, value or id, that is currently
455
+ # checkbox with the given label, value or id, or {Capybara.configure test_id} attribute that is currently
399
456
  # checked.
400
457
  #
401
458
  # @param [String] locator The label, name or id of a checked field
402
459
  # @return [Boolean] Whether it doesn't exist
403
460
  #
404
461
  def has_no_checked_field?(locator = nil, **options, &optional_filter_block)
405
- has_no_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
462
+ has_no_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
406
463
  end
407
464
 
408
465
  ##
409
466
  #
410
467
  # Checks if the page or current node has a radio button or
411
- # checkbox with the given label, value or id, that is currently
468
+ # checkbox with the given label, value or id, or {Capybara.configure test_id} attribute that is currently
412
469
  # unchecked.
413
470
  #
414
471
  # @param [String] locator The label, name or id of an unchecked field
415
472
  # @return [Boolean] Whether it exists
416
473
  #
417
474
  def has_unchecked_field?(locator = nil, **options, &optional_filter_block)
418
- has_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
475
+ has_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
419
476
  end
420
477
 
421
478
  ##
422
479
  #
423
480
  # Checks if the page or current node has no radio button or
424
- # checkbox with the given label, value or id, that is currently
481
+ # checkbox with the given label, value or id, or {Capybara.configure test_id} attribute that is currently
425
482
  # unchecked.
426
483
  #
427
484
  # @param [String] locator The label, name or id of an unchecked field
428
485
  # @return [Boolean] Whether it doesn't exist
429
486
  #
430
487
  def has_no_unchecked_field?(locator = nil, **options, &optional_filter_block)
431
- has_no_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
488
+ has_no_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
432
489
  end
433
490
 
434
491
  ##
@@ -461,19 +518,19 @@ module Capybara
461
518
  # @return [Boolean] Whether it exists
462
519
  #
463
520
  def has_select?(locator = nil, **options, &optional_filter_block)
464
- has_selector?(:select, locator, options, &optional_filter_block)
521
+ has_selector?(:select, locator, **options, &optional_filter_block)
465
522
  end
466
523
 
467
524
  ##
468
525
  #
469
526
  # Checks if the page or current node has no select field with the
470
- # given label, name or id. See {Capybara::Node::Matchers#has_select?}.
527
+ # given label, name or id. See {#has_select?}.
471
528
  #
472
- # @param (see Capybara::Node::Matchers#has_select?)
529
+ # @param (see #has_select?)
473
530
  # @return [Boolean] Whether it doesn't exist
474
531
  #
475
532
  def has_no_select?(locator = nil, **options, &optional_filter_block)
476
- has_no_selector?(:select, locator, options, &optional_filter_block)
533
+ has_no_selector?(:select, locator, **options, &optional_filter_block)
477
534
  end
478
535
 
479
536
  ##
@@ -483,35 +540,43 @@ module Capybara
483
540
  #
484
541
  # page.has_table?('People')
485
542
  #
486
- # @param [String] locator The id or caption of a table
487
- # @return [Boolean] Whether it exist
543
+ # @param [String] locator The id or caption of a table
544
+ # @option options [Array<Array<String>>] :rows
545
+ # Text which should be contained in the tables `<td>` elements organized by row (`<td>` visibility is not considered)
546
+ # @option options [Array<Array<String>>, Array<Hash<String,String>>] :with_rows
547
+ # Partial set of text which should be contained in the tables `<td>` elements organized by row (`<td>` visibility is not considered)
548
+ # @option options [Array<Array<String>>] :cols
549
+ # Text which should be contained in the tables `<td>` elements organized by column (`<td>` visibility is not considered)
550
+ # @option options [Array<Array<String>>, Array<Hash<String,String>>] :with_cols
551
+ # Partial set of text which should be contained in the tables `<td>` elements organized by column (`<td>` visibility is not considered)
552
+ # @return [Boolean] Whether it exists
488
553
  #
489
554
  def has_table?(locator = nil, **options, &optional_filter_block)
490
- has_selector?(:table, locator, options, &optional_filter_block)
555
+ has_selector?(:table, locator, **options, &optional_filter_block)
491
556
  end
492
557
 
493
558
  ##
494
559
  #
495
560
  # Checks if the page or current node has no table with the given id
496
- # or caption. See {Capybara::Node::Matchers#has_table?}.
561
+ # or caption. See {#has_table?}.
497
562
  #
498
- # @param (see Capybara::Node::Matchers#has_table?)
563
+ # @param (see #has_table?)
499
564
  # @return [Boolean] Whether it doesn't exist
500
565
  #
501
566
  def has_no_table?(locator = nil, **options, &optional_filter_block)
502
- has_no_selector?(:table, locator, options, &optional_filter_block)
567
+ has_no_selector?(:table, locator, **options, &optional_filter_block)
503
568
  end
504
569
 
505
570
  ##
506
571
  #
507
- # Asserts that the current_node matches a given selector
572
+ # Asserts that the current node matches a given selector.
508
573
  #
509
574
  # node.assert_matches_selector('p#foo')
510
575
  # node.assert_matches_selector(:xpath, '//p[@id="foo"]')
511
576
  # node.assert_matches_selector(:foo)
512
577
  #
513
578
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
514
- # such as :text and :visible.
579
+ # such as `:text` and `:visible`.
515
580
  #
516
581
  # node.assert_matches_selector('li', text: 'Horse', visible: true)
517
582
  #
@@ -520,86 +585,89 @@ module Capybara
520
585
  #
521
586
  def assert_matches_selector(*args, &optional_filter_block)
522
587
  _verify_match_result(args, optional_filter_block) do |result|
523
- raise Capybara::ExpectationNotMet, "Item does not match the provided selector" unless result.include? self
588
+ raise Capybara::ExpectationNotMet, 'Item does not match the provided selector' unless result.include? self
524
589
  end
525
590
  end
526
591
 
592
+ ##
593
+ #
594
+ # Asserts that the current node does not match a given selector.
595
+ # Usage is identical to {#assert_matches_selector}.
596
+ #
597
+ # @param (see #assert_matches_selector)
598
+ # @raise [Capybara::ExpectationNotMet] If the selector matches
599
+ #
527
600
  def assert_not_matches_selector(*args, &optional_filter_block)
528
601
  _verify_match_result(args, optional_filter_block) do |result|
529
602
  raise Capybara::ExpectationNotMet, 'Item matched the provided selector' if result.include? self
530
603
  end
531
604
  end
532
- alias_method :refute_matches_selector, :assert_not_matches_selector
533
605
 
534
606
  ##
535
607
  #
536
- # Checks if the current node matches given selector
608
+ # Checks if the current node matches given selector.
537
609
  #
538
- # @param (see Capybara::Node::Finders#has_selector?)
610
+ # @param (see #has_selector?)
539
611
  # @return [Boolean]
540
612
  #
541
- def matches_selector?(*args, &optional_filter_block)
542
- assert_matches_selector(*args, &optional_filter_block)
543
- rescue Capybara::ExpectationNotMet
544
- false
613
+ def matches_selector?(*args, **options, &optional_filter_block)
614
+ make_predicate(options) { assert_matches_selector(*args, options, &optional_filter_block) }
545
615
  end
546
616
 
547
617
  ##
548
618
  #
549
- # Checks if the current node matches given XPath expression
619
+ # Checks if the current node matches given XPath expression.
550
620
  #
551
621
  # @param [String, XPath::Expression] xpath The XPath expression to match against the current code
552
622
  # @return [Boolean]
553
623
  #
554
624
  def matches_xpath?(xpath, **options, &optional_filter_block)
555
- matches_selector?(:xpath, xpath, options, &optional_filter_block)
625
+ matches_selector?(:xpath, xpath, **options, &optional_filter_block)
556
626
  end
557
627
 
558
628
  ##
559
629
  #
560
- # Checks if the current node matches given CSS selector
630
+ # Checks if the current node matches given CSS selector.
561
631
  #
562
632
  # @param [String] css The CSS selector to match against the current code
563
633
  # @return [Boolean]
564
634
  #
565
635
  def matches_css?(css, **options, &optional_filter_block)
566
- matches_selector?(:css, css, options, &optional_filter_block)
636
+ matches_selector?(:css, css, **options, &optional_filter_block)
567
637
  end
568
638
 
569
639
  ##
570
640
  #
571
- # Checks if the current node does not match given selector
572
- # Usage is identical to Capybara::Node::Matchers#has_selector?
641
+ # Checks if the current node does not match given selector.
642
+ # Usage is identical to {#has_selector?}.
573
643
  #
574
- # @param (see Capybara::Node::Finders#has_selector?)
644
+ # @param (see #has_selector?)
575
645
  # @return [Boolean]
576
646
  #
577
- def not_matches_selector?(*args, &optional_filter_block)
578
- assert_not_matches_selector(*args, &optional_filter_block)
579
- rescue Capybara::ExpectationNotMet
580
- false
647
+ def not_matches_selector?(*args, **options, &optional_filter_block)
648
+ make_predicate(options) { assert_not_matches_selector(*args, options, &optional_filter_block) }
581
649
  end
582
650
 
583
651
  ##
584
652
  #
585
- # Checks if the current node does not match given XPath expression
653
+ # Checks if the current node does not match given XPath expression.
586
654
  #
587
655
  # @param [String, XPath::Expression] xpath The XPath expression to match against the current code
588
656
  # @return [Boolean]
589
657
  #
590
658
  def not_matches_xpath?(xpath, **options, &optional_filter_block)
591
- not_matches_selector?(:xpath, xpath, options, &optional_filter_block)
659
+ not_matches_selector?(:xpath, xpath, **options, &optional_filter_block)
592
660
  end
593
661
 
594
662
  ##
595
663
  #
596
- # Checks if the current node does not match given CSS selector
664
+ # Checks if the current node does not match given CSS selector.
597
665
  #
598
666
  # @param [String] css The CSS selector to match against the current code
599
667
  # @return [Boolean]
600
668
  #
601
669
  def not_matches_css?(css, **options, &optional_filter_block)
602
- not_matches_selector?(:css, css, options, &optional_filter_block)
670
+ not_matches_selector?(:css, css, **options, &optional_filter_block)
603
671
  end
604
672
 
605
673
  ##
@@ -608,27 +676,29 @@ module Capybara
608
676
  #
609
677
  # @!macro text_query_params
610
678
  # @overload $0(type, text, **options)
611
- # @param [:all, :visible] type Whether to check for only visible or all text. If this parameter is missing or nil then we use the value of `Capybara.ignore_hidden_elements`, which defaults to `true`, corresponding to `:visible`.
679
+ # @param [:all, :visible] type Whether to check for only visible or all text. If this parameter is missing or nil then we use the value of {Capybara.configure ignore_hidden_elements}, which defaults to `true`, corresponding to `:visible`.
612
680
  # @param [String, Regexp] text The string/regexp to check for. If it's a string, text is expected to include it. If it's a regexp, text is expected to match it.
613
681
  # @option options [Integer] :count (nil) Number of times the text is expected to occur
614
682
  # @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur
615
683
  # @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
616
684
  # @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
617
- # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
618
- # @option options [Boolean] :exact (Capybara.exact_text) Whether text must be an exact match or just substring
685
+ # @option options [Numeric] :wait Maximum time that Capybara will wait for text to eq/match given string/regexp argument. Defaults to {Capybara.configure default_max_wait_time}.
686
+ # @option options [Boolean] :exact Whether text must be an exact match or just substring. Defaults to {Capybara.configure exact_text}.
687
+ # @option options [Boolean] :normalize_ws (false) When `true` replace all whitespace with standard spaces and collapse consecutive whitespace to a single space
619
688
  # @overload $0(text, **options)
620
689
  # @param [String, Regexp] text The string/regexp to check for. If it's a string, text is expected to include it. If it's a regexp, text is expected to match it.
621
690
  # @option options [Integer] :count (nil) Number of times the text is expected to occur
622
691
  # @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur
623
692
  # @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
624
693
  # @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
625
- # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
626
- # @option options [Boolean] :exact (Capybara.exact_text) Whether text must be an exact match or just substring
694
+ # @option options [Numeric] :wait Maximum time that Capybara will wait for text to eq/match given string/regexp argument. Defaults to {Capybara.configure default_max_wait_time}.
695
+ # @option options [Boolean] :exact Whether text must be an exact match or just substring. Defaults to {Capybara.configure exact_text}.
696
+ # @option options [Boolean] :normalize_ws (false) When `true` replace all whitespace with standard spaces and collapse consecutive whitespace to a single space
627
697
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
628
698
  # @return [true]
629
699
  #
630
- def assert_text(*args)
631
- _verify_text(args) do |count, query|
700
+ def assert_text(type_or_text, *args, **opts)
701
+ _verify_text(type_or_text, *args, **opts) do |count, query|
632
702
  unless query.matches_count?(count) && (count.positive? || query.expects_none?)
633
703
  raise Capybara::ExpectationNotMet, query.failure_message
634
704
  end
@@ -643,8 +713,8 @@ module Capybara
643
713
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
644
714
  # @return [true]
645
715
  #
646
- def assert_no_text(*args)
647
- _verify_text(args) do |count, query|
716
+ def assert_no_text(type_or_text, *args, **opts)
717
+ _verify_text(type_or_text, *args, **opts) do |count, query|
648
718
  if query.matches_count?(count) && (count.positive? || query.expects_none?)
649
719
  raise Capybara::ExpectationNotMet, query.negative_failure_message
650
720
  end
@@ -665,10 +735,8 @@ module Capybara
665
735
  # @macro text_query_params
666
736
  # @return [Boolean] Whether it exists
667
737
  #
668
- def has_text?(*args)
669
- assert_text(*args)
670
- rescue Capybara::ExpectationNotMet
671
- false
738
+ def has_text?(*args, **options)
739
+ make_predicate(options) { assert_text(*args, **options) }
672
740
  end
673
741
  alias_method :has_content?, :has_text?
674
742
 
@@ -679,13 +747,97 @@ module Capybara
679
747
  # @macro text_query_params
680
748
  # @return [Boolean] Whether it doesn't exist
681
749
  #
682
- def has_no_text?(*args)
683
- assert_no_text(*args)
684
- rescue Capybara::ExpectationNotMet
685
- false
750
+ def has_no_text?(*args, **options)
751
+ make_predicate(options) { assert_no_text(*args, **options) }
686
752
  end
687
753
  alias_method :has_no_content?, :has_no_text?
688
754
 
755
+ ##
756
+ #
757
+ # Asserts that a given selector matches an ancestor of the current node.
758
+ #
759
+ # element.assert_ancestor('p#foo')
760
+ #
761
+ # Accepts the same options as {#assert_selector}
762
+ #
763
+ # @param (see Capybara::Node::Finders#find)
764
+ # @raise [Capybara::ExpectationNotMet] If the selector does not exist
765
+ #
766
+ def assert_ancestor(*args, &optional_filter_block)
767
+ _verify_selector_result(args, optional_filter_block, Capybara::Queries::AncestorQuery) do |result, query|
768
+ unless result.matches_count? && (result.any? || query.expects_none?)
769
+ raise Capybara::ExpectationNotMet, result.failure_message
770
+ end
771
+ end
772
+ end
773
+
774
+ def assert_no_ancestor(*args, &optional_filter_block)
775
+ _verify_selector_result(args, optional_filter_block, Capybara::Queries::AncestorQuery) do |result, query|
776
+ if result.matches_count? && (!result.empty? || query.expects_none?)
777
+ raise Capybara::ExpectationNotMet, result.negative_failure_message
778
+ end
779
+ end
780
+ end
781
+
782
+ ##
783
+ #
784
+ # Predicate version of {#assert_ancestor}
785
+ #
786
+ def has_ancestor?(*args, **options, &optional_filter_block)
787
+ make_predicate(options) { assert_ancestor(*args, options, &optional_filter_block) }
788
+ end
789
+
790
+ ##
791
+ #
792
+ # Predicate version of {#assert_no_ancestor}
793
+ #
794
+ def has_no_ancestor?(*args, **options, &optional_filter_block)
795
+ make_predicate(options) { assert_no_ancestor(*args, options, &optional_filter_block) }
796
+ end
797
+
798
+ ##
799
+ #
800
+ # Asserts that a given selector matches a sibling of the current node.
801
+ #
802
+ # element.assert_sibling('p#foo')
803
+ #
804
+ # Accepts the same options as {#assert_selector}
805
+ #
806
+ # @param (see Capybara::Node::Finders#find)
807
+ # @raise [Capybara::ExpectationNotMet] If the selector does not exist
808
+ #
809
+ def assert_sibling(*args, &optional_filter_block)
810
+ _verify_selector_result(args, optional_filter_block, Capybara::Queries::SiblingQuery) do |result, query|
811
+ unless result.matches_count? && (result.any? || query.expects_none?)
812
+ raise Capybara::ExpectationNotMet, result.failure_message
813
+ end
814
+ end
815
+ end
816
+
817
+ def assert_no_sibling(*args, &optional_filter_block)
818
+ _verify_selector_result(args, optional_filter_block, Capybara::Queries::SiblingQuery) do |result, query|
819
+ if result.matches_count? && (!result.empty? || query.expects_none?)
820
+ raise Capybara::ExpectationNotMet, result.negative_failure_message
821
+ end
822
+ end
823
+ end
824
+
825
+ ##
826
+ #
827
+ # Predicate version of {#assert_sibling}
828
+ #
829
+ def has_sibling?(*args, **options, &optional_filter_block)
830
+ make_predicate(options) { assert_sibling(*args, options, &optional_filter_block) }
831
+ end
832
+
833
+ ##
834
+ #
835
+ # Predicate version of {#assert_no_sibling}
836
+ #
837
+ def has_no_sibling?(*args, **options, &optional_filter_block)
838
+ make_predicate(options) { assert_no_sibling(*args, options, &optional_filter_block) }
839
+ end
840
+
689
841
  def ==(other)
690
842
  eql?(other) || (other.respond_to?(:base) && base == other.base)
691
843
  end
@@ -696,9 +848,23 @@ module Capybara
696
848
  args.first.is_a?(Symbol) ? args.shift : session_options.default_selector
697
849
  end
698
850
 
699
- def _verify_selector_result(query_args, optional_filter_block)
700
- query_args = _set_query_session_options(*query_args)
701
- query = Capybara::Queries::SelectorQuery.new(*query_args, &optional_filter_block)
851
+ def _verify_multiple(*args, wait: nil, **options)
852
+ wait = session_options.default_max_wait_time if wait.nil?
853
+ selector = extract_selector(args)
854
+ synchronize(wait) do
855
+ args.each { |locator| yield(selector, locator, options) }
856
+ end
857
+ end
858
+
859
+ def _verify_selector_result(query_args, optional_filter_block, query_type = Capybara::Queries::SelectorQuery)
860
+ # query_args, query_opts = if query_args[0].is_a? Symbol
861
+ # a,o = _set_query_session_options(*query_args.slice(2..))
862
+ # [query_args.slice(0..1).concat(a), o]
863
+ # else
864
+ # _set_query_session_options(*query_args)
865
+ # end
866
+ query_args, query_opts = _set_query_session_options(*query_args)
867
+ query = query_type.new(*query_args, **query_opts, &optional_filter_block)
702
868
  synchronize(query.wait) do
703
869
  yield query.resolve_for(self), query
704
870
  end
@@ -706,26 +872,36 @@ module Capybara
706
872
  end
707
873
 
708
874
  def _verify_match_result(query_args, optional_filter_block)
709
- query_args = _set_query_session_options(*query_args)
710
- query = Capybara::Queries::MatchQuery.new(*query_args, &optional_filter_block)
875
+ query_args, query_opts = _set_query_session_options(*query_args)
876
+ query = Capybara::Queries::MatchQuery.new(*query_args, **query_opts, &optional_filter_block)
711
877
  synchronize(query.wait) do
712
- yield query.resolve_for(query_scope)
878
+ yield query.resolve_for(parent || session&.document || query_scope)
713
879
  end
714
880
  true
715
881
  end
716
882
 
717
- def _verify_text(query_args)
718
- query_args = _set_query_session_options(*query_args)
719
- query = Capybara::Queries::TextQuery.new(*query_args)
883
+ def _verify_text(type = nil, expected_text, **query_options) # rubocop:disable Style/OptionalArguments
884
+ query_options[:session_options] = session_options
885
+ query = Capybara::Queries::TextQuery.new(type, expected_text, **query_options)
720
886
  synchronize(query.wait) do
721
887
  yield query.resolve_for(self), query
722
888
  end
723
889
  true
724
890
  end
725
891
 
726
- def _set_query_session_options(*query_args, **query_options)
892
+ def _set_query_session_options(*query_args)
893
+ query_args, query_options = query_args.dup, {}
894
+ # query_options = query_args.pop if query_options.empty? && query_args.last.is_a?(Hash)
895
+ query_options = query_args.pop if query_args.last.is_a?(Hash)
727
896
  query_options[:session_options] = session_options
728
- query_args.push(query_options)
897
+ [query_args, query_options]
898
+ end
899
+
900
+ def make_predicate(options)
901
+ options[:wait] = 0 unless options.key?(:wait) || session_options.predicates_wait
902
+ yield
903
+ rescue Capybara::ExpectationNotMet
904
+ false
729
905
  end
730
906
  end
731
907
  end