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,102 +1,146 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  Capybara::SpecHelper.spec '#has_selector?' do
3
4
  before do
4
5
  @session.visit('/with_html')
5
6
  end
6
7
 
7
- it "should be true if the given selector is on the page" do
8
- expect(@session).to have_selector(:xpath, "//p")
9
- expect(@session).to have_selector(:css, "p a#foo")
8
+ it 'should be true if the given selector is on the page' do
9
+ expect(@session).to have_selector(:xpath, '//p')
10
+ expect(@session).to have_selector(:css, 'p a#foo')
10
11
  expect(@session).to have_selector("//p[contains(.,'est')]")
11
12
  end
12
13
 
13
- it "should be false if the given selector is not on the page" do
14
- expect(@session).not_to have_selector(:xpath, "//abbr")
15
- expect(@session).not_to have_selector(:css, "p a#doesnotexist")
14
+ it 'should be false if the given selector is not on the page' do
15
+ expect(@session).not_to have_selector(:xpath, '//abbr')
16
+ expect(@session).not_to have_selector(:css, 'p a#doesnotexist')
16
17
  expect(@session).not_to have_selector("//p[contains(.,'thisstringisnotonpage')]")
17
18
  end
18
19
 
19
- it "should use default selector" do
20
+ it 'should use default selector' do
20
21
  Capybara.default_selector = :css
21
- expect(@session).not_to have_selector("p a#doesnotexist")
22
- expect(@session).to have_selector("p a#foo")
22
+ expect(@session).not_to have_selector('p a#doesnotexist')
23
+ expect(@session).to have_selector('p a#foo')
23
24
  end
24
25
 
25
- it "should respect scopes" do
26
+ it 'should respect scopes' do
26
27
  @session.within "//p[@id='first']" do
27
28
  expect(@session).to have_selector(".//a[@id='foo']")
28
29
  expect(@session).not_to have_selector(".//a[@id='red']")
29
30
  end
30
31
  end
31
32
 
32
- it "should accept a filter block" do
33
- expect(@session).to have_selector(:css, "a", count: 1) { |el| el[:id] == "foo" }
33
+ it 'should accept a filter block' do
34
+ expect(@session).to have_selector(:css, 'a', count: 1) { |el| el[:id] == 'foo' }
34
35
  end
35
36
 
36
- context "with count" do
37
- it "should be true if the content is on the page the given number of times" do
38
- expect(@session).to have_selector("//p", count: 3)
37
+ context 'with count' do
38
+ it 'should be true if the content is on the page the given number of times' do
39
+ expect(@session).to have_selector('//p', count: 3)
39
40
  expect(@session).to have_selector("//p//a[@id='foo']", count: 1)
40
41
  expect(@session).to have_selector("//p[contains(.,'est')]", count: 1)
41
42
  end
42
43
 
43
- it "should be false if the content is on the page the given number of times" do
44
- expect(@session).not_to have_selector("//p", count: 6)
44
+ it 'should be false if the content is on the page the given number of times' do
45
+ expect(@session).not_to have_selector('//p', count: 6)
45
46
  expect(@session).not_to have_selector("//p//a[@id='foo']", count: 2)
46
47
  expect(@session).not_to have_selector("//p[contains(.,'est')]", count: 5)
47
48
  end
48
49
 
49
50
  it "should be false if the content isn't on the page at all" do
50
- expect(@session).not_to have_selector("//abbr", count: 2)
51
+ expect(@session).not_to have_selector('//abbr', count: 2)
51
52
  expect(@session).not_to have_selector("//p//a[@id='doesnotexist']", count: 1)
52
53
  end
53
54
  end
54
55
 
55
- context "with text" do
56
- it "should discard all matches where the given string is not contained" do
57
- expect(@session).to have_selector("//p//a", text: "Redirect", count: 1)
58
- expect(@session).not_to have_selector("//p", text: "Doesnotexist")
56
+ context 'with text' do
57
+ it 'should discard all matches where the given string is not contained' do
58
+ expect(@session).to have_selector('//p//a', text: 'Redirect', count: 1)
59
+ expect(@session).to have_selector(:css, 'p a', text: 'Redirect', count: 1)
60
+ expect(@session).not_to have_selector('//p', text: 'Doesnotexist')
59
61
  end
60
62
 
61
- it "should respect visibility setting" do
62
- expect(@session).to have_selector(:id, "hidden-text", text: "Some of this text is hidden!", visible: false)
63
- expect(@session).not_to have_selector(:id, "hidden-text", text: "Some of this text is hidden!", visible: true)
63
+ it 'should respect visibility setting' do
64
+ expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :all)
65
+ expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :visible)
64
66
  Capybara.ignore_hidden_elements = false
65
- expect(@session).to have_selector(:id, "hidden-text", text: "Some of this text is hidden!", visible: false)
67
+ expect(@session).to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :all)
66
68
  Capybara.visible_text_only = true
67
- expect(@session).not_to have_selector(:id, "hidden-text", text: "Some of this text is hidden!", visible: true)
69
+ expect(@session).not_to have_selector(:id, 'hidden-text', text: 'Some of this text is hidden!', visible: :visible)
70
+ end
71
+
72
+ it 'should discard all matches where the given regexp is not matched' do
73
+ expect(@session).to have_selector('//p//a', text: /re[dab]i/i, count: 1)
74
+ expect(@session).not_to have_selector('//p//a', text: /Red$/)
68
75
  end
69
76
 
70
- it "should discard all matches where the given regexp is not matched" do
71
- expect(@session).to have_selector("//p//a", text: /re[dab]i/i, count: 1)
72
- expect(@session).not_to have_selector("//p//a", text: /Red$/)
77
+ it 'should raise when extra parameters passed' do
78
+ expect do
79
+ expect(@session).to have_selector(:css, 'p a#foo', 'extra')
80
+ end.to raise_error ArgumentError, /extra/
73
81
  end
74
82
 
75
- it "should warn when extra parameters passed" do
76
- expect_any_instance_of(Kernel).to receive(:warn).with(/extra/)
77
- expect(@session).to have_selector(:css, "p a#foo", 'extra')
83
+ context 'with whitespace normalization' do
84
+ context 'Capybara.default_normalize_ws = false' do
85
+ it 'should support normalize_ws option' do
86
+ Capybara.default_normalize_ws = false
87
+ expect(@session).not_to have_selector(:id, 'second', text: 'text with whitespace')
88
+ expect(@session).to have_selector(:id, 'second', text: 'text with whitespace', normalize_ws: true)
89
+ end
90
+ end
91
+
92
+ context 'Capybara.default_normalize_ws = true' do
93
+ it 'should support normalize_ws option' do
94
+ Capybara.default_normalize_ws = true
95
+ expect(@session).to have_selector(:id, 'second', text: 'text with whitespace')
96
+ expect(@session).not_to have_selector(:id, 'second', text: 'text with whitespace', normalize_ws: false)
97
+ end
98
+ end
78
99
  end
79
100
  end
80
101
 
81
- context "with exact_text" do
82
- context "string" do
83
- it "should only match elements that match exactly" do
84
- expect(@session).to have_selector(:id, "h2one", exact_text: "Header Class Test One")
85
- expect(@session).to have_no_selector(:id, "h2one", exact_text: "Header Class Test")
102
+ context 'with exact_text' do
103
+ context 'string' do
104
+ it 'should only match elements that match exactly' do
105
+ expect(@session).to have_selector(:id, 'h2one', exact_text: 'Header Class Test One')
106
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: 'Header Class Test')
86
107
  end
87
108
  end
88
109
 
89
- context "boolean" do
90
- it "should only match elements that match exactly when true" do
91
- expect(@session).to have_selector(:id, "h2one", text: "Header Class Test One", exact_text: true)
92
- expect(@session).to have_no_selector(:id, "h2one", text: "Header Class Test", exact_text: true)
110
+ context 'boolean' do
111
+ it 'should only match elements that match exactly when true' do
112
+ expect(@session).to have_selector(:id, 'h2one', text: 'Header Class Test One', exact_text: true)
113
+ expect(@session).to have_no_selector(:id, 'h2one', text: 'Header Class Test', exact_text: true)
114
+ end
115
+
116
+ it 'should match substrings when false' do
117
+ expect(@session).to have_selector(:id, 'h2one', text: 'Header Class Test One', exact_text: false)
118
+ expect(@session).to have_selector(:id, 'h2one', text: 'Header Class Test', exact_text: false)
93
119
  end
94
120
 
95
- it "should match substrings when false" do
96
- expect(@session).to have_selector(:id, "h2one", text: "Header Class Test One", exact_text: false)
97
- expect(@session).to have_selector(:id, "h2one", text: "Header Class Test", exact_text: false)
121
+ it 'should warn if text option is a regexp that it is ignoring exact_text' do
122
+ allow(Capybara::Helpers).to receive(:warn)
123
+ expect(@session).to have_selector(:id, 'h2one', text: /Class Test/, exact_text: true)
124
+ expect(Capybara::Helpers).to have_received(:warn).with(/'exact_text' option is not supported/)
98
125
  end
99
126
  end
127
+
128
+ context 'regexp' do
129
+ it 'should only match when it fully matches' do
130
+ expect(@session).to have_selector(:id, 'h2one', exact_text: /Header Class Test One/)
131
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Header Class Test/)
132
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Class Test One/)
133
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Class Test/)
134
+ end
135
+ end
136
+ end
137
+
138
+ context 'datalist' do
139
+ it 'should match options' do
140
+ @session.visit('/form')
141
+ expect(@session).to have_selector(:datalist_input, with_options: %w[Jaguar Audi Mercedes])
142
+ expect(@session).not_to have_selector(:datalist_input, with_options: %w[Ford Chevy])
143
+ end
100
144
  end
101
145
  end
102
146
 
@@ -105,64 +149,69 @@ Capybara::SpecHelper.spec '#has_no_selector?' do
105
149
  @session.visit('/with_html')
106
150
  end
107
151
 
108
- it "should be false if the given selector is on the page" do
109
- expect(@session).not_to have_no_selector(:xpath, "//p")
110
- expect(@session).not_to have_no_selector(:css, "p a#foo")
152
+ it 'should be false if the given selector is on the page' do
153
+ expect(@session).not_to have_no_selector(:xpath, '//p')
154
+ expect(@session).not_to have_no_selector(:css, 'p a#foo')
111
155
  expect(@session).not_to have_no_selector("//p[contains(.,'est')]")
112
156
  end
113
157
 
114
- it "should be true if the given selector is not on the page" do
115
- expect(@session).to have_no_selector(:xpath, "//abbr")
116
- expect(@session).to have_no_selector(:css, "p a#doesnotexist")
158
+ it 'should be true if the given selector is not on the page' do
159
+ expect(@session).to have_no_selector(:xpath, '//abbr')
160
+ expect(@session).to have_no_selector(:css, 'p a#doesnotexist')
117
161
  expect(@session).to have_no_selector("//p[contains(.,'thisstringisnotonpage')]")
118
162
  end
119
163
 
120
- it "should use default selector" do
164
+ it 'should use default selector' do
121
165
  Capybara.default_selector = :css
122
- expect(@session).to have_no_selector("p a#doesnotexist")
123
- expect(@session).not_to have_no_selector("p a#foo")
166
+ expect(@session).to have_no_selector('p a#doesnotexist')
167
+ expect(@session).not_to have_no_selector('p a#foo')
124
168
  end
125
169
 
126
- it "should respect scopes" do
170
+ it 'should respect scopes' do
127
171
  @session.within "//p[@id='first']" do
128
172
  expect(@session).not_to have_no_selector(".//a[@id='foo']")
129
173
  expect(@session).to have_no_selector(".//a[@id='red']")
130
174
  end
131
175
  end
132
176
 
133
- it "should accept a filter block" do
134
- skip "RSpec < 3 doesn't pass the block along to the matcher for the Builtin::Has matcher" if rspec2?
135
- expect(@session).to have_no_selector(:css, "a#foo") { |el| el[:id] != "foo" }
177
+ it 'should accept a filter block' do
178
+ expect(@session).to have_no_selector(:css, 'a#foo') { |el| el[:id] != 'foo' }
136
179
  end
137
180
 
138
- context "with count" do
139
- it "should be false if the content is on the page the given number of times" do
140
- expect(@session).not_to have_no_selector("//p", count: 3)
181
+ context 'with count' do
182
+ it 'should be false if the content is on the page the given number of times' do
183
+ expect(@session).not_to have_no_selector('//p', count: 3)
141
184
  expect(@session).not_to have_no_selector("//p//a[@id='foo']", count: 1)
142
185
  expect(@session).not_to have_no_selector("//p[contains(.,'est')]", count: 1)
143
186
  end
144
187
 
145
- it "should be true if the content is on the page the wrong number of times" do
146
- expect(@session).to have_no_selector("//p", count: 6)
188
+ it 'should be true if the content is on the page the wrong number of times' do
189
+ expect(@session).to have_no_selector('//p', count: 6)
147
190
  expect(@session).to have_no_selector("//p//a[@id='foo']", count: 2)
148
191
  expect(@session).to have_no_selector("//p[contains(.,'est')]", count: 5)
149
192
  end
150
193
 
151
194
  it "should be true if the content isn't on the page at all" do
152
- expect(@session).to have_no_selector("//abbr", count: 2)
195
+ expect(@session).to have_no_selector('//abbr', count: 2)
153
196
  expect(@session).to have_no_selector("//p//a[@id='doesnotexist']", count: 1)
154
197
  end
155
198
  end
156
199
 
157
- context "with text" do
158
- it "should discard all matches where the given string is contained" do
159
- expect(@session).not_to have_no_selector("//p//a", text: "Redirect", count: 1)
160
- expect(@session).to have_no_selector("//p", text: "Doesnotexist")
200
+ context 'with text' do
201
+ it 'should discard all matches where the given string is contained' do
202
+ expect(@session).not_to have_no_selector('//p//a', text: 'Redirect', count: 1)
203
+ expect(@session).to have_no_selector('//p', text: 'Doesnotexist')
204
+ end
205
+
206
+ it 'should discard all matches where the given regexp is matched' do
207
+ expect(@session).not_to have_no_selector('//p//a', text: /re[dab]i/i, count: 1)
208
+ expect(@session).to have_no_selector('//p//a', text: /Red$/)
161
209
  end
162
210
 
163
- it "should discard all matches where the given regexp is matched" do
164
- expect(@session).not_to have_no_selector("//p//a", text: /re[dab]i/i, count: 1)
165
- expect(@session).to have_no_selector("//p//a", text: /Red$/)
211
+ it 'should error when matching element exists' do
212
+ expect do
213
+ expect(@session).to have_no_selector('//h2', text: 'Header Class Test Five')
214
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
166
215
  end
167
216
  end
168
217
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ Capybara::SpecHelper.spec '#have_sibling' do
4
+ before do
5
+ @session.visit('/with_html')
6
+ end
7
+
8
+ it 'should assert a prior sibling element using the given locator' do
9
+ el = @session.find(:css, '#mid_sibling')
10
+ expect(el).to have_sibling(:css, '#pre_sibling')
11
+ end
12
+
13
+ it 'should assert a following sibling element using the given locator' do
14
+ el = @session.find(:css, '#mid_sibling')
15
+ expect(el).to have_sibling(:css, '#post_sibling')
16
+ end
17
+
18
+ it 'should not raise an error if there are multiple matches' do
19
+ el = @session.find(:css, '#mid_sibling')
20
+ expect(el).to have_sibling(:css, 'div')
21
+ end
22
+
23
+ it 'should allow counts to be specified' do
24
+ el = @session.find(:css, '#mid_sibling')
25
+
26
+ expect(el).to have_sibling(:css, 'div').exactly(2).times
27
+ expect do
28
+ expect(el).to have_sibling(:css, 'div').once
29
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
30
+ end
31
+ end
32
+
33
+ Capybara::SpecHelper.spec '#have_no_sibling' do
34
+ before do
35
+ @session.visit('/with_html')
36
+ end
37
+
38
+ it 'should assert no matching sibling' do
39
+ el = @session.find(:css, '#mid_sibling')
40
+ expect(el).to have_no_sibling(:css, '#not_a_sibling')
41
+ expect(el).not_to have_sibling(:css, '#not_a_sibling')
42
+ end
43
+
44
+ it 'should raise if there are matching siblings' do
45
+ el = @session.find(:css, '#mid_sibling')
46
+ expect do
47
+ expect(el).to have_no_sibling(:css, '#pre_sibling')
48
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
49
+ end
50
+ end
@@ -1,18 +1,136 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  Capybara::SpecHelper.spec '#has_table?' do
3
4
  before do
4
5
  @session.visit('/tables')
5
6
  end
6
7
 
7
- it "should be true if the table is on the page" do
8
+ it 'should be true if the table is on the page' do
8
9
  expect(@session).to have_table('Villain')
9
10
  expect(@session).to have_table('villain_table')
10
- expect(@session).to have_table(:'villain_table')
11
+ expect(@session).to have_table(:villain_table)
12
+ end
13
+
14
+ it 'should accept rows with column header hashes' do
15
+ expect(@session).to have_table('Horizontal Headers', with_rows:
16
+ [
17
+ { 'First Name' => 'Vern', 'Last Name' => 'Konopelski', 'City' => 'Everette' },
18
+ { 'First Name' => 'Palmer', 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
19
+ ])
20
+ end
21
+
22
+ it 'should accept rows with partial column header hashes' do
23
+ expect(@session).to have_table('Horizontal Headers', with_rows:
24
+ [
25
+ { 'First Name' => 'Thomas' },
26
+ { 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
27
+ ])
28
+
29
+ expect(@session).not_to have_table('Horizontal Headers', with_rows:
30
+ [
31
+ { 'Unmatched Header' => 'Thomas' }
32
+ ])
33
+ end
34
+
35
+ it 'should accept rows with array of cell values' do
36
+ expect(@session).to have_table('Horizontal Headers', with_rows:
37
+ [
38
+ %w[Thomas Walpole Oceanside],
39
+ ['Ratke', 'Lawrence', 'East Sorayashire']
40
+ ])
41
+ end
42
+
43
+ it 'should consider order of cells in each row' do
44
+ expect(@session).not_to have_table('Horizontal Headers', with_rows:
45
+ [
46
+ %w[Thomas Walpole Oceanside],
47
+ ['Lawrence', 'Ratke', 'East Sorayashire']
48
+ ])
11
49
  end
12
50
 
13
- it "should be false if the table is not on the page" do
51
+ it 'should accept all rows with array of cell values' do
52
+ expect(@session).to have_table('Horizontal Headers', rows:
53
+ [
54
+ %w[Thomas Walpole Oceanside],
55
+ %w[Danilo Wilkinson Johnsonville],
56
+ %w[Vern Konopelski Everette],
57
+ ['Ratke', 'Lawrence', 'East Sorayashire'],
58
+ ['Palmer', 'Sawayn', 'West Trinidad']
59
+ ])
60
+ end
61
+
62
+ it 'should match with vertical headers' do
63
+ expect(@session).to have_table('Vertical Headers', with_cols:
64
+ [
65
+ { 'First Name' => 'Thomas' },
66
+ { 'First Name' => 'Danilo', 'Last Name' => 'Wilkinson', 'City' => 'Johnsonville' },
67
+ { 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
68
+ ])
69
+ end
70
+
71
+ it 'should match col with array of cell values' do
72
+ expect(@session).to have_table('Vertical Headers', with_cols:
73
+ [
74
+ %w[Vern Konopelski Everette]
75
+ ])
76
+ end
77
+
78
+ it 'should match cols with array of cell values' do
79
+ expect(@session).to have_table('Vertical Headers', with_cols:
80
+ [
81
+ %w[Danilo Wilkinson Johnsonville],
82
+ %w[Vern Konopelski Everette]
83
+ ])
84
+ end
85
+
86
+ it 'should match all cols with array of cell values' do
87
+ expect(@session).to have_table('Vertical Headers', cols:
88
+ [
89
+ %w[Thomas Walpole Oceanside],
90
+ %w[Danilo Wilkinson Johnsonville],
91
+ %w[Vern Konopelski Everette],
92
+ ['Ratke', 'Lawrence', 'East Sorayashire'],
93
+ ['Palmer', 'Sawayn', 'West Trinidad']
94
+ ])
95
+ end
96
+
97
+ it "should not match if the order of cell values doesn't match" do
98
+ expect(@session).not_to have_table('Vertical Headers', with_cols:
99
+ [
100
+ %w[Vern Everette Konopelski]
101
+ ])
102
+ end
103
+
104
+ it "should not match with vertical headers if the columns don't match" do
105
+ expect(@session).not_to have_table('Vertical Headers', with_cols:
106
+ [
107
+ { 'First Name' => 'Thomas' },
108
+ { 'First Name' => 'Danilo', 'Last Name' => 'Walpole', 'City' => 'Johnsonville' },
109
+ { 'Last Name' => 'Sawayn', 'City' => 'West Trinidad' }
110
+ ])
111
+
112
+ expect(@session).not_to have_table('Vertical Headers', with_cols:
113
+ [
114
+ { 'Unmatched Header' => 'Thomas' }
115
+ ])
116
+ end
117
+
118
+ it 'should be false if the table is not on the page' do
14
119
  expect(@session).not_to have_table('Monkey')
15
120
  end
121
+
122
+ it 'should find row by header and cell values' do
123
+ expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, 'First Name' => 'Thomas', 'Last Name' => 'Walpole')
124
+ expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, 'Last Name' => 'Walpole')
125
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, 'First Name' => 'Walpole')
126
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, 'Unmatched Header' => 'Thomas')
127
+ end
128
+
129
+ it 'should find row by cell values' do
130
+ expect(@session.find(:table, 'Horizontal Headers')).to have_selector(:table_row, %w[Thomas Walpole Oceanside])
131
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, %w[Walpole Thomas])
132
+ expect(@session.find(:table, 'Horizontal Headers')).not_to have_selector(:table_row, %w[Other])
133
+ end
16
134
  end
17
135
 
18
136
  Capybara::SpecHelper.spec '#has_no_table?' do
@@ -20,12 +138,72 @@ Capybara::SpecHelper.spec '#has_no_table?' do
20
138
  @session.visit('/tables')
21
139
  end
22
140
 
23
- it "should be false if the table is on the page" do
141
+ it 'should be false if the table is on the page' do
24
142
  expect(@session).not_to have_no_table('Villain')
25
143
  expect(@session).not_to have_no_table('villain_table')
26
144
  end
27
145
 
28
- it "should be true if the table is not on the page" do
146
+ it 'should be true if the table is not on the page' do
29
147
  expect(@session).to have_no_table('Monkey')
30
148
  end
149
+
150
+ it 'should consider rows' do
151
+ expect(@session).to have_no_table('Horizontal Headers', with_rows:
152
+ [
153
+ { 'First Name' => 'Thomas', 'City' => 'Los Angeles' }
154
+ ])
155
+ end
156
+
157
+ context 'using :with_cols' do
158
+ it 'should consider a single column' do
159
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
160
+ [
161
+ { 'First Name' => 'Joe' }
162
+ ])
163
+ end
164
+
165
+ it 'should be true even if the last column does exist' do
166
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
167
+ [
168
+ {
169
+ 'First Name' => 'What?',
170
+ 'What?' => 'Walpole',
171
+ 'City' => 'Oceanside' # This line makes the example fail
172
+ }
173
+ ])
174
+ end
175
+
176
+ it 'should be true if none of the columns exist' do
177
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
178
+ [
179
+ {
180
+ 'First Name' => 'What?',
181
+ 'What?' => 'Walpole',
182
+ 'City' => 'What?'
183
+ }
184
+ ])
185
+ end
186
+
187
+ it 'should be true if the first column does match' do
188
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
189
+ [
190
+ {
191
+ 'First Name' => 'Thomas',
192
+ 'Last Name' => 'What',
193
+ 'City' => 'What'
194
+ }
195
+ ])
196
+ end
197
+
198
+ it 'should be true if none of the columns match' do
199
+ expect(@session).to have_no_table('Vertical Headers', with_cols:
200
+ [
201
+ {
202
+ 'First Name' => 'What',
203
+ 'Last Name' => 'What',
204
+ 'City' => 'What'
205
+ }
206
+ ])
207
+ end
208
+ end
31
209
  end