capybara 2.18.0 → 3.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +945 -12
  4. data/License.txt +1 -1
  5. data/README.md +264 -90
  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 +185 -83
  13. data/lib/capybara/minitest.rb +232 -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 +151 -137
  20. data/lib/capybara/node/matchers.rb +394 -209
  21. data/lib/capybara/node/simple.rb +59 -26
  22. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  23. data/lib/capybara/queries/active_element_query.rb +18 -0
  24. data/lib/capybara/queries/ancestor_query.rb +12 -9
  25. data/lib/capybara/queries/base_query.rb +39 -28
  26. data/lib/capybara/queries/current_path_query.rb +21 -27
  27. data/lib/capybara/queries/match_query.rb +14 -7
  28. data/lib/capybara/queries/selector_query.rb +659 -149
  29. data/lib/capybara/queries/sibling_query.rb +11 -9
  30. data/lib/capybara/queries/style_query.rb +45 -0
  31. data/lib/capybara/queries/text_query.rb +56 -38
  32. data/lib/capybara/queries/title_query.rb +8 -11
  33. data/lib/capybara/rack_test/browser.rb +114 -42
  34. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  35. data/lib/capybara/rack_test/driver.rb +22 -17
  36. data/lib/capybara/rack_test/errors.rb +6 -0
  37. data/lib/capybara/rack_test/form.rb +93 -58
  38. data/lib/capybara/rack_test/node.rb +184 -81
  39. data/lib/capybara/rails.rb +3 -7
  40. data/lib/capybara/registration_container.rb +41 -0
  41. data/lib/capybara/registrations/drivers.rb +42 -0
  42. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  43. data/lib/capybara/registrations/servers.rb +66 -0
  44. data/lib/capybara/result.rb +97 -63
  45. data/lib/capybara/rspec/features.rb +17 -50
  46. data/lib/capybara/rspec/matcher_proxies.rb +52 -15
  47. data/lib/capybara/rspec/matchers/base.rb +113 -0
  48. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  49. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  50. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  51. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  52. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  53. data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  54. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  55. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  56. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  57. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  58. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  59. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  60. data/lib/capybara/rspec/matchers.rb +146 -310
  61. data/lib/capybara/rspec.rb +7 -11
  62. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  63. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  64. data/lib/capybara/selector/css.rb +85 -13
  65. data/lib/capybara/selector/definition/button.rb +68 -0
  66. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  67. data/lib/capybara/selector/definition/css.rb +10 -0
  68. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  69. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  70. data/lib/capybara/selector/definition/element.rb +28 -0
  71. data/lib/capybara/selector/definition/field.rb +40 -0
  72. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  73. data/lib/capybara/selector/definition/file_field.rb +13 -0
  74. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  75. data/lib/capybara/selector/definition/frame.rb +17 -0
  76. data/lib/capybara/selector/definition/id.rb +6 -0
  77. data/lib/capybara/selector/definition/label.rb +62 -0
  78. data/lib/capybara/selector/definition/link.rb +55 -0
  79. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  80. data/lib/capybara/selector/definition/option.rb +27 -0
  81. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  82. data/lib/capybara/selector/definition/select.rb +81 -0
  83. data/lib/capybara/selector/definition/table.rb +109 -0
  84. data/lib/capybara/selector/definition/table_row.rb +21 -0
  85. data/lib/capybara/selector/definition/xpath.rb +5 -0
  86. data/lib/capybara/selector/definition.rb +280 -0
  87. data/lib/capybara/selector/filter.rb +2 -17
  88. data/lib/capybara/selector/filter_set.rb +80 -33
  89. data/lib/capybara/selector/filters/base.rb +50 -6
  90. data/lib/capybara/selector/filters/expression_filter.rb +8 -26
  91. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  92. data/lib/capybara/selector/filters/node_filter.rb +16 -12
  93. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  94. data/lib/capybara/selector/selector.rb +93 -210
  95. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  96. data/lib/capybara/selector.rb +475 -523
  97. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  98. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  99. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  100. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  101. data/lib/capybara/selenium/driver.rb +298 -267
  102. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  103. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  104. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
  105. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  106. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  107. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  108. data/lib/capybara/selenium/extensions/find.rb +110 -0
  109. data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
  110. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  111. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  112. data/lib/capybara/selenium/node.rb +517 -145
  113. data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
  114. data/lib/capybara/selenium/nodes/edge_node.rb +110 -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/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 +80 -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 +59 -67
  127. data/lib/capybara/session/config.rb +81 -67
  128. data/lib/capybara/session/matchers.rb +28 -20
  129. data/lib/capybara/session.rb +337 -365
  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 +151 -12
  133. data/lib/capybara/spec/session/accept_alert_spec.rb +12 -11
  134. data/lib/capybara/spec/session/accept_confirm_spec.rb +6 -5
  135. data/lib/capybara/spec/session/accept_prompt_spec.rb +10 -10
  136. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  137. data/lib/capybara/spec/session/all_spec.rb +161 -57
  138. data/lib/capybara/spec/session/ancestor_spec.rb +27 -24
  139. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +68 -38
  140. data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
  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_spec.rb +258 -0
  144. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +22 -12
  145. data/lib/capybara/spec/session/attach_file_spec.rb +144 -69
  146. data/lib/capybara/spec/session/body_spec.rb +12 -13
  147. data/lib/capybara/spec/session/check_spec.rb +117 -55
  148. data/lib/capybara/spec/session/choose_spec.rb +64 -31
  149. data/lib/capybara/spec/session/click_button_spec.rb +231 -173
  150. data/lib/capybara/spec/session/click_link_or_button_spec.rb +55 -35
  151. data/lib/capybara/spec/session/click_link_spec.rb +93 -58
  152. data/lib/capybara/spec/session/current_scope_spec.rb +12 -11
  153. data/lib/capybara/spec/session/current_url_spec.rb +57 -39
  154. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +4 -4
  155. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +3 -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 +9 -7
  159. data/lib/capybara/spec/session/element/matches_selector_spec.rb +71 -57
  160. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +8 -7
  161. data/lib/capybara/spec/session/evaluate_script_spec.rb +29 -8
  162. data/lib/capybara/spec/session/execute_script_spec.rb +10 -8
  163. data/lib/capybara/spec/session/fill_in_spec.rb +134 -43
  164. data/lib/capybara/spec/session/find_button_spec.rb +25 -24
  165. data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
  166. data/lib/capybara/spec/session/find_field_spec.rb +37 -41
  167. data/lib/capybara/spec/session/find_link_spec.rb +46 -17
  168. data/lib/capybara/spec/session/find_spec.rb +260 -145
  169. data/lib/capybara/spec/session/first_spec.rb +80 -52
  170. data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  171. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  172. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +33 -20
  173. data/lib/capybara/spec/session/frame/within_frame_spec.rb +52 -32
  174. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  175. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  176. data/lib/capybara/spec/session/has_all_selectors_spec.rb +31 -31
  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 +100 -13
  180. data/lib/capybara/spec/session/has_css_spec.rb +272 -137
  181. data/lib/capybara/spec/session/has_current_path_spec.rb +60 -61
  182. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  183. data/lib/capybara/spec/session/has_field_spec.rb +139 -59
  184. data/lib/capybara/spec/session/has_link_spec.rb +47 -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 +183 -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 +37 -0
  196. data/lib/capybara/spec/session/node_spec.rb +1024 -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 +119 -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 +43 -23
  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 +54 -44
  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 +163 -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 +69 -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 +134 -107
  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 +52 -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 +111 -50
  283. data/spec/rspec/features_spec.rb +37 -31
  284. data/spec/rspec/scenarios_spec.rb +10 -8
  285. data/spec/rspec/shared_spec_matchers.rb +473 -422
  286. data/spec/rspec/views_spec.rb +5 -3
  287. data/spec/rspec_matchers_spec.rb +52 -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 +187 -40
  292. data/spec/selenium_spec_chrome_remote.rb +96 -0
  293. data/spec/selenium_spec_edge.rb +60 -0
  294. data/spec/selenium_spec_firefox.rb +201 -41
  295. data/spec/selenium_spec_firefox_remote.rb +94 -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 +213 -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 +473 -122
  302. data/spec/spec_helper.rb +126 -7
  303. data/spec/whitespace_normalizer_spec.rb +54 -0
  304. data/spec/xpath_builder_spec.rb +93 -0
  305. metadata +355 -73
  306. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  307. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  308. data/.yard/yard_extensions.rb +0 -78
  309. data/lib/capybara/query.rb +0 -7
  310. data/lib/capybara/rspec/compound.rb +0 -95
  311. data/lib/capybara/spec/session/assert_current_path.rb +0 -72
  312. data/lib/capybara/spec/session/assert_selector.rb +0 -148
  313. data/lib/capybara/spec/session/assert_text.rb +0 -234
  314. data/lib/capybara/spec/session/source_spec.rb +0 -0
  315. data/lib/capybara/spec/views/with_title.erb +0 -5
  316. data/spec/selenium_spec_marionette.rb +0 -127
@@ -1,371 +1,207 @@
1
1
  # frozen_string_literal: true
2
- module Capybara
3
- module RSpecMatchers
4
- class Matcher
5
- if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.0'))
6
- require 'capybara/rspec/compound'
7
- include ::Capybara::RSpecMatchers::Compound
8
- end
9
-
10
- attr_reader :failure_message, :failure_message_when_negated
11
-
12
- def wrap(actual)
13
- @context_el = if actual.respond_to?("has_selector?")
14
- actual
15
- else
16
- Capybara.string(actual.to_s)
17
- end
18
- end
19
2
 
20
- # RSpec 2 compatibility:
21
- def failure_message_for_should; failure_message end
22
- def failure_message_for_should_not; failure_message_when_negated end
3
+ require 'capybara/rspec/matchers/have_selector'
4
+ require 'capybara/rspec/matchers/have_ancestor'
5
+ require 'capybara/rspec/matchers/have_sibling'
6
+ require 'capybara/rspec/matchers/match_selector'
7
+ require 'capybara/rspec/matchers/have_current_path'
8
+ require 'capybara/rspec/matchers/match_style'
9
+ require 'capybara/rspec/matchers/have_text'
10
+ require 'capybara/rspec/matchers/have_title'
11
+ require 'capybara/rspec/matchers/become_closed'
23
12
 
24
- private
25
-
26
- def wrap_matches?(actual)
27
- yield(wrap(actual))
28
- rescue Capybara::ExpectationNotMet => e
29
- @failure_message = e.message
30
- return false
31
- end
32
-
33
- def wrap_does_not_match?(actual)
34
- yield(wrap(actual))
35
- rescue Capybara::ExpectationNotMet => e
36
- @failure_message_when_negated = e.message
37
- return false
38
- end
39
-
40
- def session_query_args
41
- if @args.last.is_a? Hash
42
- @args.last[:session_options] = session_options
43
- else
44
- @args.push(session_options: session_options)
45
- end
46
- @args
47
- end
48
-
49
- def session_options
50
- @context_el ||= nil
51
- if @context_el.respond_to? :session_options
52
- @context_el.session_options
53
- elsif @context_el.respond_to? :current_scope
54
- @context_el.current_scope.session_options
55
- else
56
- Capybara.session_options
57
- end
58
- end
13
+ module Capybara
14
+ module RSpecMatchers
15
+ # RSpec matcher for whether the element(s) matching a given selector exist.
16
+ #
17
+ # @see Capybara::Node::Matchers#assert_selector
18
+ def have_selector(...)
19
+ Matchers::HaveSelector.new(...)
59
20
  end
60
21
 
61
- class HaveSelector < Matcher
62
- def initialize(*args, &filter_block)
63
- @args = args
64
- @filter_block = filter_block
65
- end
66
-
67
- def matches?(actual)
68
- wrap_matches?(actual){ |el| el.assert_selector(*@args, &@filter_block) }
69
- end
70
-
71
- def does_not_match?(actual)
72
- wrap_does_not_match?(actual){ |el| el.assert_no_selector(*@args, &@filter_block) }
73
- end
74
-
75
- def description
76
- "have #{query.description}"
77
- end
78
-
79
- def query
80
- @query ||= Capybara::Queries::SelectorQuery.new(*session_query_args, &@filter_block)
81
- end
22
+ # RSpec matcher for whether the element(s) matching a group of selectors exist.
23
+ #
24
+ # @see Capybara::Node::Matchers#assert_all_of_selectors
25
+ def have_all_of_selectors(...)
26
+ Matchers::HaveAllSelectors.new(...)
82
27
  end
83
28
 
84
- class HaveAllSelectors < Matcher
85
- def initialize(*args, &filter_block)
86
- @args = args
87
- @filter_block = filter_block
88
- end
89
-
90
- def matches?(actual)
91
- wrap_matches?(actual){ |el| el.assert_all_of_selectors(*@args, &@filter_block) }
92
- end
93
-
94
- def does_not_match?(actual)
95
- raise ArgumentError, "The have_all_selectors matcher does not support use with not_to/should_not"
96
- end
97
-
98
- def description
99
- "have all selectors"
100
- end
29
+ # RSpec matcher for whether no element(s) matching a group of selectors exist.
30
+ #
31
+ # @see Capybara::Node::Matchers#assert_none_of_selectors
32
+ def have_none_of_selectors(...)
33
+ Matchers::HaveNoSelectors.new(...)
101
34
  end
102
35
 
103
- class HaveNoSelectors < Matcher
104
- def initialize(*args, &filter_block)
105
- @args = args
106
- @filter_block = filter_block
107
- end
108
-
109
- def matches?(actual)
110
- wrap_matches?(actual){ |el| el.assert_none_of_selectors(*@args, &@filter_block) }
111
- end
112
-
113
- def does_not_match?(actual)
114
- raise ArgumentError, "The have_none_of_selectors matcher does not support use with not_to/should_not"
115
- end
116
-
117
- def description
118
- "have no selectors"
119
- end
36
+ # RSpec matcher for whether the element(s) matching any of a group of selectors exist.
37
+ #
38
+ # @see Capybara::Node::Matchers#assert_any_of_selectors
39
+ def have_any_of_selectors(...)
40
+ Matchers::HaveAnySelectors.new(...)
120
41
  end
121
42
 
122
- class MatchSelector < HaveSelector
123
- def matches?(actual)
124
- wrap_matches?(actual) { |el| el.assert_matches_selector(*@args, &@filter_block) }
125
- end
126
-
127
- def does_not_match?(actual)
128
- wrap_does_not_match?(actual) { |el| el.assert_not_matches_selector(*@args, &@filter_block) }
129
- end
130
-
131
- def description
132
- "match #{query.description}"
133
- end
134
-
135
- def query
136
- @query ||= Capybara::Queries::MatchQuery.new(*session_query_args, &@filter_block)
137
- end
43
+ # RSpec matcher for whether the current element matches a given selector.
44
+ #
45
+ # @see Capybara::Node::Matchers#assert_matches_selector
46
+ def match_selector(...)
47
+ Matchers::MatchSelector.new(...)
138
48
  end
139
49
 
140
- class HaveText < Matcher
141
- attr_reader :type, :content, :options
142
-
143
- def initialize(*args)
144
- @args = args.dup
145
-
146
- # are set just for backwards compatability
147
- @type = args.shift if args.first.is_a?(Symbol)
148
- @content = args.shift
149
- @options = (args.first.is_a?(Hash))? args.first : {}
150
- end
151
-
152
- def matches?(actual)
153
- wrap_matches?(actual) { |el| el.assert_text(*@args) }
154
- end
155
-
156
- def does_not_match?(actual)
157
- wrap_does_not_match?(actual) { |el| el.assert_no_text(*@args) }
158
- end
159
-
160
- def description
161
- "text #{format(content)}"
50
+ %i[css xpath].each do |selector|
51
+ define_method "have_#{selector}" do |expr, **options, &optional_filter_block|
52
+ Matchers::HaveSelector.new(selector, expr, **options, &optional_filter_block)
162
53
  end
163
54
 
164
- def format(content)
165
- content = Capybara::Helpers.normalize_whitespace(content) unless content.is_a? Regexp
166
- content.inspect
55
+ define_method "match_#{selector}" do |expr, **options, &optional_filter_block|
56
+ Matchers::MatchSelector.new(selector, expr, **options, &optional_filter_block)
167
57
  end
168
58
  end
169
59
 
170
- class HaveTitle < Matcher
171
- attr_reader :title
60
+ # @!method have_xpath(xpath, **options, &optional_filter_block)
61
+ # RSpec matcher for whether elements(s) matching a given xpath selector exist.
62
+ #
63
+ # @see Capybara::Node::Matchers#has_xpath?
172
64
 
173
- def initialize(*args)
174
- @args = args
65
+ # @!method have_css(css, **options, &optional_filter_block)
66
+ # RSpec matcher for whether elements(s) matching a given css selector exist
67
+ #
68
+ # @see Capybara::Node::Matchers#has_css?
175
69
 
176
- # are set just for backwards compatability
177
- @title = args.first
178
- end
70
+ # @!method match_xpath(xpath, **options, &optional_filter_block)
71
+ # RSpec matcher for whether the current element matches a given xpath selector.
72
+ #
73
+ # @see Capybara::Node::Matchers#matches_xpath?
179
74
 
180
- def matches?(actual)
181
- wrap_matches?(actual) { |el| el.assert_title(*@args) }
182
- end
75
+ # @!method match_css(css, **options, &optional_filter_block)
76
+ # RSpec matcher for whether the current element matches a given css selector.
77
+ #
78
+ # @see Capybara::Node::Matchers#matches_css?
183
79
 
184
- def does_not_match?(actual)
185
- wrap_does_not_match?(actual) { |el| el.assert_no_title(*@args) }
186
- end
187
-
188
- def description
189
- "have title #{title.inspect}"
80
+ %i[link button field select table element].each do |selector|
81
+ define_method "have_#{selector}" do |locator = nil, **options, &optional_filter_block|
82
+ Matchers::HaveSelector.new(selector, locator, **options, &optional_filter_block)
190
83
  end
191
84
  end
192
85
 
193
- class HaveCurrentPath < Matcher
194
- attr_reader :current_path
86
+ # @!method have_element(locator = nil, **options, &optional_filter_block)
87
+ # RSpec matcher for elements.
88
+ #
89
+ # @see Capybara::Node::Matchers#has_element?
195
90
 
196
- def initialize(*args)
197
- @args = args
91
+ # @!method have_link(locator = nil, **options, &optional_filter_block)
92
+ # RSpec matcher for links.
93
+ #
94
+ # @see Capybara::Node::Matchers#has_link?
198
95
 
199
- # are set just for backwards compatability
200
- @current_path = args.first
201
- end
96
+ # @!method have_button(locator = nil, **options, &optional_filter_block)
97
+ # RSpec matcher for buttons.
98
+ #
99
+ # @see Capybara::Node::Matchers#has_button?
202
100
 
203
- def matches?(actual)
204
- wrap_matches?(actual) { |el| el.assert_current_path(*@args) }
205
- end
101
+ # @!method have_field(locator = nil, **options, &optional_filter_block)
102
+ # RSpec matcher for form fields.
103
+ #
104
+ # @see Capybara::Node::Matchers#has_field?
206
105
 
207
- def does_not_match?(actual)
208
- wrap_does_not_match?(actual) { |el| el.assert_no_current_path(*@args) }
209
- end
106
+ # @!method have_select(locator = nil, **options, &optional_filter_block)
107
+ # RSpec matcher for select elements.
108
+ #
109
+ # @see Capybara::Node::Matchers#has_select?
210
110
 
211
- def description
212
- "have current path #{current_path.inspect}"
213
- end
214
- end
111
+ # @!method have_table(locator = nil, **options, &optional_filter_block)
112
+ # RSpec matcher for table elements.
113
+ #
114
+ # @see Capybara::Node::Matchers#has_table?
215
115
 
216
- class BecomeClosed
217
- def initialize(options)
218
- @options = options
116
+ %i[checked unchecked].each do |state|
117
+ define_method "have_#{state}_field" do |locator = nil, **options, &optional_filter_block|
118
+ Matchers::HaveSelector.new(:field, locator, **options.merge(state => true), &optional_filter_block)
219
119
  end
220
-
221
- def matches?(window)
222
- @window = window
223
- @wait_time = Capybara::Queries::BaseQuery.wait(@options, window.session.config.default_max_wait_time)
224
- start_time = Capybara::Helpers.monotonic_time
225
- while window.exists?
226
- return false if (Capybara::Helpers.monotonic_time - start_time) > @wait_time
227
- sleep 0.05
228
- end
229
- true
230
- end
231
-
232
- def failure_message
233
- "expected #{@window.inspect} to become closed after #{@wait_time} seconds"
234
- end
235
-
236
- def failure_message_when_negated
237
- "expected #{@window.inspect} not to become closed after #{@wait_time} seconds"
238
- end
239
-
240
- # RSpec 2 compatibility:
241
- alias_method :failure_message_for_should, :failure_message
242
- alias_method :failure_message_for_should_not, :failure_message_when_negated
243
- end
244
-
245
- # RSpec matcher for whether the element(s) matching a given selector exist
246
- # See {Capybara::Node::Matcher#assert_selector}
247
- def have_selector(*args, &optional_filter_block)
248
- HaveSelector.new(*args, &optional_filter_block)
249
- end
250
-
251
- # RSpec matcher for whether the element(s) matching a group of selectors exist
252
- # See {Capybara::Node::Matcher#assert_all_of_selectors}
253
- def have_all_of_selectors(*args, &optional_filter_block)
254
- HaveAllSelectors.new(*args, &optional_filter_block)
255
- end
256
-
257
- # RSpec matcher for whether no element(s) matching a group of selectors exist
258
- # See {Capybara::Node::Matcher#assert_none_of_selectors}
259
- def have_none_of_selectors(*args, &optional_filter_block)
260
- HaveNoSelectors.new(*args, &optional_filter_block)
261
- end
262
-
263
- # RSpec matcher for whether the current element matches a given selector
264
- # See {Capybara::Node::Matchers#assert_matches_selector}
265
- def match_selector(*args, &optional_filter_block)
266
- MatchSelector.new(*args, &optional_filter_block)
267
- end
268
- # defined_negated_matcher was added in RSpec 3.1 - it's syntactic sugar only since a user can do
269
- # expect(page).not_to match_selector, so not sure we really need to support not_match_selector for prior to RSpec 3.1
270
- ::RSpec::Matchers.define_negated_matcher :not_match_selector, :match_selector if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.1'))
271
-
272
-
273
- # RSpec matcher for whether elements(s) matching a given xpath selector exist
274
- # See {Capybara::Node::Matchers#has_xpath?}
275
- def have_xpath(xpath, options={}, &optional_filter_block)
276
- HaveSelector.new(:xpath, xpath, options, &optional_filter_block)
277
- end
278
-
279
- # RSpec matcher for whether the current element matches a given xpath selector
280
- def match_xpath(xpath, options={}, &optional_filter_block)
281
- MatchSelector.new(:xpath, xpath, options, &optional_filter_block)
282
120
  end
283
121
 
284
- # RSpec matcher for whether elements(s) matching a given css selector exist
285
- # See {Capybara::Node::Matchers#has_css?}
286
- def have_css(css, options={}, &optional_filter_block)
287
- HaveSelector.new(:css, css, options, &optional_filter_block)
288
- end
122
+ # @!method have_checked_field(locator = nil, **options, &optional_filter_block)
123
+ # RSpec matcher for checked fields.
124
+ #
125
+ # @see Capybara::Node::Matchers#has_checked_field?
289
126
 
290
- # RSpec matcher for whether the current element matches a given css selector
291
- def match_css(css, options={}, &optional_filter_block)
292
- MatchSelector.new(:css, css, options, &optional_filter_block)
293
- end
127
+ # @!method have_unchecked_field(locator = nil, **options, &optional_filter_block)
128
+ # RSpec matcher for unchecked fields.
129
+ #
130
+ # @see Capybara::Node::Matchers#has_unchecked_field?
294
131
 
295
- # RSpec matcher for text on the page
296
- # See {Capybara::SessionMatchers#assert_text}
297
- def have_text(*args)
298
- HaveText.new(*args)
132
+ # RSpec matcher for text content.
133
+ #
134
+ # @see Capybara::Node::Matchers#assert_text
135
+ def have_text(text_or_type, *args, **options)
136
+ Matchers::HaveText.new(text_or_type, *args, **options)
299
137
  end
300
138
  alias_method :have_content, :have_text
301
139
 
302
- def have_title(title, options = {})
303
- HaveTitle.new(title, options)
140
+ def have_title(title, **options)
141
+ Matchers::HaveTitle.new(title, **options)
304
142
  end
305
143
 
306
- # RSpec matcher for the current path
307
- # See {Capybara::SessionMatchers#assert_current_path}
308
- def have_current_path(path, options = {})
309
- HaveCurrentPath.new(path, options)
144
+ # RSpec matcher for the current path.
145
+ #
146
+ # @see Capybara::SessionMatchers#assert_current_path
147
+ def have_current_path(path, **options, &optional_filter_block)
148
+ Matchers::HaveCurrentPath.new(path, **options, &optional_filter_block)
310
149
  end
311
150
 
312
- # RSpec matcher for links
313
- # See {Capybara::Node::Matchers#has_link?}
314
- def have_link(locator=nil, options={}, &optional_filter_block)
315
- locator, options = nil, locator if locator.is_a? Hash
316
- HaveSelector.new(:link, locator, options, &optional_filter_block)
151
+ # RSpec matcher for element style.
152
+ #
153
+ # @see Capybara::Node::Matchers#matches_style?
154
+ def match_style(styles = nil, **options)
155
+ styles, options = options, {} if styles.nil?
156
+ Matchers::MatchStyle.new(styles, **options)
317
157
  end
318
158
 
319
- # RSpec matcher for buttons
320
- # See {Capybara::Node::Matchers#has_button?}
321
- def have_button(locator=nil, options={}, &optional_filter_block)
322
- locator, options = nil, locator if locator.is_a? Hash
323
- HaveSelector.new(:button, locator, options, &optional_filter_block)
324
- end
325
-
326
- # RSpec matcher for links
327
- # See {Capybara::Node::Matchers#has_field?}
328
- def have_field(locator=nil, options={}, &optional_filter_block)
329
- locator, options = nil, locator if locator.is_a? Hash
330
- HaveSelector.new(:field, locator, options, &optional_filter_block)
159
+ ##
160
+ # @deprecated
161
+ #
162
+ def have_style(styles = nil, **options)
163
+ Capybara::Helpers.warn "DEPRECATED: have_style is deprecated, please use match_style : #{Capybara::Helpers.filter_backtrace(caller)}"
164
+ match_style(styles, **options)
331
165
  end
332
166
 
333
- # RSpec matcher for checked fields
334
- # See {Capybara::Node::Matchers#has_checked_field?}
335
- def have_checked_field(locator=nil, options={}, &optional_filter_block)
336
- locator, options = nil, locator if locator.is_a? Hash
337
- HaveSelector.new(:field, locator, options.merge(checked: true), &optional_filter_block)
167
+ %w[selector css xpath text title current_path link button
168
+ field checked_field unchecked_field select table
169
+ sibling ancestor element].each do |matcher_type|
170
+ define_method "have_no_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
171
+ Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, **kw_args, &optional_filter_block))
172
+ end
338
173
  end
174
+ alias_method :have_no_content, :have_no_text
339
175
 
340
- # RSpec matcher for unchecked fields
341
- # See {Capybara::Node::Matchers#has_unchecked_field?}
342
- def have_unchecked_field(locator=nil, options={}, &optional_filter_block)
343
- locator, options = nil, locator if locator.is_a? Hash
344
- HaveSelector.new(:field, locator, options.merge(unchecked: true), &optional_filter_block)
176
+ %w[selector css xpath].each do |matcher_type|
177
+ define_method "not_match_#{matcher_type}" do |*args, **kw_args, &optional_filter_block|
178
+ Matchers::NegatedMatcher.new(send("match_#{matcher_type}", *args, **kw_args, &optional_filter_block))
179
+ end
345
180
  end
346
181
 
347
- # RSpec matcher for select elements
348
- # See {Capybara::Node::Matchers#has_select?}
349
- def have_select(locator=nil, options={}, &optional_filter_block)
350
- locator, options = nil, locator if locator.is_a? Hash
351
- HaveSelector.new(:select, locator, options, &optional_filter_block)
182
+ # RSpec matcher for whether sibling element(s) matching a given selector exist.
183
+ #
184
+ # @see Capybara::Node::Matchers#assert_sibling
185
+ def have_sibling(...)
186
+ Matchers::HaveSibling.new(...)
352
187
  end
353
188
 
354
- # RSpec matcher for table elements
355
- # See {Capybara::Node::Matchers#has_table?}
356
- def have_table(locator=nil, options={}, &optional_filter_block)
357
- locator, options = nil, locator if locator.is_a? Hash
358
- HaveSelector.new(:table, locator, options, &optional_filter_block)
189
+ # RSpec matcher for whether ancestor element(s) matching a given selector exist.
190
+ #
191
+ # @see Capybara::Node::Matchers#assert_ancestor
192
+ def have_ancestor(...)
193
+ Matchers::HaveAncestor.new(...)
359
194
  end
360
195
 
361
196
  ##
362
197
  # Wait for window to become closed.
198
+ #
363
199
  # @example
364
200
  # expect(window).to become_closed(wait: 0.8)
365
- # @param options [Hash] optional param
366
- # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum wait time
367
- def become_closed(options = {})
368
- BecomeClosed.new(options)
201
+ #
202
+ # @option options [Numeric] :wait Maximum wait time. Defaults to {Capybara.configure default_max_wait_time}
203
+ def become_closed(**options)
204
+ Matchers::BecomeClosed.new(options)
369
205
  end
370
206
  end
371
- end
207
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'rspec/core'
3
4
  require 'capybara/dsl'
4
5
  require 'capybara/rspec/matchers'
@@ -6,14 +7,11 @@ require 'capybara/rspec/features'
6
7
  require 'capybara/rspec/matcher_proxies'
7
8
 
8
9
  RSpec.configure do |config|
9
- config.include Capybara::DSL, :type => :feature
10
- config.include Capybara::RSpecMatchers, :type => :feature
11
- config.include Capybara::RSpecMatchers, :type => :view
12
-
13
- # A work-around to support accessing the current example that works in both
14
- # RSpec 2 and RSpec 3.
15
- fetch_current_example = RSpec.respond_to?(:current_example) ?
16
- proc { RSpec.current_example } : proc { |context| context.example }
10
+ config.include Capybara::DSL, type: :feature
11
+ config.include Capybara::RSpecMatchers, type: :feature
12
+ config.include Capybara::DSL, type: :system
13
+ config.include Capybara::RSpecMatchers, type: :system
14
+ config.include Capybara::RSpecMatchers, type: :view
17
15
 
18
16
  # The before and after blocks must run instantaneously, because Capybara
19
17
  # might not actually be used in all examples where it's included.
@@ -24,12 +22,10 @@ RSpec.configure do |config|
24
22
  end
25
23
  end
26
24
 
27
- config.before do
25
+ config.before do |example|
28
26
  if self.class.include?(Capybara::DSL)
29
- example = fetch_current_example.call(self)
30
27
  Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js]
31
28
  Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver]
32
29
  end
33
30
  end
34
31
  end
35
-
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'xpath'
4
+
5
+ module Capybara
6
+ class Selector
7
+ # @api private
8
+ class CSSBuilder
9
+ def initialize(expression)
10
+ @expression = expression || ''
11
+ end
12
+
13
+ attr_reader :expression
14
+
15
+ def add_attribute_conditions(**attributes)
16
+ @expression = attributes.inject(expression) do |css, (name, value)|
17
+ conditions = if name == :class
18
+ class_conditions(value)
19
+ elsif value.is_a? Regexp
20
+ regexp_conditions(name, value)
21
+ else
22
+ [attribute_conditions(name => value)]
23
+ end
24
+
25
+ ::Capybara::Selector::CSS.split(css).map do |sel|
26
+ next sel if conditions.empty?
27
+
28
+ conditions.map { |cond| sel + cond }.join(', ')
29
+ end.join(', ')
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def regexp_conditions(name, value)
36
+ Selector::RegexpDisassembler.new(value).alternated_substrings.map do |strs|
37
+ strs.map do |str|
38
+ "[#{name}*='#{str}'#{' i' if value.casefold?}]"
39
+ end.join
40
+ end
41
+ end
42
+
43
+ def attribute_conditions(attributes)
44
+ attributes.map do |attribute, value|
45
+ case value
46
+ when XPath::Expression
47
+ raise ArgumentError, "XPath expressions are not supported for the :#{attribute} filter with CSS based selectors"
48
+ when Regexp
49
+ Selector::RegexpDisassembler.new(value).substrings.map do |str|
50
+ "[#{attribute}*='#{str}'#{' i' if value.casefold?}]"
51
+ end.join
52
+ when true
53
+ "[#{attribute}]"
54
+ when false
55
+ ':not([attribute])'
56
+ else
57
+ if attribute == :id
58
+ "##{::Capybara::Selector::CSS.escape(value)}"
59
+ else
60
+ "[#{attribute}='#{value}']"
61
+ end
62
+ end
63
+ end.join
64
+ end
65
+
66
+ def class_conditions(classes)
67
+ case classes
68
+ when XPath::Expression
69
+ raise ArgumentError, 'XPath expressions are not supported for the :class filter with CSS based selectors'
70
+ when Regexp
71
+ Selector::RegexpDisassembler.new(classes).alternated_substrings.map do |strs|
72
+ strs.map do |str|
73
+ "[class*='#{str}'#{' i' if classes.casefold?}]"
74
+ end.join
75
+ end
76
+ else
77
+ cls = Array(classes).reject { |c| c.is_a? Regexp }.group_by { |cl| cl.match?(/^!(?!!!)/) }
78
+ [(cls[false].to_a.map { |cl| ".#{Capybara::Selector::CSS.escape(cl.sub(/^!!/, ''))}" } +
79
+ cls[true].to_a.map { |cl| ":not(.#{Capybara::Selector::CSS.escape(cl.slice(1..))})" }).join]
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end