capybara 2.18.0 → 3.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (315) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +889 -12
  4. data/License.txt +1 -1
  5. data/README.md +108 -78
  6. data/lib/capybara/config.rb +29 -57
  7. data/lib/capybara/cucumber.rb +2 -3
  8. data/lib/capybara/driver/base.rb +35 -18
  9. data/lib/capybara/driver/node.rb +40 -10
  10. data/lib/capybara/dsl.rb +10 -7
  11. data/lib/capybara/helpers.rb +70 -31
  12. data/lib/capybara/minitest/spec.rb +173 -83
  13. data/lib/capybara/minitest.rb +219 -112
  14. data/lib/capybara/node/actions.rb +274 -171
  15. data/lib/capybara/node/base.rb +42 -34
  16. data/lib/capybara/node/document.rb +15 -3
  17. data/lib/capybara/node/document_matchers.rb +19 -21
  18. data/lib/capybara/node/element.rb +362 -135
  19. data/lib/capybara/node/finders.rb +149 -137
  20. data/lib/capybara/node/matchers.rb +369 -209
  21. data/lib/capybara/node/simple.rb +59 -26
  22. data/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/lib/capybara/queries/ancestor_query.rb +12 -9
  24. data/lib/capybara/queries/base_query.rb +39 -28
  25. data/lib/capybara/queries/current_path_query.rb +21 -27
  26. data/lib/capybara/queries/match_query.rb +14 -7
  27. data/lib/capybara/queries/selector_query.rb +658 -149
  28. data/lib/capybara/queries/sibling_query.rb +11 -9
  29. data/lib/capybara/queries/style_query.rb +45 -0
  30. data/lib/capybara/queries/text_query.rb +56 -38
  31. data/lib/capybara/queries/title_query.rb +8 -11
  32. data/lib/capybara/rack_test/browser.rb +113 -42
  33. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  34. data/lib/capybara/rack_test/driver.rb +22 -17
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +93 -58
  37. data/lib/capybara/rack_test/node.rb +188 -81
  38. data/lib/capybara/rails.rb +3 -7
  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 +53 -0
  43. data/lib/capybara/result.rb +96 -62
  44. data/lib/capybara/rspec/features.rb +17 -50
  45. data/lib/capybara/rspec/matcher_proxies.rb +52 -15
  46. data/lib/capybara/rspec/matchers/base.rb +111 -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 +77 -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 +142 -311
  60. data/lib/capybara/rspec.rb +7 -11
  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 +89 -17
  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 +54 -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 +2 -17
  87. data/lib/capybara/selector/filter_set.rb +80 -33
  88. data/lib/capybara/selector/filters/base.rb +50 -6
  89. data/lib/capybara/selector/filters/expression_filter.rb +8 -26
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +16 -12
  92. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  93. data/lib/capybara/selector/selector.rb +93 -210
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selector.rb +227 -526
  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 +332 -261
  101. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  102. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
  103. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -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 +226 -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/logger_suppressor.rb +44 -0
  112. data/lib/capybara/selenium/node.rb +545 -144
  113. data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
  114. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  115. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  116. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  117. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  118. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  119. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  120. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  121. data/lib/capybara/selenium/patches/logs.rb +45 -0
  122. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  123. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  124. data/lib/capybara/server/animation_disabler.rb +81 -0
  125. data/lib/capybara/server/checker.rb +44 -0
  126. data/lib/capybara/server/middleware.rb +71 -0
  127. data/lib/capybara/server.rb +59 -67
  128. data/lib/capybara/session/config.rb +81 -67
  129. data/lib/capybara/session/matchers.rb +28 -20
  130. data/lib/capybara/session.rb +336 -365
  131. data/lib/capybara/spec/public/jquery.js +5 -5
  132. data/lib/capybara/spec/public/offset.js +6 -0
  133. data/lib/capybara/spec/public/test.js +147 -12
  134. data/lib/capybara/spec/session/accept_alert_spec.rb +12 -11
  135. data/lib/capybara/spec/session/accept_confirm_spec.rb +6 -5
  136. data/lib/capybara/spec/session/accept_prompt_spec.rb +10 -10
  137. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  138. data/lib/capybara/spec/session/all_spec.rb +160 -56
  139. data/lib/capybara/spec/session/ancestor_spec.rb +27 -24
  140. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +68 -38
  141. data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
  142. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  143. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  144. data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
  145. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +22 -12
  146. data/lib/capybara/spec/session/attach_file_spec.rb +144 -69
  147. data/lib/capybara/spec/session/body_spec.rb +12 -13
  148. data/lib/capybara/spec/session/check_spec.rb +117 -55
  149. data/lib/capybara/spec/session/choose_spec.rb +64 -31
  150. data/lib/capybara/spec/session/click_button_spec.rb +231 -173
  151. data/lib/capybara/spec/session/click_link_or_button_spec.rb +55 -35
  152. data/lib/capybara/spec/session/click_link_spec.rb +82 -58
  153. data/lib/capybara/spec/session/current_scope_spec.rb +12 -11
  154. data/lib/capybara/spec/session/current_url_spec.rb +57 -39
  155. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +4 -4
  156. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +3 -2
  157. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  158. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  159. data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
  160. data/lib/capybara/spec/session/element/matches_selector_spec.rb +71 -57
  161. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +8 -7
  162. data/lib/capybara/spec/session/evaluate_script_spec.rb +29 -8
  163. data/lib/capybara/spec/session/execute_script_spec.rb +10 -8
  164. data/lib/capybara/spec/session/fill_in_spec.rb +134 -43
  165. data/lib/capybara/spec/session/find_button_spec.rb +25 -24
  166. data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
  167. data/lib/capybara/spec/session/find_field_spec.rb +37 -41
  168. data/lib/capybara/spec/session/find_link_spec.rb +36 -17
  169. data/lib/capybara/spec/session/find_spec.rb +251 -144
  170. data/lib/capybara/spec/session/first_spec.rb +79 -51
  171. data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  172. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  173. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +33 -20
  174. data/lib/capybara/spec/session/frame/within_frame_spec.rb +50 -32
  175. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  176. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  177. data/lib/capybara/spec/session/has_all_selectors_spec.rb +31 -31
  178. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  179. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  180. data/lib/capybara/spec/session/has_button_spec.rb +100 -13
  181. data/lib/capybara/spec/session/has_css_spec.rb +272 -137
  182. data/lib/capybara/spec/session/has_current_path_spec.rb +59 -60
  183. data/lib/capybara/spec/session/has_field_spec.rb +139 -59
  184. data/lib/capybara/spec/session/has_link_spec.rb +43 -6
  185. data/lib/capybara/spec/session/has_none_selectors_spec.rb +42 -40
  186. data/lib/capybara/spec/session/has_select_spec.rb +107 -72
  187. data/lib/capybara/spec/session/has_selector_spec.rb +120 -71
  188. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  189. data/lib/capybara/spec/session/has_table_spec.rb +172 -5
  190. data/lib/capybara/spec/session/has_text_spec.rb +106 -62
  191. data/lib/capybara/spec/session/has_title_spec.rb +20 -14
  192. data/lib/capybara/spec/session/has_xpath_spec.rb +57 -38
  193. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
  194. data/lib/capybara/spec/session/html_spec.rb +14 -6
  195. data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
  196. data/lib/capybara/spec/session/node_spec.rb +1002 -153
  197. data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
  198. data/lib/capybara/spec/session/refresh_spec.rb +12 -6
  199. data/lib/capybara/spec/session/reset_session_spec.rb +82 -35
  200. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
  201. data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
  202. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +8 -12
  203. data/lib/capybara/spec/session/save_page_spec.rb +42 -55
  204. data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
  205. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  206. data/lib/capybara/spec/session/scroll_spec.rb +117 -0
  207. data/lib/capybara/spec/session/select_spec.rb +107 -81
  208. data/lib/capybara/spec/session/selectors_spec.rb +52 -19
  209. data/lib/capybara/spec/session/sibling_spec.rb +10 -10
  210. data/lib/capybara/spec/session/text_spec.rb +37 -21
  211. data/lib/capybara/spec/session/title_spec.rb +17 -5
  212. data/lib/capybara/spec/session/uncheck_spec.rb +42 -22
  213. data/lib/capybara/spec/session/unselect_spec.rb +39 -38
  214. data/lib/capybara/spec/session/visit_spec.rb +85 -53
  215. data/lib/capybara/spec/session/window/become_closed_spec.rb +24 -20
  216. data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
  217. data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
  218. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +27 -22
  219. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +12 -6
  220. data/lib/capybara/spec/session/window/window_spec.rb +97 -63
  221. data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
  222. data/lib/capybara/spec/session/window/within_window_spec.rb +31 -86
  223. data/lib/capybara/spec/session/within_spec.rb +83 -44
  224. data/lib/capybara/spec/spec_helper.rb +53 -43
  225. data/lib/capybara/spec/test_app.rb +158 -43
  226. data/lib/capybara/spec/views/animated.erb +49 -0
  227. data/lib/capybara/spec/views/form.erb +154 -42
  228. data/lib/capybara/spec/views/frame_child.erb +4 -3
  229. data/lib/capybara/spec/views/frame_one.erb +2 -1
  230. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  231. data/lib/capybara/spec/views/frame_two.erb +1 -1
  232. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  233. data/lib/capybara/spec/views/layout.erb +10 -0
  234. data/lib/capybara/spec/views/obscured.erb +47 -0
  235. data/lib/capybara/spec/views/offset.erb +33 -0
  236. data/lib/capybara/spec/views/path.erb +2 -2
  237. data/lib/capybara/spec/views/popup_one.erb +1 -1
  238. data/lib/capybara/spec/views/popup_two.erb +1 -1
  239. data/lib/capybara/spec/views/react.erb +45 -0
  240. data/lib/capybara/spec/views/scroll.erb +21 -0
  241. data/lib/capybara/spec/views/spatial.erb +31 -0
  242. data/lib/capybara/spec/views/tables.erb +68 -1
  243. data/lib/capybara/spec/views/with_animation.erb +81 -0
  244. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  245. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  246. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  247. data/lib/capybara/spec/views/with_hover.erb +3 -2
  248. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  249. data/lib/capybara/spec/views/with_html.erb +67 -12
  250. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  251. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  252. data/lib/capybara/spec/views/with_js.erb +30 -5
  253. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  254. data/lib/capybara/spec/views/with_namespace.erb +21 -0
  255. data/lib/capybara/spec/views/with_scope.erb +2 -2
  256. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  257. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  258. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  259. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  260. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  261. data/lib/capybara/spec/views/with_windows.erb +1 -1
  262. data/lib/capybara/spec/views/within_frames.erb +5 -2
  263. data/lib/capybara/version.rb +2 -1
  264. data/lib/capybara/window.rb +36 -34
  265. data/lib/capybara.rb +129 -103
  266. data/spec/basic_node_spec.rb +60 -34
  267. data/spec/capybara_spec.rb +63 -88
  268. data/spec/counter_spec.rb +35 -0
  269. data/spec/css_builder_spec.rb +101 -0
  270. data/spec/css_splitter_spec.rb +38 -0
  271. data/spec/dsl_spec.rb +85 -64
  272. data/spec/filter_set_spec.rb +27 -9
  273. data/spec/fixtures/certificate.pem +25 -0
  274. data/spec/fixtures/key.pem +27 -0
  275. data/spec/fixtures/selenium_driver_rspec_failure.rb +6 -5
  276. data/spec/fixtures/selenium_driver_rspec_success.rb +6 -5
  277. data/spec/minitest_spec.rb +45 -7
  278. data/spec/minitest_spec_spec.rb +94 -63
  279. data/spec/per_session_config_spec.rb +14 -13
  280. data/spec/rack_test_spec.rb +194 -125
  281. data/spec/regexp_dissassembler_spec.rb +250 -0
  282. data/spec/result_spec.rb +102 -50
  283. data/spec/rspec/features_spec.rb +37 -31
  284. data/spec/rspec/scenarios_spec.rb +9 -7
  285. data/spec/rspec/shared_spec_matchers.rb +449 -422
  286. data/spec/rspec/views_spec.rb +5 -3
  287. data/spec/rspec_matchers_spec.rb +27 -11
  288. data/spec/rspec_spec.rb +109 -89
  289. data/spec/sauce_spec_chrome.rb +43 -0
  290. data/spec/selector_spec.rb +397 -68
  291. data/spec/selenium_spec_chrome.rb +186 -40
  292. data/spec/selenium_spec_chrome_remote.rb +103 -0
  293. data/spec/selenium_spec_edge.rb +49 -0
  294. data/spec/selenium_spec_firefox.rb +194 -41
  295. data/spec/selenium_spec_firefox_remote.rb +82 -0
  296. data/spec/selenium_spec_ie.rb +149 -0
  297. data/spec/selenium_spec_safari.rb +162 -0
  298. data/spec/server_spec.rb +201 -102
  299. data/spec/session_spec.rb +53 -16
  300. data/spec/shared_selenium_node.rb +79 -0
  301. data/spec/shared_selenium_session.rb +474 -122
  302. data/spec/spec_helper.rb +93 -7
  303. data/spec/xpath_builder_spec.rb +93 -0
  304. metadata +360 -73
  305. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  306. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  307. data/.yard/yard_extensions.rb +0 -78
  308. data/lib/capybara/query.rb +0 -7
  309. data/lib/capybara/rspec/compound.rb +0 -95
  310. data/lib/capybara/spec/session/assert_current_path.rb +0 -72
  311. data/lib/capybara/spec/session/assert_selector.rb +0 -148
  312. data/lib/capybara/spec/session/assert_text.rb +0 -234
  313. data/lib/capybara/spec/session/source_spec.rb +0 -0
  314. data/lib/capybara/spec/views/with_title.erb +0 -5
  315. data/spec/selenium_spec_marionette.rb +0 -127
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  module Node
4
5
  module Matchers
5
-
6
6
  ##
7
7
  #
8
8
  # Checks if a given selector is on the page or a descendant of the current node.
@@ -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
- return 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
- return 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,88 +108,135 @@ 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, &optional_filter_block)
116
- options = if args.last.is_a?(Hash) then args.pop.dup else {} end
117
- selector = if args.first.is_a?(Symbol) then args.shift else session_options.default_selector end
118
- wait = options.fetch(:wait, session_options.default_max_wait_time)
119
- synchronize(wait) do
120
- args.each do |locator|
121
- assert_selector(selector, locator, options, &optional_filter_block)
122
- 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)
123
162
  end
124
163
  end
125
164
 
126
165
  # Asserts that none of the provided selectors are present on the given page
127
166
  # or descendants of the current node. If options are provided, the assertion
128
- # 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`).
129
168
  #
130
- # page.assert_none_of_selectors(:custom, 'Tom', 'Joe', visible: all)
131
- # 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')
132
171
  #
133
172
  # It accepts all options that {Capybara::Node::Finders#all} accepts,
134
- # such as :text and :visible.
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.
135
177
  #
136
- # The :wait option applies to all of the selectors as a group, so none of the locators must be present
137
- # within :wait (Defaults to Capybara.default_max_wait_time) seconds.
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`).
138
189
  #
139
- # @overload assert_none_of_selectors([kind = Capybara.default_selector], *locators, options = {})
190
+ # page.assert_any_of_selectors(:custom, 'Tom', 'Joe', visible: all)
191
+ # page.assert_any_of_selectors(:css, '#my_div', 'a.not_clicked')
140
192
  #
141
- def assert_none_of_selectors(*args, &optional_filter_block)
142
- options = if args.last.is_a?(Hash) then args.pop.dup else {} end
143
- selector = if args.first.is_a?(Symbol) then args.shift else session_options.default_selector end
144
- wait = options.fetch(:wait, session_options.default_max_wait_time)
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)
202
+ wait = session_options.default_max_wait_time if wait.nil?
203
+ selector = extract_selector(args)
145
204
  synchronize(wait) do
146
- args.each do |locator|
147
- 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
148
210
  end
211
+ raise Capybara::ExpectationNotMet, res.join(' or ') if res
212
+
213
+ true
149
214
  end
150
215
  end
151
216
 
152
217
  ##
153
218
  #
154
219
  # Asserts that a given selector is not on the page or a descendant of the current node.
155
- # Usage is identical to Capybara::Node::Matchers#assert_selector
220
+ # Usage is identical to {#assert_selector}.
156
221
  #
157
- # Query options such as :count, :minimum, :maximum, and :between are
222
+ # Query options such as `:count`, `:minimum`, `:maximum`, and `:between` are
158
223
  # considered to be an integral part of the selector. This will return
159
- # 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:
160
225
  #
161
226
  # page.assert_no_selector('a', minimum: 1) # Found, raises Capybara::ExpectationNotMet
162
227
  # page.assert_no_selector('a', count: 4) # Found, raises Capybara::ExpectationNotMet
163
228
  # page.assert_no_selector('a', count: 5) # Not Found, returns true
164
229
  #
165
- # @param (see Capybara::Node::Finders#assert_selector)
230
+ # @param (see #assert_selector)
166
231
  # @raise [Capybara::ExpectationNotMet] If the selector exists
167
232
  #
168
233
  def assert_no_selector(*args, &optional_filter_block)
169
234
  _verify_selector_result(args, optional_filter_block) do |result, query|
170
- if result.matches_count? && ((!result.empty?) || query.expects_none?)
235
+ if result.matches_count? && (!result.empty? || query.expects_none?)
171
236
  raise Capybara::ExpectationNotMet, result.negative_failure_message
172
237
  end
173
238
  end
174
239
  end
175
- alias_method :refute_selector, :assert_no_selector
176
240
 
177
241
  ##
178
242
  #
@@ -188,11 +252,11 @@ module Capybara
188
252
  # This will check if the expression occurs exactly 4 times.
189
253
  #
190
254
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
191
- # such as :text and :visible.
255
+ # such as `:text` and `:visible`.
192
256
  #
193
257
  # page.has_xpath?('.//li', text: 'Horse', visible: true)
194
258
  #
195
- # has_xpath? can also accept XPath expressions generate by the
259
+ # {#has_xpath?} can also accept XPath expressions generated by the
196
260
  # XPath gem:
197
261
  #
198
262
  # xpath = XPath.generate { |x| x.descendant(:p) }
@@ -203,20 +267,20 @@ module Capybara
203
267
  # @option options [Integer] :count (nil) Number of times the expression should occur
204
268
  # @return [Boolean] If the expression exists
205
269
  #
206
- def has_xpath?(path, options={}, &optional_filter_block)
207
- has_selector?(:xpath, path, options, &optional_filter_block)
270
+ def has_xpath?(path, **options, &optional_filter_block)
271
+ has_selector?(:xpath, path, **options, &optional_filter_block)
208
272
  end
209
273
 
210
274
  ##
211
275
  #
212
276
  # Checks if a given XPath expression is not on the page or a descendant of the current node.
213
- # Usage is identical to Capybara::Node::Matchers#has_xpath?
277
+ # Usage is identical to {#has_xpath?}.
214
278
  #
215
- # @param (see Capybara::Node::Finders#has_xpath?)
279
+ # @param (see #has_xpath?)
216
280
  # @return [Boolean]
217
281
  #
218
- def has_no_xpath?(path, options={}, &optional_filter_block)
219
- has_no_selector?(:xpath, path, options, &optional_filter_block)
282
+ def has_no_xpath?(path, **options, &optional_filter_block)
283
+ has_no_selector?(:xpath, path, **options, &optional_filter_block)
220
284
  end
221
285
 
222
286
  ##
@@ -233,7 +297,7 @@ module Capybara
233
297
  # This will check if the selector occurs exactly 4 times.
234
298
  #
235
299
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
236
- # such as :text and :visible.
300
+ # such as `:text` and `:visible`.
237
301
  #
238
302
  # page.has_css?('li', text: 'Horse', visible: true)
239
303
  #
@@ -242,20 +306,20 @@ module Capybara
242
306
  # @option options [Integer] :count (nil) Number of times the selector should occur
243
307
  # @return [Boolean] If the selector exists
244
308
  #
245
- def has_css?(path, options={}, &optional_filter_block)
246
- has_selector?(:css, path, options, &optional_filter_block)
309
+ def has_css?(path, **options, &optional_filter_block)
310
+ has_selector?(:css, path, **options, &optional_filter_block)
247
311
  end
248
312
 
249
313
  ##
250
314
  #
251
315
  # Checks if a given CSS selector is not on the page or a descendant of the current node.
252
- # Usage is identical to Capybara::Node::Matchers#has_css?
316
+ # Usage is identical to {#has_css?}.
253
317
  #
254
- # @param (see Capybara::Node::Finders#has_css?)
318
+ # @param (see #has_css?)
255
319
  # @return [Boolean]
256
320
  #
257
- def has_no_css?(path, options={}, &optional_filter_block)
258
- has_no_selector?(:css, path, options, &optional_filter_block)
321
+ def has_no_css?(path, **options, &optional_filter_block)
322
+ has_no_selector?(:css, path, **options, &optional_filter_block)
259
323
  end
260
324
 
261
325
  ##
@@ -264,13 +328,11 @@ module Capybara
264
328
  # text or id.
265
329
  #
266
330
  # @param [String] locator The text or id of a link to check for
267
- # @param options
268
331
  # @option options [String, Regexp] :href The value the href attribute must be
269
332
  # @return [Boolean] Whether it exists
270
333
  #
271
- def has_link?(locator=nil, options={}, &optional_filter_block)
272
- locator, options = nil, locator if locator.is_a? Hash
273
- has_selector?(:link, locator, options, &optional_filter_block)
334
+ def has_link?(locator = nil, **options, &optional_filter_block)
335
+ has_selector?(:link, locator, **options, &optional_filter_block)
274
336
  end
275
337
 
276
338
  ##
@@ -278,12 +340,11 @@ module Capybara
278
340
  # Checks if the page or current node has no link with the given
279
341
  # text or id.
280
342
  #
281
- # @param (see Capybara::Node::Finders#has_link?)
343
+ # @param (see #has_link?)
282
344
  # @return [Boolean] Whether it doesn't exist
283
345
  #
284
- def has_no_link?(locator=nil, options={}, &optional_filter_block)
285
- locator, options = nil, locator if locator.is_a? Hash
286
- has_no_selector?(:link, locator, options, &optional_filter_block)
346
+ def has_no_link?(locator = nil, **options, &optional_filter_block)
347
+ has_no_selector?(:link, locator, **options, &optional_filter_block)
287
348
  end
288
349
 
289
350
  ##
@@ -294,9 +355,8 @@ module Capybara
294
355
  # @param [String] locator The text, value or id of a button to check for
295
356
  # @return [Boolean] Whether it exists
296
357
  #
297
- def has_button?(locator=nil, options={}, &optional_filter_block)
298
- locator, options = nil, locator if locator.is_a? Hash
299
- has_selector?(:button, locator, options, &optional_filter_block)
358
+ def has_button?(locator = nil, **options, &optional_filter_block)
359
+ has_selector?(:button, locator, **options, &optional_filter_block)
300
360
  end
301
361
 
302
362
  ##
@@ -307,9 +367,8 @@ module Capybara
307
367
  # @param [String] locator The text, value or id of a button to check for
308
368
  # @return [Boolean] Whether it doesn't exist
309
369
  #
310
- def has_no_button?(locator=nil, options={}, &optional_filter_block)
311
- locator, options = nil, locator if locator.is_a? Hash
312
- has_no_selector?(:button, locator, options, &optional_filter_block)
370
+ def has_no_button?(locator = nil, **options, &optional_filter_block)
371
+ has_no_selector?(:button, locator, **options, &optional_filter_block)
313
372
  end
314
373
 
315
374
  ##
@@ -318,7 +377,7 @@ module Capybara
318
377
  # label, name or id.
319
378
  #
320
379
  # For text fields and other textual fields, such as textareas and
321
- # 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`
322
381
  # option to specify the text the field should contain:
323
382
  #
324
383
  # page.has_field?('Name', with: 'Jonas')
@@ -327,87 +386,81 @@ module Capybara
327
386
  #
328
387
  # page.has_field?('Email', type: 'email')
329
388
  #
330
- # 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.
331
390
  #
332
391
  # @param [String] locator The label, name or id of a field to check for
333
392
  # @option options [String, Regexp] :with The text content of the field or a Regexp to match
334
393
  # @option options [String] :type The type attribute of the field
335
394
  # @return [Boolean] Whether it exists
336
395
  #
337
- def has_field?(locator=nil, options={}, &optional_filter_block)
338
- locator, options = nil, locator if locator.is_a? Hash
339
- has_selector?(:field, locator, options, &optional_filter_block)
396
+ def has_field?(locator = nil, **options, &optional_filter_block)
397
+ has_selector?(:field, locator, **options, &optional_filter_block)
340
398
  end
341
399
 
342
400
  ##
343
401
  #
344
402
  # Checks if the page or current node has no form field with the given
345
- # label, name or id. See {Capybara::Node::Matchers#has_field?}.
403
+ # label, name or id. See {#has_field?}.
346
404
  #
347
405
  # @param [String] locator The label, name or id of a field to check for
348
406
  # @option options [String, Regexp] :with The text content of the field or a Regexp to match
349
407
  # @option options [String] :type The type attribute of the field
350
408
  # @return [Boolean] Whether it doesn't exist
351
409
  #
352
- def has_no_field?(locator=nil, options={}, &optional_filter_block)
353
- locator, options = nil, locator if locator.is_a? Hash
354
- has_no_selector?(:field, locator, options, &optional_filter_block)
410
+ def has_no_field?(locator = nil, **options, &optional_filter_block)
411
+ has_no_selector?(:field, locator, **options, &optional_filter_block)
355
412
  end
356
413
 
357
414
  ##
358
415
  #
359
416
  # Checks if the page or current node has a radio button or
360
- # 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
361
418
  # checked.
362
419
  #
363
420
  # @param [String] locator The label, name or id of a checked field
364
421
  # @return [Boolean] Whether it exists
365
422
  #
366
- def has_checked_field?(locator=nil, options={}, &optional_filter_block)
367
- locator, options = nil, locator if locator.is_a? Hash
368
- has_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
423
+ def has_checked_field?(locator = nil, **options, &optional_filter_block)
424
+ has_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
369
425
  end
370
426
 
371
427
  ##
372
428
  #
373
429
  # Checks if the page or current node has no radio button or
374
- # 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
375
431
  # checked.
376
432
  #
377
433
  # @param [String] locator The label, name or id of a checked field
378
434
  # @return [Boolean] Whether it doesn't exist
379
435
  #
380
- def has_no_checked_field?(locator=nil, options={}, &optional_filter_block)
381
- locator, options = nil, locator if locator.is_a? Hash
382
- has_no_selector?(:field, locator, options.merge(checked: true), &optional_filter_block)
436
+ def has_no_checked_field?(locator = nil, **options, &optional_filter_block)
437
+ has_no_selector?(:field, locator, **options.merge(checked: true), &optional_filter_block)
383
438
  end
384
439
 
385
440
  ##
386
441
  #
387
442
  # Checks if the page or current node has a radio button or
388
- # 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
389
444
  # unchecked.
390
445
  #
391
446
  # @param [String] locator The label, name or id of an unchecked field
392
447
  # @return [Boolean] Whether it exists
393
448
  #
394
- def has_unchecked_field?(locator=nil, options={}, &optional_filter_block)
395
- locator, options = nil, locator if locator.is_a? Hash
396
- has_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
449
+ def has_unchecked_field?(locator = nil, **options, &optional_filter_block)
450
+ has_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
397
451
  end
398
452
 
399
453
  ##
400
454
  #
401
455
  # Checks if the page or current node has no radio button or
402
- # 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
403
457
  # unchecked.
404
458
  #
405
459
  # @param [String] locator The label, name or id of an unchecked field
406
460
  # @return [Boolean] Whether it doesn't exist
407
461
  #
408
- def has_no_unchecked_field?(locator=nil, options={}, &optional_filter_block)
409
- locator, options = nil, locator if locator.is_a? Hash
410
- has_no_selector?(:field, locator, options.merge(unchecked: true), &optional_filter_block)
462
+ def has_no_unchecked_field?(locator = nil, **options, &optional_filter_block)
463
+ has_no_selector?(:field, locator, **options.merge(unchecked: true), &optional_filter_block)
411
464
  end
412
465
 
413
466
  ##
@@ -439,22 +492,20 @@ module Capybara
439
492
  # @option options [String, Array] :with_selected Partial set of options which should minimally be selected
440
493
  # @return [Boolean] Whether it exists
441
494
  #
442
- def has_select?(locator=nil, options={}, &optional_filter_block)
443
- locator, options = nil, locator if locator.is_a? Hash
444
- has_selector?(:select, locator, options, &optional_filter_block)
495
+ def has_select?(locator = nil, **options, &optional_filter_block)
496
+ has_selector?(:select, locator, **options, &optional_filter_block)
445
497
  end
446
498
 
447
499
  ##
448
500
  #
449
501
  # Checks if the page or current node has no select field with the
450
- # given label, name or id. See {Capybara::Node::Matchers#has_select?}.
502
+ # given label, name or id. See {#has_select?}.
451
503
  #
452
- # @param (see Capybara::Node::Matchers#has_select?)
504
+ # @param (see #has_select?)
453
505
  # @return [Boolean] Whether it doesn't exist
454
506
  #
455
- def has_no_select?(locator=nil, options={}, &optional_filter_block)
456
- locator, options = nil, locator if locator.is_a? Hash
457
- has_no_selector?(:select, locator, options, &optional_filter_block)
507
+ def has_no_select?(locator = nil, **options, &optional_filter_block)
508
+ has_no_selector?(:select, locator, **options, &optional_filter_block)
458
509
  end
459
510
 
460
511
  ##
@@ -464,37 +515,43 @@ module Capybara
464
515
  #
465
516
  # page.has_table?('People')
466
517
  #
467
- # @param [String] locator The id or caption of a table
468
- # @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
469
528
  #
470
- def has_table?(locator=nil, options={}, &optional_filter_block)
471
- locator, options = nil, locator if locator.is_a? Hash
472
- has_selector?(:table, locator, options, &optional_filter_block)
529
+ def has_table?(locator = nil, **options, &optional_filter_block)
530
+ has_selector?(:table, locator, **options, &optional_filter_block)
473
531
  end
474
532
 
475
533
  ##
476
534
  #
477
535
  # Checks if the page or current node has no table with the given id
478
- # or caption. See {Capybara::Node::Matchers#has_table?}.
536
+ # or caption. See {#has_table?}.
479
537
  #
480
- # @param (see Capybara::Node::Matchers#has_table?)
538
+ # @param (see #has_table?)
481
539
  # @return [Boolean] Whether it doesn't exist
482
540
  #
483
- def has_no_table?(locator=nil, options={}, &optional_filter_block)
484
- locator, options = nil, locator if locator.is_a? Hash
485
- has_no_selector?(:table, locator, options, &optional_filter_block)
541
+ def has_no_table?(locator = nil, **options, &optional_filter_block)
542
+ has_no_selector?(:table, locator, **options, &optional_filter_block)
486
543
  end
487
544
 
488
545
  ##
489
546
  #
490
- # Asserts that the current_node matches a given selector
547
+ # Asserts that the current node matches a given selector.
491
548
  #
492
549
  # node.assert_matches_selector('p#foo')
493
550
  # node.assert_matches_selector(:xpath, '//p[@id="foo"]')
494
551
  # node.assert_matches_selector(:foo)
495
552
  #
496
553
  # It also accepts all options that {Capybara::Node::Finders#all} accepts,
497
- # such as :text and :visible.
554
+ # such as `:text` and `:visible`.
498
555
  #
499
556
  # node.assert_matches_selector('li', text: 'Horse', visible: true)
500
557
  #
@@ -503,117 +560,121 @@ module Capybara
503
560
  #
504
561
  def assert_matches_selector(*args, &optional_filter_block)
505
562
  _verify_match_result(args, optional_filter_block) do |result|
506
- 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
507
564
  end
508
565
  end
509
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
+ #
510
575
  def assert_not_matches_selector(*args, &optional_filter_block)
511
576
  _verify_match_result(args, optional_filter_block) do |result|
512
577
  raise Capybara::ExpectationNotMet, 'Item matched the provided selector' if result.include? self
513
578
  end
514
579
  end
515
- alias_method :refute_matches_selector, :assert_not_matches_selector
516
580
 
517
581
  ##
518
582
  #
519
- # Checks if the current node matches given selector
583
+ # Checks if the current node matches given selector.
520
584
  #
521
- # @param (see Capybara::Node::Finders#has_selector?)
585
+ # @param (see #has_selector?)
522
586
  # @return [Boolean]
523
587
  #
524
- def matches_selector?(*args, &optional_filter_block)
525
- assert_matches_selector(*args, &optional_filter_block)
526
- rescue Capybara::ExpectationNotMet
527
- return false
588
+ def matches_selector?(*args, **options, &optional_filter_block)
589
+ make_predicate(options) { assert_matches_selector(*args, options, &optional_filter_block) }
528
590
  end
529
591
 
530
592
  ##
531
593
  #
532
- # Checks if the current node matches given XPath expression
594
+ # Checks if the current node matches given XPath expression.
533
595
  #
534
596
  # @param [String, XPath::Expression] xpath The XPath expression to match against the current code
535
597
  # @return [Boolean]
536
598
  #
537
- def matches_xpath?(xpath, options={}, &optional_filter_block)
538
- matches_selector?(:xpath, xpath, options, &optional_filter_block)
599
+ def matches_xpath?(xpath, **options, &optional_filter_block)
600
+ matches_selector?(:xpath, xpath, **options, &optional_filter_block)
539
601
  end
540
602
 
541
603
  ##
542
604
  #
543
- # Checks if the current node matches given CSS selector
605
+ # Checks if the current node matches given CSS selector.
544
606
  #
545
607
  # @param [String] css The CSS selector to match against the current code
546
608
  # @return [Boolean]
547
609
  #
548
- def matches_css?(css, options={}, &optional_filter_block)
549
- matches_selector?(:css, css, options, &optional_filter_block)
610
+ def matches_css?(css, **options, &optional_filter_block)
611
+ matches_selector?(:css, css, **options, &optional_filter_block)
550
612
  end
551
613
 
552
614
  ##
553
615
  #
554
- # Checks if the current node does not match given selector
555
- # 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?}.
556
618
  #
557
- # @param (see Capybara::Node::Finders#has_selector?)
619
+ # @param (see #has_selector?)
558
620
  # @return [Boolean]
559
621
  #
560
- def not_matches_selector?(*args, &optional_filter_block)
561
- assert_not_matches_selector(*args, &optional_filter_block)
562
- rescue Capybara::ExpectationNotMet
563
- 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) }
564
624
  end
565
625
 
566
626
  ##
567
627
  #
568
- # Checks if the current node does not match given XPath expression
628
+ # Checks if the current node does not match given XPath expression.
569
629
  #
570
630
  # @param [String, XPath::Expression] xpath The XPath expression to match against the current code
571
631
  # @return [Boolean]
572
632
  #
573
- def not_matches_xpath?(xpath, options={}, &optional_filter_block)
574
- not_matches_selector?(:xpath, xpath, options, &optional_filter_block)
633
+ def not_matches_xpath?(xpath, **options, &optional_filter_block)
634
+ not_matches_selector?(:xpath, xpath, **options, &optional_filter_block)
575
635
  end
576
636
 
577
637
  ##
578
638
  #
579
- # Checks if the current node does not match given CSS selector
639
+ # Checks if the current node does not match given CSS selector.
580
640
  #
581
641
  # @param [String] css The CSS selector to match against the current code
582
642
  # @return [Boolean]
583
643
  #
584
- def not_matches_css?(css, options={}, &optional_filter_block)
585
- not_matches_selector?(:css, css, options, &optional_filter_block)
644
+ def not_matches_css?(css, **options, &optional_filter_block)
645
+ not_matches_selector?(:css, css, **options, &optional_filter_block)
586
646
  end
587
647
 
588
-
589
648
  ##
590
649
  # Asserts that the page or current node has the given text content,
591
650
  # ignoring any HTML tags.
592
651
  #
593
652
  # @!macro text_query_params
594
- # @overload $0(type, text, options = {})
595
- # @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`.
596
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.
597
656
  # @option options [Integer] :count (nil) Number of times the text is expected to occur
598
657
  # @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur
599
658
  # @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
600
659
  # @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
601
- # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
602
- # @option options [Boolean] :exact (Capybara.exact_text) Whether text must be an exact match or just substring
603
- # @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)
604
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.
605
665
  # @option options [Integer] :count (nil) Number of times the text is expected to occur
606
666
  # @option options [Integer] :minimum (nil) Minimum number of times the text is expected to occur
607
667
  # @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
608
668
  # @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
609
- # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
610
- # @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
611
672
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
612
673
  # @return [true]
613
674
  #
614
- def assert_text(*args)
615
- _verify_text(args) do |count, query|
616
- 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?)
617
678
  raise Capybara::ExpectationNotMet, query.failure_message
618
679
  end
619
680
  end
@@ -627,9 +688,9 @@ module Capybara
627
688
  # @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
628
689
  # @return [true]
629
690
  #
630
- def assert_no_text(*args)
631
- _verify_text(args) do |count, query|
632
- 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?)
633
694
  raise Capybara::ExpectationNotMet, query.negative_failure_message
634
695
  end
635
696
  end
@@ -639,10 +700,6 @@ module Capybara
639
700
  # Checks if the page or current node has the given text content,
640
701
  # ignoring any HTML tags.
641
702
  #
642
- # Whitespaces are normalized in both node's text and passed text parameter.
643
- # Note that whitespace isn't normalized in passed regexp as normalizing whitespace
644
- # in regexp isn't easy and doesn't seem to be worth it.
645
- #
646
703
  # By default it will check if the text occurs at least once,
647
704
  # but a different number can be specified.
648
705
  #
@@ -653,10 +710,8 @@ module Capybara
653
710
  # @macro text_query_params
654
711
  # @return [Boolean] Whether it exists
655
712
  #
656
- def has_text?(*args)
657
- assert_text(*args)
658
- rescue Capybara::ExpectationNotMet
659
- return false
713
+ def has_text?(*args, **options)
714
+ make_predicate(options) { assert_text(*args, **options) }
660
715
  end
661
716
  alias_method :has_content?, :has_text?
662
717
 
@@ -667,56 +722,161 @@ module Capybara
667
722
  # @macro text_query_params
668
723
  # @return [Boolean] Whether it doesn't exist
669
724
  #
670
- def has_no_text?(*args)
671
- assert_no_text(*args)
672
- rescue Capybara::ExpectationNotMet
673
- return false
725
+ def has_no_text?(*args, **options)
726
+ make_predicate(options) { assert_no_text(*args, **options) }
674
727
  end
675
728
  alias_method :has_no_content?, :has_no_text?
676
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
+
677
816
  def ==(other)
678
- self.eql?(other) || (other.respond_to?(:base) && base == other.base)
817
+ eql?(other) || (other.respond_to?(:base) && base == other.base)
679
818
  end
680
819
 
681
820
  private
682
821
 
683
- def _verify_selector_result(query_args, optional_filter_block, &result_block)
684
- _set_query_session_options(query_args)
685
- query = Capybara::Queries::SelectorQuery.new(*query_args, &optional_filter_block)
686
- synchronize(query.wait) do
687
- result = query.resolve_for(self)
688
- result_block.call(result, query)
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) }
689
831
  end
690
- return true
691
832
  end
692
833
 
693
- def _verify_match_result(query_args, optional_filter_block, &result_block)
694
- _set_query_session_options(query_args)
695
- query = Capybara::Queries::MatchQuery.new(*query_args, &optional_filter_block)
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)
696
843
  synchronize(query.wait) do
697
- result = query.resolve_for(self.query_scope)
698
- result_block.call(result)
844
+ yield query.resolve_for(self), query
699
845
  end
700
- return true
846
+ true
701
847
  end
702
848
 
703
- def _verify_text(query_args)
704
- _set_query_session_options(query_args)
705
- query = Capybara::Queries::TextQuery.new(*query_args)
849
+ def _verify_match_result(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)
706
852
  synchronize(query.wait) do
707
- count = query.resolve_for(self)
708
- yield(count, query)
853
+ yield query.resolve_for(parent || session&.document || query_scope)
709
854
  end
710
- return true
855
+ true
711
856
  end
712
857
 
713
- def _set_query_session_options(query_args)
714
- if query_args.last.is_a? Hash
715
- query_args.last[:session_options] = session_options
716
- else
717
- query_args.push(session_options: session_options)
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)
861
+ synchronize(query.wait) do
862
+ yield query.resolve_for(self), query
718
863
  end
719
- query_args
864
+ true
865
+ end
866
+
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)
871
+ query_options[:session_options] = session_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
720
880
  end
721
881
  end
722
882
  end