capybara 2.7.0 → 3.35.3

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 (318) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +1 -0
  3. data/History.md +1147 -11
  4. data/License.txt +1 -1
  5. data/README.md +252 -131
  6. data/lib/capybara/config.rb +92 -0
  7. data/lib/capybara/cucumber.rb +3 -3
  8. data/lib/capybara/driver/base.rb +52 -21
  9. data/lib/capybara/driver/node.rb +48 -14
  10. data/lib/capybara/dsl.rb +16 -9
  11. data/lib/capybara/helpers.rb +72 -81
  12. data/lib/capybara/minitest/spec.rb +267 -0
  13. data/lib/capybara/minitest.rb +385 -0
  14. data/lib/capybara/node/actions.rb +337 -89
  15. data/lib/capybara/node/base.rb +50 -32
  16. data/lib/capybara/node/document.rb +19 -3
  17. data/lib/capybara/node/document_matchers.rb +22 -24
  18. data/lib/capybara/node/element.rb +388 -125
  19. data/lib/capybara/node/finders.rb +231 -121
  20. data/lib/capybara/node/matchers.rb +503 -217
  21. data/lib/capybara/node/simple.rb +64 -27
  22. data/lib/capybara/queries/ancestor_query.rb +27 -0
  23. data/lib/capybara/queries/base_query.rb +87 -11
  24. data/lib/capybara/queries/current_path_query.rb +24 -24
  25. data/lib/capybara/queries/match_query.rb +15 -10
  26. data/lib/capybara/queries/selector_query.rb +675 -81
  27. data/lib/capybara/queries/sibling_query.rb +26 -0
  28. data/lib/capybara/queries/style_query.rb +45 -0
  29. data/lib/capybara/queries/text_query.rb +88 -20
  30. data/lib/capybara/queries/title_query.rb +9 -11
  31. data/lib/capybara/rack_test/browser.rb +63 -39
  32. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  33. data/lib/capybara/rack_test/driver.rb +26 -16
  34. data/lib/capybara/rack_test/errors.rb +6 -0
  35. data/lib/capybara/rack_test/form.rb +73 -58
  36. data/lib/capybara/rack_test/node.rb +187 -67
  37. data/lib/capybara/rails.rb +4 -8
  38. data/lib/capybara/registration_container.rb +44 -0
  39. data/lib/capybara/registrations/drivers.rb +42 -0
  40. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  41. data/lib/capybara/registrations/servers.rb +45 -0
  42. data/lib/capybara/result.rb +142 -14
  43. data/lib/capybara/rspec/features.rb +17 -42
  44. data/lib/capybara/rspec/matcher_proxies.rb +82 -0
  45. data/lib/capybara/rspec/matchers/base.rb +111 -0
  46. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  47. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  48. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  49. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  50. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  51. data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
  52. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  53. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  54. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  55. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  56. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  57. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  58. data/lib/capybara/rspec/matchers.rb +143 -244
  59. data/lib/capybara/rspec.rb +10 -12
  60. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  61. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  62. data/lib/capybara/selector/css.rb +102 -0
  63. data/lib/capybara/selector/definition/button.rb +63 -0
  64. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  65. data/lib/capybara/selector/definition/css.rb +10 -0
  66. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  67. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  68. data/lib/capybara/selector/definition/element.rb +28 -0
  69. data/lib/capybara/selector/definition/field.rb +40 -0
  70. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  71. data/lib/capybara/selector/definition/file_field.rb +13 -0
  72. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  73. data/lib/capybara/selector/definition/frame.rb +17 -0
  74. data/lib/capybara/selector/definition/id.rb +6 -0
  75. data/lib/capybara/selector/definition/label.rb +62 -0
  76. data/lib/capybara/selector/definition/link.rb +54 -0
  77. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  78. data/lib/capybara/selector/definition/option.rb +27 -0
  79. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  80. data/lib/capybara/selector/definition/select.rb +81 -0
  81. data/lib/capybara/selector/definition/table.rb +109 -0
  82. data/lib/capybara/selector/definition/table_row.rb +21 -0
  83. data/lib/capybara/selector/definition/xpath.rb +5 -0
  84. data/lib/capybara/selector/definition.rb +278 -0
  85. data/lib/capybara/selector/filter.rb +3 -46
  86. data/lib/capybara/selector/filter_set.rb +124 -0
  87. data/lib/capybara/selector/filters/base.rb +77 -0
  88. data/lib/capybara/selector/filters/expression_filter.rb +22 -0
  89. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  90. data/lib/capybara/selector/filters/node_filter.rb +31 -0
  91. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  92. data/lib/capybara/selector/selector.rb +155 -0
  93. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  94. data/lib/capybara/selector.rb +232 -369
  95. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  96. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  97. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  98. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  99. data/lib/capybara/selenium/driver.rb +380 -142
  100. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  101. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
  102. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
  103. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  104. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  105. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  106. data/lib/capybara/selenium/extensions/find.rb +110 -0
  107. data/lib/capybara/selenium/extensions/html5_drag.rb +228 -0
  108. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  109. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  110. data/lib/capybara/selenium/logger_suppressor.rb +40 -0
  111. data/lib/capybara/selenium/node.rb +528 -97
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  114. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  115. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  116. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  117. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  118. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  119. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  120. data/lib/capybara/selenium/patches/logs.rb +45 -0
  121. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  122. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  123. data/lib/capybara/server/animation_disabler.rb +63 -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 +74 -71
  127. data/lib/capybara/session/config.rb +126 -0
  128. data/lib/capybara/session/matchers.rb +44 -27
  129. data/lib/capybara/session.rb +500 -297
  130. data/lib/capybara/spec/fixtures/no_extension +1 -0
  131. data/lib/capybara/spec/public/jquery.js +5 -5
  132. data/lib/capybara/spec/public/offset.js +6 -0
  133. data/lib/capybara/spec/public/test.js +168 -14
  134. data/lib/capybara/spec/session/accept_alert_spec.rb +37 -14
  135. data/lib/capybara/spec/session/accept_confirm_spec.rb +7 -6
  136. data/lib/capybara/spec/session/accept_prompt_spec.rb +38 -10
  137. data/lib/capybara/spec/session/all_spec.rb +179 -59
  138. data/lib/capybara/spec/session/ancestor_spec.rb +88 -0
  139. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
  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_spec.rb +93 -0
  145. data/lib/capybara/spec/session/attach_file_spec.rb +154 -48
  146. data/lib/capybara/spec/session/body_spec.rb +12 -13
  147. data/lib/capybara/spec/session/check_spec.rb +168 -41
  148. data/lib/capybara/spec/session/choose_spec.rb +75 -23
  149. data/lib/capybara/spec/session/click_button_spec.rb +243 -175
  150. data/lib/capybara/spec/session/click_link_or_button_spec.rb +57 -32
  151. data/lib/capybara/spec/session/click_link_spec.rb +100 -53
  152. data/lib/capybara/spec/session/current_scope_spec.rb +11 -10
  153. data/lib/capybara/spec/session/current_url_spec.rb +61 -35
  154. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +7 -7
  155. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +5 -4
  156. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +13 -6
  157. data/lib/capybara/spec/session/element/match_css_spec.rb +21 -7
  158. data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
  159. data/lib/capybara/spec/session/element/matches_selector_spec.rb +91 -34
  160. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
  161. data/lib/capybara/spec/session/evaluate_script_spec.rb +45 -3
  162. data/lib/capybara/spec/session/execute_script_spec.rb +24 -4
  163. data/lib/capybara/spec/session/fill_in_spec.rb +166 -64
  164. data/lib/capybara/spec/session/find_button_spec.rb +37 -18
  165. data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
  166. data/lib/capybara/spec/session/find_field_spec.rb +57 -34
  167. data/lib/capybara/spec/session/find_link_spec.rb +47 -10
  168. data/lib/capybara/spec/session/find_spec.rb +290 -144
  169. data/lib/capybara/spec/session/first_spec.rb +91 -48
  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 +116 -0
  173. data/lib/capybara/spec/session/frame/within_frame_spec.rb +112 -0
  174. data/lib/capybara/spec/session/go_back_spec.rb +3 -2
  175. data/lib/capybara/spec/session/go_forward_spec.rb +3 -2
  176. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  177. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  178. data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
  179. data/lib/capybara/spec/session/has_button_spec.rb +76 -19
  180. data/lib/capybara/spec/session/has_css_spec.rb +277 -131
  181. data/lib/capybara/spec/session/has_current_path_spec.rb +98 -26
  182. data/lib/capybara/spec/session/has_field_spec.rb +177 -107
  183. data/lib/capybara/spec/session/has_link_spec.rb +13 -12
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
  185. data/lib/capybara/spec/session/has_select_spec.rb +191 -95
  186. data/lib/capybara/spec/session/has_selector_spec.rb +128 -64
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +172 -5
  189. data/lib/capybara/spec/session/has_text_spec.rb +126 -60
  190. data/lib/capybara/spec/session/has_title_spec.rb +35 -12
  191. data/lib/capybara/spec/session/has_xpath_spec.rb +74 -53
  192. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
  193. data/lib/capybara/spec/session/html_spec.rb +14 -6
  194. data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
  195. data/lib/capybara/spec/session/node_spec.rb +1028 -131
  196. data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
  197. data/lib/capybara/spec/session/refresh_spec.rb +34 -0
  198. data/lib/capybara/spec/session/reset_session_spec.rb +75 -34
  199. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
  200. data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
  201. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +11 -15
  202. data/lib/capybara/spec/session/save_page_spec.rb +42 -55
  203. data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
  204. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  205. data/lib/capybara/spec/session/scroll_spec.rb +117 -0
  206. data/lib/capybara/spec/session/select_spec.rb +112 -85
  207. data/lib/capybara/spec/session/selectors_spec.rb +71 -8
  208. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  209. data/lib/capybara/spec/session/text_spec.rb +38 -23
  210. data/lib/capybara/spec/session/title_spec.rb +17 -5
  211. data/lib/capybara/spec/session/uncheck_spec.rb +71 -12
  212. data/lib/capybara/spec/session/unselect_spec.rb +44 -43
  213. data/lib/capybara/spec/session/visit_spec.rb +99 -32
  214. data/lib/capybara/spec/session/window/become_closed_spec.rb +33 -29
  215. data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
  216. data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
  217. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +39 -30
  218. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +17 -10
  219. data/lib/capybara/spec/session/window/window_spec.rb +121 -73
  220. data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
  221. data/lib/capybara/spec/session/window/within_window_spec.rb +52 -82
  222. data/lib/capybara/spec/session/within_spec.rb +76 -43
  223. data/lib/capybara/spec/spec_helper.rb +67 -33
  224. data/lib/capybara/spec/test_app.rb +85 -36
  225. data/lib/capybara/spec/views/animated.erb +49 -0
  226. data/lib/capybara/spec/views/buttons.erb +1 -1
  227. data/lib/capybara/spec/views/fieldsets.erb +1 -1
  228. data/lib/capybara/spec/views/form.erb +227 -20
  229. data/lib/capybara/spec/views/frame_child.erb +10 -2
  230. data/lib/capybara/spec/views/frame_one.erb +2 -1
  231. data/lib/capybara/spec/views/frame_parent.erb +2 -2
  232. data/lib/capybara/spec/views/frame_two.erb +1 -1
  233. data/lib/capybara/spec/views/header_links.erb +1 -1
  234. data/lib/capybara/spec/views/host_links.erb +1 -1
  235. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  236. data/lib/capybara/spec/views/obscured.erb +47 -0
  237. data/lib/capybara/spec/views/offset.erb +32 -0
  238. data/lib/capybara/spec/views/path.erb +1 -1
  239. data/lib/capybara/spec/views/popup_one.erb +1 -1
  240. data/lib/capybara/spec/views/popup_two.erb +1 -1
  241. data/lib/capybara/spec/views/postback.erb +1 -1
  242. data/lib/capybara/spec/views/react.erb +45 -0
  243. data/lib/capybara/spec/views/scroll.erb +20 -0
  244. data/lib/capybara/spec/views/spatial.erb +31 -0
  245. data/lib/capybara/spec/views/tables.erb +69 -2
  246. data/lib/capybara/spec/views/with_animation.erb +82 -0
  247. data/lib/capybara/spec/views/with_base_tag.erb +1 -1
  248. data/lib/capybara/spec/views/with_count.erb +1 -1
  249. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  250. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  251. data/lib/capybara/spec/views/with_hover.erb +7 -1
  252. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  253. data/lib/capybara/spec/views/with_html.erb +100 -10
  254. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  255. data/lib/capybara/spec/views/with_html_entities.erb +1 -1
  256. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  257. data/lib/capybara/spec/views/with_js.erb +49 -3
  258. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  259. data/lib/capybara/spec/views/with_namespace.erb +20 -0
  260. data/lib/capybara/spec/views/with_scope.erb +1 -1
  261. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  262. data/lib/capybara/spec/views/with_simple_html.erb +1 -1
  263. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  264. data/lib/capybara/spec/views/with_title.erb +1 -1
  265. data/lib/capybara/spec/views/with_unload_alert.erb +3 -1
  266. data/lib/capybara/spec/views/with_windows.erb +7 -1
  267. data/lib/capybara/spec/views/within_frames.erb +6 -3
  268. data/lib/capybara/version.rb +2 -1
  269. data/lib/capybara/window.rb +39 -21
  270. data/lib/capybara.rb +208 -186
  271. data/spec/basic_node_spec.rb +52 -39
  272. data/spec/capybara_spec.rb +72 -50
  273. data/spec/css_builder_spec.rb +101 -0
  274. data/spec/css_splitter_spec.rb +38 -0
  275. data/spec/dsl_spec.rb +81 -61
  276. data/spec/filter_set_spec.rb +46 -0
  277. data/spec/fixtures/capybara.csv +1 -0
  278. data/spec/fixtures/certificate.pem +25 -0
  279. data/spec/fixtures/key.pem +27 -0
  280. data/spec/fixtures/selenium_driver_rspec_failure.rb +7 -3
  281. data/spec/fixtures/selenium_driver_rspec_success.rb +7 -3
  282. data/spec/minitest_spec.rb +164 -0
  283. data/spec/minitest_spec_spec.rb +162 -0
  284. data/spec/per_session_config_spec.rb +68 -0
  285. data/spec/rack_test_spec.rb +189 -96
  286. data/spec/regexp_dissassembler_spec.rb +250 -0
  287. data/spec/result_spec.rb +143 -13
  288. data/spec/rspec/features_spec.rb +38 -32
  289. data/spec/rspec/scenarios_spec.rb +9 -7
  290. data/spec/rspec/shared_spec_matchers.rb +959 -0
  291. data/spec/rspec/views_spec.rb +9 -3
  292. data/spec/rspec_matchers_spec.rb +62 -0
  293. data/spec/rspec_spec.rb +127 -30
  294. data/spec/sauce_spec_chrome.rb +43 -0
  295. data/spec/selector_spec.rb +458 -37
  296. data/spec/selenium_spec_chrome.rb +196 -9
  297. data/spec/selenium_spec_chrome_remote.rb +100 -0
  298. data/spec/selenium_spec_edge.rb +47 -0
  299. data/spec/selenium_spec_firefox.rb +210 -0
  300. data/spec/selenium_spec_firefox_remote.rb +80 -0
  301. data/spec/selenium_spec_ie.rb +150 -0
  302. data/spec/selenium_spec_safari.rb +148 -0
  303. data/spec/server_spec.rb +200 -101
  304. data/spec/session_spec.rb +91 -0
  305. data/spec/shared_selenium_node.rb +83 -0
  306. data/spec/shared_selenium_session.rb +558 -0
  307. data/spec/spec_helper.rb +94 -2
  308. data/spec/xpath_builder_spec.rb +93 -0
  309. metadata +420 -60
  310. data/lib/capybara/query.rb +0 -7
  311. data/lib/capybara/spec/session/assert_current_path.rb +0 -60
  312. data/lib/capybara/spec/session/assert_selector.rb +0 -148
  313. data/lib/capybara/spec/session/assert_text.rb +0 -196
  314. data/lib/capybara/spec/session/assert_title.rb +0 -70
  315. data/lib/capybara/spec/session/source_spec.rb +0 -0
  316. data/lib/capybara/spec/session/within_frame_spec.rb +0 -53
  317. data/spec/rspec/matchers_spec.rb +0 -827
  318. data/spec/selenium_spec.rb +0 -151
@@ -1,21 +1,23 @@
1
1
  # frozen_string_literal: true
2
+
3
+ # rubocop:disable RSpec/MultipleDescribes
4
+
2
5
  require 'spec_helper'
3
6
  require 'capybara/rspec'
4
7
 
5
- RSpec.configuration.before(:each, { file_path: "./spec/rspec/scenarios_spec.rb" } ) do
8
+ RSpec.configuration.before(:each, file_path: './spec/rspec/scenarios_spec.rb') do
6
9
  @in_filtered_hook = true
7
10
  end
8
11
 
9
- if RSpec::Core::Version::STRING.to_f >= 3.0
10
- feature "if fscenario aliases focused tag then" do
11
- fscenario "scenario should have focused meta tag" do |example|
12
- expect(example.metadata[:focus]).to eq true
13
- end
12
+ feature 'if fscenario aliases focused tag then' do
13
+ fscenario 'scenario should have focused meta tag' do |example| # rubocop:disable RSpec/Focus
14
+ expect(example.metadata[:focus]).to eq true
14
15
  end
15
16
  end
16
17
 
17
- feature "if xscenario aliases to pending then" do
18
+ feature 'if xscenario aliases to pending then' do
18
19
  xscenario "this test should be 'temporarily disabled with xscenario'" do
19
20
  end
20
21
  end
21
22
 
23
+ # rubocop:enable RSpec/MultipleDescribes
@@ -0,0 +1,959 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'capybara/dsl'
5
+ require 'capybara/rspec/matchers'
6
+ require 'benchmark'
7
+
8
+ # rubocop:disable RSpec/ExpectActual
9
+
10
+ RSpec.shared_examples Capybara::RSpecMatchers do |session, _mode|
11
+ include Capybara::DSL
12
+ include Capybara::RSpecMatchers
13
+
14
+ describe 'have_css matcher' do
15
+ it 'gives proper description' do
16
+ expect(have_css('h1').description).to eq('have visible css "h1"')
17
+ end
18
+
19
+ context 'on a string' do
20
+ context 'with should' do
21
+ it 'passes if has_css? returns true' do
22
+ expect('<h1>Text</h1>').to have_css('h1')
23
+ end
24
+
25
+ it 'fails if has_css? returns false' do
26
+ expect do
27
+ expect('<h1>Text</h1>').to have_css('h2')
28
+ end.to raise_error(/expected to find css "h2" but there were no matches/)
29
+ end
30
+
31
+ it 'passes if matched node count equals expected count' do
32
+ expect('<h1>Text</h1>').to have_css('h1', count: 1)
33
+ end
34
+
35
+ it 'fails if matched node count does not equal expected count' do
36
+ expect do
37
+ expect('<h1>Text</h1>').to have_css('h1', count: 2)
38
+ end.to raise_error('expected to find visible css "h1" 2 times, found 1 match: "Text"')
39
+ end
40
+
41
+ it 'fails if matched node count is less than expected minimum count' do
42
+ expect do
43
+ expect('<h1>Text</h1>').to have_css('p', minimum: 1)
44
+ end.to raise_error('expected to find css "p" at least 1 time but there were no matches')
45
+ end
46
+
47
+ it 'fails if matched node count is more than expected maximum count' do
48
+ expect do
49
+ expect('<h1>Text</h1><h1>Text</h1><h1>Text</h1>').to have_css('h1', maximum: 2)
50
+ end.to raise_error('expected to find visible css "h1" at most 2 times, found 3 matches: "Text", "Text", "Text"')
51
+ end
52
+
53
+ it 'fails if matched node count does not belong to expected range' do
54
+ expect do
55
+ expect('<h1>Text</h1>').to have_css('h1', between: 2..3)
56
+ end.to raise_error('expected to find visible css "h1" between 2 and 3 times, found 1 match: "Text"')
57
+ end
58
+ end
59
+
60
+ context 'with should_not' do
61
+ it 'passes if has_no_css? returns true' do
62
+ expect('<h1>Text</h1>').not_to have_css('h2')
63
+ end
64
+
65
+ it 'fails if has_no_css? returns false' do
66
+ expect do
67
+ expect('<h1>Text</h1>').not_to have_css('h1')
68
+ end.to raise_error(/expected not to find visible css "h1"/)
69
+ end
70
+
71
+ it 'passes if matched node count does not equal expected count' do
72
+ expect('<h1>Text</h1>').not_to have_css('h1', count: 2)
73
+ end
74
+
75
+ it 'fails if matched node count equals expected count' do
76
+ expect do
77
+ expect('<h1>Text</h1>').not_to have_css('h1', count: 1)
78
+ end.to raise_error(/expected not to find visible css "h1"/)
79
+ end
80
+ end
81
+
82
+ it 'supports compounding' do
83
+ expect('<h1>Text</h1><h2>Text</h2>').to have_css('h1').and have_css('h2')
84
+ expect('<h1>Text</h1><h2>Text</h2>').to have_css('h3').or have_css('h1')
85
+ expect('<h1>Text</h1><h2>Text</h2>').to have_no_css('h4').and have_css('h2')
86
+ expect('<h1>Text</h1><h2>Text</h2>').to have_no_css('h2').or have_css('h1')
87
+ end
88
+ end
89
+
90
+ context 'on a page or node' do
91
+ before do
92
+ session.visit('/with_html')
93
+ end
94
+
95
+ context 'with should' do
96
+ it 'passes if has_css? returns true' do
97
+ expect(session).to have_css('h1')
98
+ end
99
+
100
+ it 'fails if has_css? returns false' do
101
+ expect do
102
+ expect(session).to have_css('h1#doesnotexist')
103
+ end.to raise_error(/expected to find css "h1#doesnotexist" but there were no matches/)
104
+ end
105
+ end
106
+
107
+ context 'with should_not' do
108
+ it 'passes if has_no_css? returns true' do
109
+ expect(session).not_to have_css('h1#doesnotexist')
110
+ end
111
+
112
+ it 'fails if has_no_css? returns false' do
113
+ expect do
114
+ expect(session).not_to have_css('h1')
115
+ end.to raise_error(/expected not to find visible css "h1"/)
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ describe 'have_xpath matcher' do
122
+ it 'gives proper description' do
123
+ expect(have_xpath('//h1').description).to eq("have visible xpath \"\/\/h1\"")
124
+ end
125
+
126
+ context 'on a string' do
127
+ context 'with should' do
128
+ it 'passes if has_xpath? returns true' do
129
+ expect('<h1>Text</h1>').to have_xpath('//h1')
130
+ end
131
+
132
+ it 'fails if has_xpath? returns false' do
133
+ expect do
134
+ expect('<h1>Text</h1>').to have_xpath('//h2')
135
+ end.to raise_error(%r{expected to find xpath "//h2" but there were no matches})
136
+ end
137
+ end
138
+
139
+ context 'with should_not' do
140
+ it 'passes if has_no_xpath? returns true' do
141
+ expect('<h1>Text</h1>').not_to have_xpath('//h2')
142
+ end
143
+
144
+ it 'fails if has_no_xpath? returns false' do
145
+ expect do
146
+ expect('<h1>Text</h1>').not_to have_xpath('//h1')
147
+ end.to raise_error(%r{expected not to find visible xpath "//h1"})
148
+ end
149
+ end
150
+
151
+ it 'supports compounding' do
152
+ expect('<h1>Text</h1><h2>Text</h2>').to have_xpath('//h1').and have_xpath('//h2')
153
+ expect('<h1>Text</h1><h2>Text</h2>').to have_xpath('//h3').or have_xpath('//h1')
154
+ expect('<h1>Text</h1><h2>Text</h2>').to have_no_xpath('//h4').and have_xpath('//h1')
155
+ expect('<h1>Text</h1><h2>Text</h2>').to have_no_xpath('//h4').or have_xpath('//h4')
156
+ end
157
+ end
158
+
159
+ context 'on a page or node' do
160
+ before do
161
+ session.visit('/with_html')
162
+ end
163
+
164
+ context 'with should' do
165
+ it 'passes if has_xpath? returns true' do
166
+ expect(session).to have_xpath('//h1')
167
+ end
168
+
169
+ it 'fails if has_xpath? returns false' do
170
+ expect do
171
+ expect(session).to have_xpath("//h1[@id='doesnotexist']")
172
+ end.to raise_error(%r{expected to find xpath "//h1\[@id='doesnotexist'\]" but there were no matches})
173
+ end
174
+ end
175
+
176
+ context 'with should_not' do
177
+ it 'passes if has_no_xpath? returns true' do
178
+ expect(session).not_to have_xpath('//h1[@id="doesnotexist"]')
179
+ end
180
+
181
+ it 'fails if has_no_xpath? returns false' do
182
+ expect do
183
+ expect(session).not_to have_xpath('//h1')
184
+ end.to raise_error(%r{expected not to find visible xpath "//h1"})
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ describe 'have_selector matcher' do
191
+ it 'gives proper description' do
192
+ matcher = have_selector('//h1')
193
+ expect('<h1>Text</h1>').to matcher
194
+ expect(matcher.description).to eq('have visible xpath "//h1"')
195
+ end
196
+
197
+ context 'on a string' do
198
+ context 'with should' do
199
+ it 'passes if has_selector? returns true' do
200
+ expect('<h1>Text</h1>').to have_selector('//h1')
201
+ end
202
+
203
+ it 'fails if has_selector? returns false' do
204
+ expect do
205
+ expect('<h1>Text</h1>').to have_selector('//h2')
206
+ end.to raise_error(%r{expected to find xpath "//h2" but there were no matches})
207
+ end
208
+ end
209
+
210
+ context 'with should_not' do
211
+ it 'passes if has_no_selector? returns true' do
212
+ expect('<h1>Text</h1>').not_to have_selector(:css, 'h2')
213
+ end
214
+
215
+ it 'fails if has_no_selector? returns false' do
216
+ expect do
217
+ expect('<h1>Text</h1>').not_to have_selector(:css, 'h1')
218
+ end.to raise_error(/expected not to find visible css "h1"/)
219
+ end
220
+ end
221
+ end
222
+
223
+ context 'on a page or node' do
224
+ before do
225
+ session.visit('/with_html')
226
+ end
227
+
228
+ context 'with should' do
229
+ it 'passes if has_selector? returns true' do
230
+ expect(session).to have_selector('//h1', text: 'test')
231
+ end
232
+
233
+ it 'fails if has_selector? returns false' do
234
+ expect do
235
+ expect(session).to have_selector("//h1[@id='doesnotexist']")
236
+ end.to raise_error(%r{expected to find xpath "//h1\[@id='doesnotexist'\]" but there were no matches})
237
+ end
238
+
239
+ it 'includes text in error message' do
240
+ expect do
241
+ expect(session).to have_selector('//h1', text: 'wrong text')
242
+ end.to raise_error(%r{expected to find visible xpath "//h1" with text "wrong text" but there were no matches})
243
+ end
244
+ end
245
+
246
+ context 'with should_not' do
247
+ it 'passes if has_no_css? returns true' do
248
+ expect(session).not_to have_selector(:css, 'h1#doesnotexist')
249
+ end
250
+
251
+ it 'fails if has_no_selector? returns false' do
252
+ expect do
253
+ expect(session).not_to have_selector(:css, 'h1', text: 'test')
254
+ end.to raise_error(/expected not to find visible css "h1" with text "test"/)
255
+ end
256
+ end
257
+ end
258
+
259
+ it 'supports compounding' do
260
+ expect('<h1>Text</h1><h2>Text</h2>').to have_selector('//h1').and have_selector('//h2')
261
+ expect('<h1>Text</h1><h2>Text</h2>').to have_selector('//h3').or have_selector('//h1')
262
+ expect('<h1>Text</h1><h2>Text</h2>').to have_no_selector('//h3').and have_selector('//h1')
263
+ end
264
+ end
265
+
266
+ describe 'have_content matcher' do
267
+ it 'gives proper description' do
268
+ expect(have_content('Text').description).to eq('have text "Text"')
269
+ end
270
+
271
+ context 'on a string' do
272
+ context 'with should' do
273
+ it 'passes if has_content? returns true' do
274
+ expect('<h1>Text</h1>').to have_content('Text')
275
+ end
276
+
277
+ it 'passes if has_content? returns true using regexp' do
278
+ expect('<h1>Text</h1>').to have_content(/ext/)
279
+ end
280
+
281
+ it 'fails if has_content? returns false' do
282
+ expect do
283
+ expect('<h1>Text</h1>').to have_content('No such Text')
284
+ end.to raise_error(/expected to find text "No such Text" in "Text"/)
285
+ end
286
+ end
287
+
288
+ context 'with should_not' do
289
+ it 'passes if has_no_content? returns true' do
290
+ expect('<h1>Text</h1>').not_to have_content('No such Text')
291
+ end
292
+
293
+ it 'passes because escapes any characters that would have special meaning in a regexp' do
294
+ expect('<h1>Text</h1>').not_to have_content('.')
295
+ end
296
+
297
+ it 'fails if has_no_content? returns false' do
298
+ expect do
299
+ expect('<h1>Text</h1>').not_to have_content('Text')
300
+ end.to raise_error(/expected not to find text "Text" in "Text"/)
301
+ end
302
+ end
303
+ end
304
+
305
+ context 'on a page or node' do
306
+ before do
307
+ session.visit('/with_html')
308
+ end
309
+
310
+ context 'with should' do
311
+ it 'passes if has_content? returns true' do
312
+ expect(session).to have_content('This is a test')
313
+ end
314
+
315
+ it 'passes if has_content? returns true using regexp' do
316
+ expect(session).to have_content(/test/)
317
+ end
318
+
319
+ it 'fails if has_content? returns false' do
320
+ expect do
321
+ expect(session).to have_content('No such Text')
322
+ end.to raise_error(/expected to find text "No such Text" in "(.*)This is a test(.*)"/)
323
+ end
324
+
325
+ context 'with default selector CSS' do
326
+ before { Capybara.default_selector = :css }
327
+
328
+ after { Capybara.default_selector = :xpath }
329
+
330
+ it 'fails if has_content? returns false' do
331
+ expect do
332
+ expect(session).to have_content('No such Text')
333
+ end.to raise_error(/expected to find text "No such Text" in "(.*)This is a test(.*)"/)
334
+ end
335
+ end
336
+ end
337
+
338
+ context 'with should_not' do
339
+ it 'passes if has_no_content? returns true' do
340
+ expect(session).not_to have_content('No such Text')
341
+ end
342
+
343
+ it 'fails if has_no_content? returns false' do
344
+ expect do
345
+ expect(session).not_to have_content('This is a test')
346
+ end.to raise_error(/expected not to find text "This is a test"/)
347
+ end
348
+
349
+ it 'not_to have_content behaves the same as to have_no_content' do
350
+ Capybara.using_wait_time(5) do
351
+ expect(session).to have_content('This is a test')
352
+ start = Time.now
353
+ expect(session).to have_no_content('No such Text')
354
+ to_time = Time.now
355
+ expect(session).not_to have_content('No such Text')
356
+ not_to_time = Time.now
357
+ expect(not_to_time - to_time).to be_within(0.5).of(to_time - start)
358
+ end
359
+ end
360
+ end
361
+ end
362
+
363
+ it 'supports compounding' do
364
+ expect('<h1>Text</h1><h2>And</h2>').to have_content('Text').and have_content('And')
365
+ expect('<h1>Text</h1><h2>Or</h2>').to have_content('XYZ').or have_content('Or')
366
+ expect('<h1>Text</h1><h2>Or</h2>').to have_no_content('XYZ').and have_content('Or')
367
+ end
368
+ end
369
+
370
+ describe 'have_text matcher' do
371
+ it 'gives proper description' do
372
+ expect(have_text('Text').description).to eq('have text "Text"')
373
+ end
374
+
375
+ context 'on a string' do
376
+ context 'with should' do
377
+ it 'passes if text contains given string' do
378
+ expect('<h1>Text</h1>').to have_text('Text')
379
+ end
380
+
381
+ it 'passes if text matches given regexp' do
382
+ expect('<h1>Text</h1>').to have_text(/ext/)
383
+ end
384
+
385
+ it "fails if text doesn't contain given string" do
386
+ expect do
387
+ expect('<h1>Text</h1>').to have_text('No such Text')
388
+ end.to raise_error(/expected to find text "No such Text" in "Text"/)
389
+ end
390
+
391
+ it "fails if text doesn't match given regexp" do
392
+ expect do
393
+ expect('<h1>Text</h1>').to have_text(/No such Text/)
394
+ end.to raise_error('expected to find text matching /No such Text/ in "Text"')
395
+ end
396
+
397
+ it 'casts Integer to string' do
398
+ expect do
399
+ expect('<h1>Text</h1>').to have_text(3)
400
+ end.to raise_error(/expected to find text "3" in "Text"/)
401
+ end
402
+
403
+ it 'fails if matched text count does not equal to expected count' do
404
+ expect do
405
+ expect('<h1>Text</h1>').to have_text('Text', count: 2)
406
+ end.to raise_error('expected to find text "Text" 2 times but found 1 time in "Text"')
407
+ end
408
+
409
+ it 'fails if matched text count is less than expected minimum count' do
410
+ expect do
411
+ expect('<h1>Text</h1>').to have_text('Lorem', minimum: 1)
412
+ end.to raise_error('expected to find text "Lorem" at least 1 time but found 0 times in "Text"')
413
+ end
414
+
415
+ it 'fails if matched text count is more than expected maximum count' do
416
+ expect do
417
+ expect('<h1>Text TextText</h1>').to have_text('Text', maximum: 2)
418
+ end.to raise_error('expected to find text "Text" at most 2 times but found 3 times in "Text TextText"')
419
+ end
420
+
421
+ it 'fails if matched text count does not belong to expected range' do
422
+ expect do
423
+ expect('<h1>Text</h1>').to have_text('Text', between: 2..3)
424
+ end.to raise_error('expected to find text "Text" between 2 and 3 times but found 1 time in "Text"')
425
+ end
426
+ end
427
+
428
+ context 'with should_not' do
429
+ it "passes if text doesn't contain a string" do
430
+ expect('<h1>Text</h1>').not_to have_text('No such Text')
431
+ end
432
+
433
+ it 'passes because escapes any characters that would have special meaning in a regexp' do
434
+ expect('<h1>Text</h1>').not_to have_text('.')
435
+ end
436
+
437
+ it 'fails if text contains a string' do
438
+ expect do
439
+ expect('<h1>Text</h1>').not_to have_text('Text')
440
+ end.to raise_error(/expected not to find text "Text" in "Text"/)
441
+ end
442
+ end
443
+ end
444
+
445
+ context 'on a page or node' do
446
+ before do
447
+ session.visit('/with_html')
448
+ end
449
+
450
+ context 'with should' do
451
+ it 'passes if has_text? returns true' do
452
+ expect(session).to have_text('This is a test')
453
+ end
454
+
455
+ it 'passes if has_text? returns true using regexp' do
456
+ expect(session).to have_text(/test/)
457
+ end
458
+
459
+ it 'can check for all text' do
460
+ expect(session).to have_text(:all, 'Some of this text is hidden!')
461
+ end
462
+
463
+ it 'can check for visible text' do
464
+ expect(session).to have_text(:visible, 'Some of this text is')
465
+ expect(session).not_to have_text(:visible, 'Some of this text is hidden!')
466
+ end
467
+
468
+ it 'fails if has_text? returns false' do
469
+ expect do
470
+ expect(session).to have_text('No such Text')
471
+ end.to raise_error(/expected to find text "No such Text" in "(.*)This is a test(.*)"/)
472
+ end
473
+
474
+ context 'with default selector CSS' do
475
+ before { Capybara.default_selector = :css }
476
+
477
+ after { Capybara.default_selector = :xpath }
478
+
479
+ it 'fails if has_text? returns false' do
480
+ expect do
481
+ expect(session).to have_text('No such Text')
482
+ end.to raise_error(/expected to find text "No such Text" in "(.*)This is a test(.*)"/)
483
+ end
484
+ end
485
+ end
486
+
487
+ context 'with should_not' do
488
+ it 'passes if has_no_text? returns true' do
489
+ expect(session).not_to have_text('No such Text')
490
+ end
491
+
492
+ it 'fails if has_no_text? returns false' do
493
+ expect do
494
+ expect(session).not_to have_text('This is a test')
495
+ end.to raise_error(/expected not to find text "This is a test"/)
496
+ end
497
+ end
498
+ end
499
+
500
+ it 'supports compounding' do
501
+ expect('<h1>Text</h1><h2>And</h2>').to have_text('Text').and have_text('And')
502
+ expect('<h1>Text</h1><h2>Or</h2>').to have_text('Not here').or have_text('Or')
503
+ end
504
+ end
505
+
506
+ describe 'have_link matcher' do
507
+ let(:html) { '<a href="#">Just a link</a><a href="#">Another link</a>' }
508
+
509
+ it 'gives proper description' do
510
+ expect(have_link('Just a link').description).to eq('have visible link "Just a link"')
511
+ end
512
+
513
+ it 'passes if there is such a link' do
514
+ expect(html).to have_link('Just a link')
515
+ end
516
+
517
+ it 'fails if there is no such link' do
518
+ expect do
519
+ expect(html).to have_link('No such Link')
520
+ end.to raise_error(/expected to find link "No such Link"/)
521
+ end
522
+
523
+ it 'supports compounding' do
524
+ expect(html).to have_link('Just a link').and have_link('Another link')
525
+ expect(html).to have_link('Not a link').or have_link('Another link')
526
+ expect(html).to have_no_link('Not a link').and have_link('Another link')
527
+ end
528
+ end
529
+
530
+ describe 'have_title matcher' do
531
+ it 'gives proper description' do
532
+ expect(have_title('Just a title').description).to eq('have title "Just a title"')
533
+ end
534
+
535
+ context 'on a string' do
536
+ let(:html) { '<title>Just a title</title>' }
537
+
538
+ it 'passes if there is such a title' do
539
+ expect(html).to have_title('Just a title')
540
+ end
541
+
542
+ it 'fails if there is no such title' do
543
+ expect do
544
+ expect(html).to have_title('No such title')
545
+ end.to raise_error('expected "Just a title" to include "No such title"')
546
+ end
547
+
548
+ it "fails if title doesn't match regexp" do
549
+ expect do
550
+ expect(html).to have_title(/[[:upper:]]+[[:lower:]]+l{2}o/)
551
+ end.to raise_error('expected "Just a title" to match /[[:upper:]]+[[:lower:]]+l{2}o/')
552
+ end
553
+ end
554
+
555
+ context 'on a page or node' do
556
+ it 'passes if there is such a title' do
557
+ session.visit('/with_js')
558
+ expect(session).to have_title('with_js')
559
+ end
560
+
561
+ it 'fails if there is no such title' do
562
+ session.visit('/with_js')
563
+ expect do
564
+ expect(session).to have_title('No such title')
565
+ end.to raise_error(/ to include "No such title"/)
566
+ end
567
+
568
+ context 'with wait' do
569
+ before do
570
+ session.visit('/with_js')
571
+ end
572
+
573
+ it 'waits if wait time is more than timeout' do
574
+ session.click_link('Change title')
575
+ session.using_wait_time 0 do
576
+ expect(session).to have_title('changed title', wait: 2)
577
+ end
578
+ end
579
+
580
+ it "doesn't wait if wait time is less than timeout" do
581
+ session.click_link('Change title')
582
+ session.using_wait_time 3 do
583
+ expect(session).not_to have_title('changed title', wait: 0)
584
+ end
585
+ end
586
+ end
587
+ end
588
+
589
+ it 'supports compounding' do
590
+ expect('<title>I compound</title>').to have_title('I dont compound').or have_title('I compound')
591
+ end
592
+ end
593
+
594
+ describe 'have_current_path matcher' do
595
+ it 'gives proper description' do
596
+ expect(have_current_path('http://www.example.com').description).to eq('have current path "http://www.example.com"')
597
+ end
598
+
599
+ context 'on a page or node' do
600
+ it 'passes if there is such a current path' do
601
+ session.visit('/with_js')
602
+ expect(session).to have_current_path('/with_js')
603
+ end
604
+
605
+ it 'fails if there is no such current_path' do
606
+ visit('/with_js')
607
+ expect do
608
+ expect(session).to have_current_path('/not_with_js')
609
+ end.to raise_error(%r{to equal "/not_with_js"})
610
+ end
611
+
612
+ context 'with wait' do
613
+ before do
614
+ session.visit('/with_js')
615
+ end
616
+
617
+ it 'waits if wait time is more than timeout' do
618
+ session.click_link('Change page')
619
+ session.using_wait_time 0 do
620
+ expect(session).to have_current_path('/with_html', wait: 2)
621
+ end
622
+ end
623
+
624
+ it "doesn't wait if wait time is less than timeout" do
625
+ session.click_link('Change page')
626
+ session.using_wait_time 0 do
627
+ expect(session).not_to have_current_path('/with_html')
628
+ end
629
+ end
630
+ end
631
+ end
632
+
633
+ it 'supports compounding' do
634
+ session.visit('/with_html')
635
+ expect(session).to have_current_path('/not_with_html').or have_current_path('/with_html')
636
+ end
637
+ end
638
+
639
+ describe 'have_button matcher' do
640
+ let(:html) { '<button>A button</button><input type="submit" value="Another button"/>' }
641
+
642
+ it 'gives proper description with no options' do
643
+ expect(have_button('A button').description).to eq('have visible button "A button" that is not disabled')
644
+ end
645
+
646
+ it 'gives proper description with disabled :any option' do
647
+ expect(have_button('A button', disabled: :all).description).to eq('have visible button "A button"')
648
+ end
649
+
650
+ it 'passes if there is such a button' do
651
+ expect(html).to have_button('A button')
652
+ end
653
+
654
+ it 'fails if there is no such button' do
655
+ expect do
656
+ expect(html).to have_button('No such Button')
657
+ end.to raise_error(/expected to find button "No such Button"/)
658
+ end
659
+
660
+ it 'supports compounding' do
661
+ expect(html).to have_button('Not this button').or have_button('A button')
662
+ end
663
+ end
664
+
665
+ describe 'have_field matcher' do
666
+ let(:html) { '<p><label>Text field<input type="text" value="some value"/></label></p>' }
667
+
668
+ it 'gives proper description' do
669
+ expect(have_field('Text field').description).to eq('have visible field "Text field" that is not disabled')
670
+ end
671
+
672
+ it 'gives proper description for a given value' do
673
+ expect(have_field('Text field', with: 'some value').description).to eq('have visible field "Text field" that is not disabled with value "some value"')
674
+ end
675
+
676
+ it 'passes if there is such a field' do
677
+ expect(html).to have_field('Text field')
678
+ end
679
+
680
+ it 'passes if there is such a field with value' do
681
+ expect(html).to have_field('Text field', with: 'some value')
682
+ end
683
+
684
+ it 'fails if there is no such field' do
685
+ expect do
686
+ expect(html).to have_field('No such Field')
687
+ end.to raise_error(/expected to find field "No such Field"/)
688
+ end
689
+
690
+ it 'fails if there is such field but with false value' do
691
+ expect do
692
+ expect(html).to have_field('Text field', with: 'false value')
693
+ end.to raise_error(/expected to find visible field "Text field"/)
694
+ end
695
+
696
+ it 'treats a given value as a string' do
697
+ foo = Class.new do
698
+ def to_s
699
+ 'some value'
700
+ end
701
+ end
702
+ expect(html).to have_field('Text field', with: foo.new)
703
+ end
704
+
705
+ it 'supports compounding' do
706
+ expect(html).to have_field('Not this one').or have_field('Text field')
707
+ end
708
+ end
709
+
710
+ describe 'have_checked_field matcher' do
711
+ let(:html) do
712
+ '<label>it is checked<input type="checkbox" checked="checked"/></label>
713
+ <label>unchecked field<input type="checkbox"/></label>'
714
+ end
715
+
716
+ it 'gives proper description' do
717
+ expect(have_checked_field('it is checked').description).to eq('have visible field "it is checked" that is not disabled that is checked')
718
+ end
719
+
720
+ context 'with should' do
721
+ it 'passes if there is such a field and it is checked' do
722
+ expect(html).to have_checked_field('it is checked')
723
+ end
724
+
725
+ it 'fails if there is such a field but it is not checked' do
726
+ expect do
727
+ expect(html).to have_checked_field('unchecked field')
728
+ end.to raise_error(/expected to find visible field "unchecked field"/)
729
+ end
730
+
731
+ it 'fails if there is no such field' do
732
+ expect do
733
+ expect(html).to have_checked_field('no such field')
734
+ end.to raise_error(/expected to find field "no such field"/)
735
+ end
736
+ end
737
+
738
+ context 'with should not' do
739
+ it 'fails if there is such a field and it is checked' do
740
+ expect do
741
+ expect(html).not_to have_checked_field('it is checked')
742
+ end.to raise_error(/expected not to find visible field "it is checked"/)
743
+ end
744
+
745
+ it 'passes if there is such a field but it is not checked' do
746
+ expect(html).not_to have_checked_field('unchecked field')
747
+ end
748
+
749
+ it 'passes if there is no such field' do
750
+ expect(html).not_to have_checked_field('no such field')
751
+ end
752
+ end
753
+
754
+ it 'supports compounding' do
755
+ expect(html).to have_checked_field('not this one').or have_checked_field('it is checked')
756
+ end
757
+ end
758
+
759
+ describe 'have_unchecked_field matcher' do
760
+ let(:html) do
761
+ '<label>it is checked<input type="checkbox" checked="checked"/></label>
762
+ <label>unchecked field<input type="checkbox"/></label>'
763
+ end
764
+
765
+ it 'gives proper description' do
766
+ expect(have_unchecked_field('unchecked field').description).to eq('have visible field "unchecked field" that is not disabled that is not checked')
767
+ end
768
+
769
+ context 'with should' do
770
+ it 'passes if there is such a field and it is not checked' do
771
+ expect(html).to have_unchecked_field('unchecked field')
772
+ end
773
+
774
+ it 'fails if there is such a field but it is checked' do
775
+ expect do
776
+ expect(html).to have_unchecked_field('it is checked')
777
+ end.to raise_error(/expected to find visible field "it is checked"/)
778
+ end
779
+
780
+ it 'fails if there is no such field' do
781
+ expect do
782
+ expect(html).to have_unchecked_field('no such field')
783
+ end.to raise_error(/expected to find field "no such field"/)
784
+ end
785
+ end
786
+
787
+ context 'with should not' do
788
+ it 'fails if there is such a field and it is not checked' do
789
+ expect do
790
+ expect(html).not_to have_unchecked_field('unchecked field')
791
+ end.to raise_error(/expected not to find visible field "unchecked field"/)
792
+ end
793
+
794
+ it 'passes if there is such a field but it is checked' do
795
+ expect(html).not_to have_unchecked_field('it is checked')
796
+ end
797
+
798
+ it 'passes if there is no such field' do
799
+ expect(html).not_to have_unchecked_field('no such field')
800
+ end
801
+ end
802
+
803
+ it 'supports compounding' do
804
+ expect(html).to have_unchecked_field('it is checked').or have_unchecked_field('unchecked field')
805
+ end
806
+ end
807
+
808
+ describe 'have_select matcher' do
809
+ let(:html) { '<label>Select Box<select></select></label>' }
810
+
811
+ it 'gives proper description' do
812
+ expect(have_select('Select Box').description).to eq('have visible select box "Select Box" that is not disabled')
813
+ end
814
+
815
+ it 'gives proper description for a given selected value' do
816
+ expect(have_select('Select Box', selected: 'some value').description).to eq('have visible select box "Select Box" that is not disabled with "some value" selected')
817
+ end
818
+
819
+ it 'passes if there is such a select' do
820
+ expect(html).to have_select('Select Box')
821
+ end
822
+
823
+ it 'fails if there is no such select' do
824
+ expect do
825
+ expect(html).to have_select('No such Select box')
826
+ end.to raise_error(/expected to find select box "No such Select box"/)
827
+ end
828
+
829
+ it 'supports compounding' do
830
+ expect(html).to have_select('Not this one').or have_select('Select Box')
831
+ end
832
+ end
833
+
834
+ describe 'have_table matcher' do
835
+ let(:html) { '<table><caption>Lovely table</caption></table>' }
836
+
837
+ it 'gives proper description' do
838
+ expect(have_table('Lovely table').description).to eq('have visible table "Lovely table"')
839
+ expect(have_table('Lovely table', caption: 'my caption').description).to eq('have visible table "Lovely table" with caption "my caption"')
840
+ end
841
+
842
+ it 'gives proper description when :visible option passed' do
843
+ expect(have_table('Lovely table', visible: true).description).to eq('have visible table "Lovely table"')
844
+ expect(have_table('Lovely table', visible: :hidden).description).to eq('have non-visible table "Lovely table"')
845
+ expect(have_table('Lovely table', visible: :all).description).to eq('have table "Lovely table"')
846
+ expect(have_table('Lovely table', visible: false).description).to eq('have table "Lovely table"')
847
+ end
848
+
849
+ it 'passes if there is such a table' do
850
+ expect(html).to have_table('Lovely table')
851
+ end
852
+
853
+ it 'fails if there is no such table' do
854
+ expect do
855
+ expect(html).to have_table('No such Table')
856
+ end.to raise_error(/expected to find table "No such Table"/)
857
+ end
858
+
859
+ it 'supports compounding' do
860
+ expect(html).to have_table('nope').or have_table('Lovely table')
861
+ end
862
+ end
863
+
864
+ context 'compounding timing' do
865
+ let(:session) { session }
866
+ let(:el) { session.find(:css, '#reload-me') }
867
+
868
+ before do
869
+ session.visit('/with_js')
870
+ end
871
+
872
+ describe '#and' do
873
+ it "should run 'concurrently'" do
874
+ session.using_wait_time(2) do
875
+ matcher = have_text('this is not there').and have_text('neither is this')
876
+ expect(Benchmark.realtime do
877
+ expect do
878
+ expect(el).to matcher
879
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
880
+ end).to be_between(2, 3)
881
+ end
882
+ end
883
+
884
+ it "should run 'concurrently' and retry" do
885
+ session.click_link('reload-link')
886
+ session.using_wait_time(2) do
887
+ expect(Benchmark.realtime do
888
+ expect do
889
+ expect(el).to have_text('waiting to be reloaded').and(have_text('has been reloaded'))
890
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError, /expected to find text "waiting to be reloaded" in "has been reloaded"/
891
+ end).to be_between(2, 3)
892
+ end
893
+ end
894
+
895
+ it 'should ignore :wait options' do
896
+ session.using_wait_time(2) do
897
+ matcher = have_text('this is not there', wait: 5).and have_text('neither is this', wait: 6)
898
+ expect(Benchmark.realtime do
899
+ expect do
900
+ expect(el).to matcher
901
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
902
+ end).to be_between(2, 3)
903
+ end
904
+ end
905
+
906
+ it 'should work on the session' do
907
+ session.using_wait_time(2) do
908
+ session.click_link('reload-link')
909
+ expect(session).to have_selector(:css, 'h1', text: 'FooBar').and have_text('has been reloaded')
910
+ end
911
+ end
912
+ end
913
+
914
+ describe '#and_then' do
915
+ it 'should run sequentially' do
916
+ session.click_link('reload-link')
917
+ expect(el).to have_text('waiting to be reloaded').and_then have_text('has been reloaded')
918
+ end
919
+ end
920
+
921
+ describe '#or' do
922
+ it "should run 'concurrently'" do
923
+ session.using_wait_time(3) do
924
+ expect(Benchmark.realtime do
925
+ expect(el).to have_text('has been reloaded').or have_text('waiting to be reloaded')
926
+ end).to be < 1
927
+ end
928
+ end
929
+
930
+ it 'should retry' do
931
+ session.using_wait_time(3) do
932
+ expect(Benchmark.realtime do
933
+ expect do
934
+ expect(el).to have_text('has been reloaded').or have_text('random stuff')
935
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
936
+ end).to be > 3
937
+ end
938
+ end
939
+
940
+ it 'should ignore :wait options' do
941
+ session.using_wait_time(2) do
942
+ expect(Benchmark.realtime do
943
+ expect do
944
+ expect(el).to have_text('this is not there', wait: 10).or have_text('neither is this', wait: 15)
945
+ end.to raise_error RSpec::Expectations::ExpectationNotMetError
946
+ end).to be_between(2, 3)
947
+ end
948
+ end
949
+
950
+ it 'should work on the session' do
951
+ session.using_wait_time(2) do
952
+ session.click_link('reload-link')
953
+ expect(session).to have_selector(:css, 'h1', text: 'Not on the page').or have_text('has been reloaded')
954
+ end
955
+ end
956
+ end
957
+ end
958
+ end
959
+ # rubocop:enable RSpec/ExpectActual