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