capybara 3.3.0 → 3.40.0

Sign up to get free protection for your applications and to get access to all the features.
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