capybara 3.0.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 (312) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +891 -12
  4. data/License.txt +1 -1
  5. data/README.md +257 -84
  6. data/lib/capybara/config.rb +29 -10
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/base.rb +22 -4
  9. data/lib/capybara/driver/node.rb +38 -9
  10. data/lib/capybara/dsl.rb +9 -7
  11. data/lib/capybara/helpers.rb +57 -8
  12. data/lib/capybara/minitest/spec.rb +185 -84
  13. data/lib/capybara/minitest.rb +264 -145
  14. data/lib/capybara/node/actions.rb +248 -124
  15. data/lib/capybara/node/base.rb +35 -20
  16. data/lib/capybara/node/document.rb +14 -2
  17. data/lib/capybara/node/document_matchers.rb +13 -15
  18. data/lib/capybara/node/element.rb +350 -113
  19. data/lib/capybara/node/finders.rb +104 -82
  20. data/lib/capybara/node/matchers.rb +363 -157
  21. data/lib/capybara/node/simple.rb +54 -15
  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 +9 -10
  25. data/lib/capybara/queries/base_query.rb +25 -18
  26. data/lib/capybara/queries/current_path_query.rb +16 -6
  27. data/lib/capybara/queries/match_query.rb +11 -0
  28. data/lib/capybara/queries/selector_query.rb +617 -104
  29. data/lib/capybara/queries/sibling_query.rb +9 -7
  30. data/lib/capybara/queries/style_query.rb +45 -0
  31. data/lib/capybara/queries/text_query.rb +40 -22
  32. data/lib/capybara/queries/title_query.rb +2 -2
  33. data/lib/capybara/rack_test/browser.rb +106 -31
  34. data/lib/capybara/rack_test/driver.rb +16 -7
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +74 -49
  37. data/lib/capybara/rack_test/node.rb +120 -47
  38. data/lib/capybara/rails.rb +1 -1
  39. data/lib/capybara/registration_container.rb +41 -0
  40. data/lib/capybara/registrations/drivers.rb +42 -0
  41. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  42. data/lib/capybara/registrations/servers.rb +66 -0
  43. data/lib/capybara/result.rb +87 -53
  44. data/lib/capybara/rspec/features.rb +8 -10
  45. data/lib/capybara/rspec/matcher_proxies.rb +39 -18
  46. data/lib/capybara/rspec/matchers/base.rb +113 -0
  47. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  48. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  49. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  50. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  51. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  52. data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  53. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  54. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  55. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  56. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  57. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  58. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  59. data/lib/capybara/rspec/matchers.rb +142 -315
  60. data/lib/capybara/rspec.rb +3 -2
  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 +85 -8
  64. data/lib/capybara/selector/definition/button.rb +68 -0
  65. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  66. data/lib/capybara/selector/definition/css.rb +10 -0
  67. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  68. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  69. data/lib/capybara/selector/definition/element.rb +28 -0
  70. data/lib/capybara/selector/definition/field.rb +40 -0
  71. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  72. data/lib/capybara/selector/definition/file_field.rb +13 -0
  73. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  74. data/lib/capybara/selector/definition/frame.rb +17 -0
  75. data/lib/capybara/selector/definition/id.rb +6 -0
  76. data/lib/capybara/selector/definition/label.rb +62 -0
  77. data/lib/capybara/selector/definition/link.rb +55 -0
  78. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  79. data/lib/capybara/selector/definition/option.rb +27 -0
  80. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  81. data/lib/capybara/selector/definition/select.rb +81 -0
  82. data/lib/capybara/selector/definition/table.rb +109 -0
  83. data/lib/capybara/selector/definition/table_row.rb +21 -0
  84. data/lib/capybara/selector/definition/xpath.rb +5 -0
  85. data/lib/capybara/selector/definition.rb +280 -0
  86. data/lib/capybara/selector/filter.rb +1 -0
  87. data/lib/capybara/selector/filter_set.rb +72 -28
  88. data/lib/capybara/selector/filters/base.rb +45 -2
  89. data/lib/capybara/selector/filters/expression_filter.rb +5 -6
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +18 -4
  92. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  93. data/lib/capybara/selector/selector.rb +89 -200
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selector.rb +474 -534
  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 +270 -245
  101. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  102. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  103. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
  104. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  105. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  106. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  107. data/lib/capybara/selenium/extensions/find.rb +110 -0
  108. data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
  109. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  110. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  111. data/lib/capybara/selenium/node.rb +460 -170
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  114. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  115. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  116. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  117. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  118. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  119. data/lib/capybara/selenium/patches/logs.rb +45 -0
  120. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  121. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  122. data/lib/capybara/server/animation_disabler.rb +80 -0
  123. data/lib/capybara/server/checker.rb +44 -0
  124. data/lib/capybara/server/middleware.rb +71 -0
  125. data/lib/capybara/server.rb +58 -67
  126. data/lib/capybara/session/config.rb +40 -6
  127. data/lib/capybara/session/matchers.rb +26 -19
  128. data/lib/capybara/session.rb +252 -194
  129. data/lib/capybara/spec/public/jquery.js +5 -5
  130. data/lib/capybara/spec/public/offset.js +6 -0
  131. data/lib/capybara/spec/public/test.js +126 -8
  132. data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
  133. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
  134. data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
  135. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  136. data/lib/capybara/spec/session/all_spec.rb +135 -44
  137. data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
  138. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
  139. data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
  140. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  141. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  142. data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +76 -52
  143. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +12 -12
  144. data/lib/capybara/spec/session/attach_file_spec.rb +126 -72
  145. data/lib/capybara/spec/session/body_spec.rb +11 -13
  146. data/lib/capybara/spec/session/check_spec.rb +112 -51
  147. data/lib/capybara/spec/session/choose_spec.rb +62 -30
  148. data/lib/capybara/spec/session/click_button_spec.rb +227 -161
  149. data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
  150. data/lib/capybara/spec/session/click_link_spec.rb +89 -55
  151. data/lib/capybara/spec/session/current_scope_spec.rb +8 -8
  152. data/lib/capybara/spec/session/current_url_spec.rb +44 -37
  153. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
  154. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
  155. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  156. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  157. data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
  158. data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
  159. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
  160. data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
  161. data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
  162. data/lib/capybara/spec/session/fill_in_spec.rb +110 -44
  163. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  164. data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
  165. data/lib/capybara/spec/session/find_field_spec.rb +33 -31
  166. data/lib/capybara/spec/session/find_link_spec.rb +42 -14
  167. data/lib/capybara/spec/session/find_spec.rb +251 -142
  168. data/lib/capybara/spec/session/first_spec.rb +45 -44
  169. data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
  170. data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
  171. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
  172. data/lib/capybara/spec/session/frame/within_frame_spec.rb +46 -19
  173. data/lib/capybara/spec/session/go_back_spec.rb +1 -1
  174. data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
  175. data/lib/capybara/spec/session/has_all_selectors_spec.rb +23 -23
  176. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  177. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  178. data/lib/capybara/spec/session/has_button_spec.rb +98 -12
  179. data/lib/capybara/spec/session/has_css_spec.rb +271 -137
  180. data/lib/capybara/spec/session/has_current_path_spec.rb +50 -35
  181. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  182. data/lib/capybara/spec/session/has_field_spec.rb +137 -58
  183. data/lib/capybara/spec/session/has_link_spec.rb +46 -6
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +33 -31
  185. data/lib/capybara/spec/session/has_select_spec.rb +84 -50
  186. data/lib/capybara/spec/session/has_selector_spec.rb +117 -69
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +181 -4
  189. data/lib/capybara/spec/session/has_text_spec.rb +101 -53
  190. data/lib/capybara/spec/session/has_title_spec.rb +19 -14
  191. data/lib/capybara/spec/session/has_xpath_spec.rb +56 -38
  192. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +1 -1
  193. data/lib/capybara/spec/session/html_spec.rb +13 -6
  194. data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
  195. data/lib/capybara/spec/session/node_spec.rb +958 -122
  196. data/lib/capybara/spec/session/node_wrapper_spec.rb +15 -12
  197. data/lib/capybara/spec/session/refresh_spec.rb +9 -7
  198. data/lib/capybara/spec/session/reset_session_spec.rb +65 -37
  199. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +1 -1
  200. data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
  201. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +5 -4
  202. data/lib/capybara/spec/session/save_page_spec.rb +41 -38
  203. data/lib/capybara/spec/session/save_screenshot_spec.rb +13 -11
  204. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  205. data/lib/capybara/spec/session/scroll_spec.rb +119 -0
  206. data/lib/capybara/spec/session/select_spec.rb +102 -76
  207. data/lib/capybara/spec/session/selectors_spec.rb +51 -18
  208. data/lib/capybara/spec/session/sibling_spec.rb +9 -9
  209. data/lib/capybara/spec/session/text_spec.rb +26 -24
  210. data/lib/capybara/spec/session/title_spec.rb +8 -6
  211. data/lib/capybara/spec/session/uncheck_spec.rb +41 -22
  212. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  213. data/lib/capybara/spec/session/visit_spec.rb +79 -53
  214. data/lib/capybara/spec/session/window/become_closed_spec.rb +22 -19
  215. data/lib/capybara/spec/session/window/current_window_spec.rb +4 -3
  216. data/lib/capybara/spec/session/window/open_new_window_spec.rb +4 -3
  217. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +25 -21
  218. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +10 -5
  219. data/lib/capybara/spec/session/window/window_spec.rb +88 -54
  220. data/lib/capybara/spec/session/window/windows_spec.rb +11 -8
  221. data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
  222. data/lib/capybara/spec/session/within_spec.rb +82 -44
  223. data/lib/capybara/spec/spec_helper.rb +46 -52
  224. data/lib/capybara/spec/test_app.rb +148 -41
  225. data/lib/capybara/spec/views/animated.erb +49 -0
  226. data/lib/capybara/spec/views/form.erb +156 -42
  227. data/lib/capybara/spec/views/frame_child.erb +4 -3
  228. data/lib/capybara/spec/views/frame_one.erb +2 -1
  229. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  230. data/lib/capybara/spec/views/frame_two.erb +1 -1
  231. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  232. data/lib/capybara/spec/views/layout.erb +10 -0
  233. data/lib/capybara/spec/views/obscured.erb +47 -0
  234. data/lib/capybara/spec/views/offset.erb +33 -0
  235. data/lib/capybara/spec/views/path.erb +2 -2
  236. data/lib/capybara/spec/views/popup_one.erb +1 -1
  237. data/lib/capybara/spec/views/popup_two.erb +1 -1
  238. data/lib/capybara/spec/views/react.erb +45 -0
  239. data/lib/capybara/spec/views/scroll.erb +21 -0
  240. data/lib/capybara/spec/views/spatial.erb +31 -0
  241. data/lib/capybara/spec/views/tables.erb +68 -1
  242. data/lib/capybara/spec/views/with_animation.erb +81 -0
  243. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  244. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  245. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  246. data/lib/capybara/spec/views/with_hover.erb +3 -2
  247. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  248. data/lib/capybara/spec/views/with_html.erb +46 -11
  249. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  250. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  251. data/lib/capybara/spec/views/with_js.erb +30 -5
  252. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  253. data/lib/capybara/spec/views/with_namespace.erb +21 -0
  254. data/lib/capybara/spec/views/with_scope.erb +2 -2
  255. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  256. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  257. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  258. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  259. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  260. data/lib/capybara/spec/views/with_windows.erb +1 -1
  261. data/lib/capybara/spec/views/within_frames.erb +1 -1
  262. data/lib/capybara/version.rb +1 -1
  263. data/lib/capybara/window.rb +32 -26
  264. data/lib/capybara.rb +128 -104
  265. data/spec/basic_node_spec.rb +59 -34
  266. data/spec/capybara_spec.rb +65 -51
  267. data/spec/counter_spec.rb +35 -0
  268. data/spec/css_builder_spec.rb +101 -0
  269. data/spec/css_splitter_spec.rb +38 -0
  270. data/spec/dsl_spec.rb +84 -55
  271. data/spec/filter_set_spec.rb +24 -7
  272. data/spec/fixtures/certificate.pem +25 -0
  273. data/spec/fixtures/key.pem +27 -0
  274. data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -5
  275. data/spec/fixtures/selenium_driver_rspec_success.rb +5 -5
  276. data/spec/minitest_spec.rb +49 -5
  277. data/spec/minitest_spec_spec.rb +92 -62
  278. data/spec/per_session_config_spec.rb +6 -6
  279. data/spec/rack_test_spec.rb +183 -115
  280. data/spec/regexp_dissassembler_spec.rb +250 -0
  281. data/spec/result_spec.rb +99 -39
  282. data/spec/rspec/features_spec.rb +28 -25
  283. data/spec/rspec/scenarios_spec.rb +10 -6
  284. data/spec/rspec/shared_spec_matchers.rb +418 -364
  285. data/spec/rspec/views_spec.rb +4 -3
  286. data/spec/rspec_matchers_spec.rb +35 -10
  287. data/spec/rspec_spec.rb +109 -85
  288. data/spec/sauce_spec_chrome.rb +43 -0
  289. data/spec/selector_spec.rb +392 -62
  290. data/spec/selenium_spec_chrome.rb +183 -41
  291. data/spec/selenium_spec_chrome_remote.rb +96 -0
  292. data/spec/selenium_spec_edge.rb +41 -8
  293. data/spec/selenium_spec_firefox.rb +228 -0
  294. data/spec/selenium_spec_firefox_remote.rb +94 -0
  295. data/spec/selenium_spec_ie.rb +129 -11
  296. data/spec/selenium_spec_safari.rb +162 -0
  297. data/spec/server_spec.rb +192 -81
  298. data/spec/session_spec.rb +52 -16
  299. data/spec/shared_selenium_node.rb +79 -0
  300. data/spec/shared_selenium_session.rb +460 -123
  301. data/spec/spec_helper.rb +124 -2
  302. data/spec/whitespace_normalizer_spec.rb +54 -0
  303. data/spec/xpath_builder_spec.rb +93 -0
  304. metadata +344 -45
  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/rspec/compound.rb +0 -90
  309. data/lib/capybara/spec/session/assert_selector.rb +0 -149
  310. data/lib/capybara/spec/session/source_spec.rb +0 -0
  311. data/lib/capybara/spec/views/with_title.erb +0 -5
  312. data/spec/selenium_spec_marionette.rb +0 -143
@@ -1,380 +1,207 @@
1
1
  # frozen_string_literal: true
2
2
 
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'
12
+
3
13
  module Capybara
4
14
  module RSpecMatchers
5
- class Matcher
6
- if defined?(::RSpec::Expectations::Version)
7
- require 'capybara/rspec/compound'
8
- include ::Capybara::RSpecMatchers::Compound
9
- end
10
-
11
- attr_reader :failure_message, :failure_message_when_negated
12
-
13
- def wrap(actual)
14
- actual = actual.to_capybara_node if actual.respond_to?(:to_capybara_node)
15
- @context_el = if actual.respond_to?(:has_selector?)
16
- actual
17
- else
18
- Capybara.string(actual.to_s)
19
- end
20
- end
21
-
22
- private
23
-
24
- def wrap_matches?(actual)
25
- yield(wrap(actual))
26
- rescue Capybara::ExpectationNotMet => e
27
- @failure_message = e.message
28
- return false
29
- end
30
-
31
- def wrap_does_not_match?(actual)
32
- yield(wrap(actual))
33
- rescue Capybara::ExpectationNotMet => e
34
- @failure_message_when_negated = e.message
35
- return false
36
- end
37
-
38
- def session_query_args
39
- if @args.last.is_a? Hash
40
- @args.last[:session_options] = session_options
41
- else
42
- @args.push(session_options: session_options)
43
- end
44
- @args
45
- end
46
-
47
- def session_options
48
- @context_el ||= nil
49
- if @context_el.respond_to? :session_options
50
- @context_el.session_options
51
- elsif @context_el.respond_to? :current_scope
52
- @context_el.current_scope.session_options
53
- else
54
- Capybara.session_options
55
- end
56
- end
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(...)
57
20
  end
58
21
 
59
- class HaveSelector < Matcher
60
- def initialize(*args, &filter_block)
61
- @args = args
62
- @filter_block = filter_block
63
- end
64
-
65
- def matches?(actual)
66
- wrap_matches?(actual) { |el| el.assert_selector(*@args, &@filter_block) }
67
- end
68
-
69
- def does_not_match?(actual)
70
- wrap_does_not_match?(actual) { |el| el.assert_no_selector(*@args, &@filter_block) }
71
- end
72
-
73
- def description
74
- "have #{query.description}"
75
- end
76
-
77
- def query
78
- @query ||= Capybara::Queries::SelectorQuery.new(*session_query_args, &@filter_block)
79
- 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(...)
80
27
  end
81
28
 
82
- class HaveAllSelectors < Matcher
83
- def initialize(*args, &filter_block)
84
- @args = args
85
- @filter_block = filter_block
86
- end
87
-
88
- def matches?(actual)
89
- wrap_matches?(actual) { |el| el.assert_all_of_selectors(*@args, &@filter_block) }
90
- end
91
-
92
- def does_not_match?(_actual)
93
- raise ArgumentError, "The have_all_selectors matcher does not support use with not_to/should_not"
94
- end
95
-
96
- def description
97
- "have all selectors"
98
- 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(...)
99
34
  end
100
35
 
101
- class HaveNoSelectors < Matcher
102
- def initialize(*args, &filter_block)
103
- @args = args
104
- @filter_block = filter_block
105
- end
106
-
107
- def matches?(actual)
108
- wrap_matches?(actual) { |el| el.assert_none_of_selectors(*@args, &@filter_block) }
109
- end
110
-
111
- def does_not_match?(_actual)
112
- raise ArgumentError, "The have_none_of_selectors matcher does not support use with not_to/should_not"
113
- end
114
-
115
- def description
116
- "have no selectors"
117
- 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(...)
118
41
  end
119
42
 
120
- class MatchSelector < HaveSelector
121
- def matches?(actual)
122
- wrap_matches?(actual) { |el| el.assert_matches_selector(*@args, &@filter_block) }
123
- end
124
-
125
- def does_not_match?(actual)
126
- wrap_does_not_match?(actual) { |el| el.assert_not_matches_selector(*@args, &@filter_block) }
127
- end
128
-
129
- def description
130
- "match #{query.description}"
131
- end
132
-
133
- def query
134
- @query ||= Capybara::Queries::MatchQuery.new(*session_query_args, &@filter_block)
135
- 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(...)
136
48
  end
137
49
 
138
- class HaveText < Matcher
139
- def initialize(*args)
140
- @args = args.dup
141
- @content = args[0].is_a?(Symbol) ? args[1] : args[0]
142
- end
143
-
144
- def matches?(actual)
145
- wrap_matches?(actual) { |el| el.assert_text(*@args) }
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)
146
53
  end
147
54
 
148
- def does_not_match?(actual)
149
- wrap_does_not_match?(actual) { |el| el.assert_no_text(*@args) }
150
- end
151
-
152
- def description
153
- "text #{format(@content)}"
154
- end
155
-
156
- def format(content)
157
- content.inspect
55
+ define_method "match_#{selector}" do |expr, **options, &optional_filter_block|
56
+ Matchers::MatchSelector.new(selector, expr, **options, &optional_filter_block)
158
57
  end
159
58
  end
160
59
 
161
- class HaveTitle < Matcher
162
- def initialize(*args)
163
- @args = args
164
-
165
- # are set just for backwards compatability
166
- @title = args.first
167
- end
168
-
169
- def matches?(actual)
170
- wrap_matches?(actual) { |el| el.assert_title(*@args) }
171
- end
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 does_not_match?(actual)
174
- wrap_does_not_match?(actual) { |el| el.assert_no_title(*@args) }
175
- end
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?
176
69
 
177
- def description
178
- "have title #{@title.inspect}"
179
- end
180
- 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?
181
74
 
182
- class HaveCurrentPath < Matcher
183
- def initialize(*args)
184
- @args = args
185
- @current_path = args.first
186
- 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?
187
79
 
188
- def matches?(actual)
189
- wrap_matches?(actual) { |el| el.assert_current_path(*@args) }
190
- end
191
-
192
- def does_not_match?(actual)
193
- wrap_does_not_match?(actual) { |el| el.assert_no_current_path(*@args) }
194
- end
195
-
196
- def description
197
- "have current path #{@current_path.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)
198
83
  end
199
84
  end
200
85
 
201
- class NegatedMatcher
202
- def initialize(matcher)
203
- @matcher = matcher
204
- end
205
-
206
- def matches?(actual)
207
- @matcher.does_not_match?(actual)
208
- end
209
-
210
- def does_not_match?(actual)
211
- @matcher.matches?(actual)
212
- end
86
+ # @!method have_element(locator = nil, **options, &optional_filter_block)
87
+ # RSpec matcher for elements.
88
+ #
89
+ # @see Capybara::Node::Matchers#has_element?
213
90
 
214
- def description
215
- "not #{@matcher.description}"
216
- end
91
+ # @!method have_link(locator = nil, **options, &optional_filter_block)
92
+ # RSpec matcher for links.
93
+ #
94
+ # @see Capybara::Node::Matchers#has_link?
217
95
 
218
- def failure_message
219
- @matcher.failure_message_when_negated
220
- end
96
+ # @!method have_button(locator = nil, **options, &optional_filter_block)
97
+ # RSpec matcher for buttons.
98
+ #
99
+ # @see Capybara::Node::Matchers#has_button?
221
100
 
222
- def failure_message_when_negated
223
- @matcher.failure_message
224
- end
225
- 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?
226
105
 
227
- class BecomeClosed
228
- def initialize(options)
229
- @options = options
230
- 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?
231
110
 
232
- def matches?(window)
233
- @window = window
234
- @wait_time = Capybara::Queries::BaseQuery.wait(@options, window.session.config.default_max_wait_time)
235
- start_time = Capybara::Helpers.monotonic_time
236
- while window.exists?
237
- return false if (Capybara::Helpers.monotonic_time - start_time) > @wait_time
238
- sleep 0.05
239
- end
240
- true
241
- end
242
-
243
- def failure_message
244
- "expected #{@window.inspect} to become closed after #{@wait_time} seconds"
245
- 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?
246
115
 
247
- def failure_message_when_negated
248
- "expected #{@window.inspect} not to become closed after #{@wait_time} seconds"
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)
249
119
  end
250
120
  end
251
121
 
252
- # RSpec matcher for whether the element(s) matching a given selector exist
253
- # See {Capybara::Node::Matcher#assert_selector}
254
- def have_selector(*args, &optional_filter_block)
255
- HaveSelector.new(*args, &optional_filter_block)
256
- end
257
-
258
- # RSpec matcher for whether the element(s) matching a group of selectors exist
259
- # See {Capybara::Node::Matcher#assert_all_of_selectors}
260
- def have_all_of_selectors(*args, &optional_filter_block)
261
- HaveAllSelectors.new(*args, &optional_filter_block)
262
- end
263
-
264
- # RSpec matcher for whether no element(s) matching a group of selectors exist
265
- # See {Capybara::Node::Matcher#assert_none_of_selectors}
266
- def have_none_of_selectors(*args, &optional_filter_block)
267
- HaveNoSelectors.new(*args, &optional_filter_block)
268
- end
269
-
270
- # RSpec matcher for whether the current element matches a given selector
271
- # See {Capybara::Node::Matchers#assert_matches_selector}
272
- def match_selector(*args, &optional_filter_block)
273
- MatchSelector.new(*args, &optional_filter_block)
274
- 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?
275
126
 
276
- # RSpec matcher for whether elements(s) matching a given xpath selector exist
277
- # See {Capybara::Node::Matchers#has_xpath?}
278
- def have_xpath(xpath, **options, &optional_filter_block)
279
- HaveSelector.new(:xpath, xpath, options, &optional_filter_block)
280
- end
281
-
282
- # RSpec matcher for whether the current element matches a given xpath selector
283
- def match_xpath(xpath, **options, &optional_filter_block)
284
- MatchSelector.new(:xpath, xpath, options, &optional_filter_block)
285
- 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?
286
131
 
287
- # RSpec matcher for whether elements(s) matching a given css selector exist
288
- # See {Capybara::Node::Matchers#has_css?}
289
- def have_css(css, **options, &optional_filter_block)
290
- HaveSelector.new(:css, css, options, &optional_filter_block)
291
- end
292
-
293
- # RSpec matcher for whether the current element matches a given css selector
294
- def match_css(css, **options, &optional_filter_block)
295
- MatchSelector.new(:css, css, options, &optional_filter_block)
296
- end
297
-
298
- # RSpec matcher for text content
299
- # See {Capybara::SessionMatchers#assert_text}
300
- def have_text(*args)
301
- 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)
302
137
  end
303
138
  alias_method :have_content, :have_text
304
139
 
305
140
  def have_title(title, **options)
306
- HaveTitle.new(title, options)
307
- end
308
-
309
- # RSpec matcher for the current path
310
- # See {Capybara::SessionMatchers#assert_current_path}
311
- def have_current_path(path, **options)
312
- HaveCurrentPath.new(path, options)
141
+ Matchers::HaveTitle.new(title, **options)
313
142
  end
314
143
 
315
- # RSpec matcher for links
316
- # See {Capybara::Node::Matchers#has_link?}
317
- def have_link(locator = nil, **options, &optional_filter_block)
318
- HaveSelector.new(:link, locator, options, &optional_filter_block)
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)
319
149
  end
320
150
 
321
- # RSpec matcher for buttons
322
- # See {Capybara::Node::Matchers#has_button?}
323
- def have_button(locator = nil, **options, &optional_filter_block)
324
- HaveSelector.new(:button, 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)
325
157
  end
326
158
 
327
- # RSpec matcher for links
328
- # See {Capybara::Node::Matchers#has_field?}
329
- def have_field(locator = nil, **options, &optional_filter_block)
330
- HaveSelector.new(:field, locator, options, &optional_filter_block)
331
- end
332
-
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
- HaveSelector.new(:field, locator, options.merge(checked: true), &optional_filter_block)
337
- end
338
-
339
- # RSpec matcher for unchecked fields
340
- # See {Capybara::Node::Matchers#has_unchecked_field?}
341
- def have_unchecked_field(locator = nil, **options, &optional_filter_block)
342
- HaveSelector.new(:field, locator, options.merge(unchecked: true), &optional_filter_block)
343
- end
344
-
345
- # RSpec matcher for select elements
346
- # See {Capybara::Node::Matchers#has_select?}
347
- def have_select(locator = nil, **options, &optional_filter_block)
348
- HaveSelector.new(:select, locator, options, &optional_filter_block)
349
- end
350
-
351
- # RSpec matcher for table elements
352
- # See {Capybara::Node::Matchers#has_table?}
353
- def have_table(locator = nil, **options, &optional_filter_block)
354
- HaveSelector.new(:table, 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)
355
165
  end
356
166
 
357
- %w[selector css xpath text title current_path link button field checked_field unchecked_field select table].each do |matcher_type|
358
- define_method "have_no_#{matcher_type}" do |*args, &optional_filter_block|
359
- NegatedMatcher.new(send("have_#{matcher_type}", *args, &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))
360
172
  end
361
173
  end
362
174
  alias_method :have_no_content, :have_no_text
363
175
 
364
176
  %w[selector css xpath].each do |matcher_type|
365
- define_method "not_match_#{matcher_type}" do |*args, &optional_filter_block|
366
- NegatedMatcher.new(send("match_#{matcher_type}", *args, &optional_filter_block))
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))
367
179
  end
368
180
  end
369
181
 
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(...)
187
+ end
188
+
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(...)
194
+ end
195
+
370
196
  ##
371
197
  # Wait for window to become closed.
198
+ #
372
199
  # @example
373
200
  # expect(window).to become_closed(wait: 0.8)
374
- # @param options [Hash] optional param
375
- # @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum wait time
201
+ #
202
+ # @option options [Numeric] :wait Maximum wait time. Defaults to {Capybara.configure default_max_wait_time}
376
203
  def become_closed(**options)
377
- BecomeClosed.new(options)
204
+ Matchers::BecomeClosed.new(options)
378
205
  end
379
206
  end
380
207
  end
@@ -9,6 +9,8 @@ require 'capybara/rspec/matcher_proxies'
9
9
  RSpec.configure do |config|
10
10
  config.include Capybara::DSL, type: :feature
11
11
  config.include Capybara::RSpecMatchers, type: :feature
12
+ config.include Capybara::DSL, type: :system
13
+ config.include Capybara::RSpecMatchers, type: :system
12
14
  config.include Capybara::RSpecMatchers, type: :view
13
15
 
14
16
  # The before and after blocks must run instantaneously, because Capybara
@@ -20,9 +22,8 @@ RSpec.configure do |config|
20
22
  end
21
23
  end
22
24
 
23
- config.before do
25
+ config.before do |example|
24
26
  if self.class.include?(Capybara::DSL)
25
- example = RSpec.current_example
26
27
  Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js]
27
28
  Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver]
28
29
  end
@@ -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