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,34 +1,58 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  Capybara::SpecHelper.spec '#within' do
3
4
  before do
4
5
  @session.visit('/with_scope')
5
6
  end
6
7
 
7
- context "with CSS selector" do
8
- it "should click links in the given scope" do
9
- @session.within(:css, "#for_bar li", text: 'With Simple HTML') do
8
+ context 'with CSS selector' do
9
+ it 'should click links in the given scope' do
10
+ @session.within(:css, '#for_bar li:first-child') do
10
11
  @session.click_link('Go')
11
12
  end
12
13
  expect(@session).to have_content('Bar')
13
14
  end
14
15
 
15
- it "should assert content in the given scope" do
16
- @session.within(:css, "#for_foo") do
16
+ it 'should assert content in the given scope' do
17
+ @session.within(:css, '#for_foo') do
17
18
  expect(@session).not_to have_content('First Name')
18
19
  end
19
20
  expect(@session).to have_content('First Name')
20
21
  end
21
22
 
22
- it "should accept additional options" do
23
- @session.within(:css, "#for_bar li", :text => 'With Simple HTML') do
23
+ it 'should accept additional options' do
24
+ @session.within(:css, '#for_bar li', text: 'With Simple HTML') do
24
25
  @session.click_link('Go')
25
26
  end
26
27
  expect(@session).to have_content('Bar')
27
28
  end
29
+
30
+ it 'should reload the node if the page is changed' do
31
+ @session.within(:css, '#for_foo') do
32
+ @session.visit('/with_scope_other')
33
+ expect(@session).to have_content('Different text')
34
+ end
35
+ end
36
+
37
+ it 'should reload multiple nodes if the page is changed' do
38
+ @session.within(:css, '#for_bar') do
39
+ @session.within(:css, 'form[action="/redirect"]') do
40
+ @session.refresh
41
+ expect(@session).to have_content('First Name')
42
+ end
43
+ end
44
+ end
45
+
46
+ it 'should error if the page is changed and a matching node no longer exists' do
47
+ @session.within(:css, '#for_foo') do
48
+ @session.visit('/')
49
+ expect { @session.text }.to raise_error(StandardError)
50
+ end
51
+ end
28
52
  end
29
53
 
30
- context "with XPath selector" do
31
- it "should click links in the given scope" do
54
+ context 'with XPath selector' do
55
+ it 'should click links in the given scope' do
32
56
  @session.within(:xpath, "//div[@id='for_bar']//li[contains(.,'With Simple HTML')]") do
33
57
  @session.click_link('Go')
34
58
  end
@@ -36,8 +60,8 @@ Capybara::SpecHelper.spec '#within' do
36
60
  end
37
61
  end
38
62
 
39
- context "with the default selector" do
40
- it "should use XPath" do
63
+ context 'with the default selector' do
64
+ it 'should use XPath' do
41
65
  @session.within("//div[@id='for_bar']//li[contains(.,'With Simple HTML')]") do
42
66
  @session.click_link('Go')
43
67
  end
@@ -45,9 +69,9 @@ Capybara::SpecHelper.spec '#within' do
45
69
  end
46
70
  end
47
71
 
48
- context "with Node rather than selector" do
49
- it "should click links in the given scope" do
50
- node_of_interest = @session.find(:css, "#for_bar li", text: 'With Simple HTML')
72
+ context 'with Node rather than selector' do
73
+ it 'should click links in the given scope' do
74
+ node_of_interest = @session.find(:css, '#for_bar li', text: 'With Simple HTML')
51
75
 
52
76
  @session.within(node_of_interest) do
53
77
  @session.click_link('Go')
@@ -56,19 +80,21 @@ Capybara::SpecHelper.spec '#within' do
56
80
  end
57
81
  end
58
82
 
59
- context "with the default selector set to CSS" do
83
+ context 'with the default selector set to CSS' do
60
84
  before { Capybara.default_selector = :css }
61
- it "should use CSS" do
62
- @session.within("#for_bar li", text: 'With Simple HTML') do
85
+
86
+ after { Capybara.default_selector = :xpath }
87
+
88
+ it 'should use CSS' do
89
+ @session.within('#for_bar li', text: 'With Simple HTML') do
63
90
  @session.click_link('Go')
64
91
  end
65
92
  expect(@session).to have_content('Bar')
66
93
  end
67
- after { Capybara.default_selector = :xpath }
68
94
  end
69
95
 
70
- context "with nested scopes" do
71
- it "should respect the inner scope" do
96
+ context 'with nested scopes' do
97
+ it 'should respect the inner scope' do
72
98
  @session.within("//div[@id='for_bar']") do
73
99
  @session.within(".//li[contains(.,'Bar')]") do
74
100
  @session.click_link('Go')
@@ -77,7 +103,7 @@ Capybara::SpecHelper.spec '#within' do
77
103
  expect(@session).to have_content('Another World')
78
104
  end
79
105
 
80
- it "should respect the outer scope" do
106
+ it 'should respect the outer scope' do
81
107
  @session.within("//div[@id='another_foo']") do
82
108
  @session.within(".//li[contains(.,'With Simple HTML')]") do
83
109
  @session.click_link('Go')
@@ -87,14 +113,14 @@ Capybara::SpecHelper.spec '#within' do
87
113
  end
88
114
  end
89
115
 
90
- it "should raise an error if the scope is not found on the page" do
116
+ it 'should raise an error if the scope is not found on the page' do
91
117
  expect do
92
118
  @session.within("//div[@id='doesnotexist']") do
93
119
  end
94
120
  end.to raise_error(Capybara::ElementNotFound)
95
121
  end
96
122
 
97
- it "should restore the scope when an error is raised" do
123
+ it 'should restore the scope when an error is raised' do
98
124
  expect do
99
125
  @session.within("//div[@id='for_bar']") do
100
126
  expect do
@@ -102,23 +128,30 @@ Capybara::SpecHelper.spec '#within' do
102
128
  @session.within(".//div[@id='doesnotexist']") do
103
129
  end
104
130
  end.to raise_error(Capybara::ElementNotFound)
105
- end.to_not change { @session.has_xpath?(".//div[@id='another_foo']") }.from(false)
131
+ end.not_to change { @session.has_xpath?(".//div[@id='another_foo']") }.from(false)
106
132
  end
107
- end.to_not change { @session.has_xpath?(".//div[@id='another_foo']") }.from(true)
133
+ end.not_to change { @session.has_xpath?(".//div[@id='another_foo']") }.from(true)
108
134
  end
109
135
 
110
- it "should fill in a field and click a button" do
136
+ it 'should fill in a field and click a button' do
111
137
  @session.within("//li[contains(.,'Bar')]") do
112
138
  @session.click_button('Go')
113
139
  end
114
140
  expect(extract_results(@session)['first_name']).to eq('Peter')
115
141
  @session.visit('/with_scope')
116
142
  @session.within("//li[contains(.,'Bar')]") do
117
- @session.fill_in('First Name', :with => 'Dagobert')
143
+ @session.fill_in('First Name', with: 'Dagobert')
118
144
  @session.click_button('Go')
119
145
  end
120
146
  expect(extract_results(@session)['first_name']).to eq('Dagobert')
121
147
  end
148
+
149
+ it 'should have #within_element as an alias' do
150
+ expect(Capybara::Session.instance_method(:within)).to eq Capybara::Session.instance_method(:within_element)
151
+ @session.within_element(:css, '#for_foo') do
152
+ expect(@session).not_to have_content('First Name')
153
+ end
154
+ end
122
155
  end
123
156
 
124
157
  Capybara::SpecHelper.spec '#within_fieldset' do
@@ -126,18 +159,18 @@ Capybara::SpecHelper.spec '#within_fieldset' do
126
159
  @session.visit('/fieldsets')
127
160
  end
128
161
 
129
- it "should restrict scope to a fieldset given by id" do
130
- @session.within_fieldset("villain_fieldset") do
131
- @session.fill_in("Name", :with => 'Goldfinger')
132
- @session.click_button("Create")
162
+ it 'should restrict scope to a fieldset given by id' do
163
+ @session.within_fieldset('villain_fieldset') do
164
+ @session.fill_in('Name', with: 'Goldfinger')
165
+ @session.click_button('Create')
133
166
  end
134
167
  expect(extract_results(@session)['villain_name']).to eq('Goldfinger')
135
168
  end
136
169
 
137
- it "should restrict scope to a fieldset given by legend" do
138
- @session.within_fieldset("Villain") do
139
- @session.fill_in("Name", :with => 'Goldfinger')
140
- @session.click_button("Create")
170
+ it 'should restrict scope to a fieldset given by legend' do
171
+ @session.within_fieldset('Villain') do
172
+ @session.fill_in('Name', with: 'Goldfinger')
173
+ @session.click_button('Create')
141
174
  end
142
175
  expect(extract_results(@session)['villain_name']).to eq('Goldfinger')
143
176
  end
@@ -148,18 +181,18 @@ Capybara::SpecHelper.spec '#within_table' do
148
181
  @session.visit('/tables')
149
182
  end
150
183
 
151
- it "should restrict scope to a fieldset given by id" do
152
- @session.within_table("girl_table") do
153
- @session.fill_in("Name", :with => 'Christmas')
154
- @session.click_button("Create")
184
+ it 'should restrict scope to a fieldset given by id' do
185
+ @session.within_table('girl_table') do
186
+ @session.fill_in('Name', with: 'Christmas')
187
+ @session.click_button('Create')
155
188
  end
156
189
  expect(extract_results(@session)['girl_name']).to eq('Christmas')
157
190
  end
158
191
 
159
- it "should restrict scope to a fieldset given by legend" do
160
- @session.within_table("Villain") do
161
- @session.fill_in("Name", :with => 'Quantum')
162
- @session.click_button("Create")
192
+ it 'should restrict scope to a fieldset given by legend' do
193
+ @session.within_table('Villain') do
194
+ @session.fill_in('Name', with: 'Quantum')
195
+ @session.click_button('Create')
163
196
  end
164
197
  expect(extract_results(@session)['villain_name']).to eq('Quantum')
165
198
  end
@@ -1,27 +1,22 @@
1
1
  # frozen_string_literal: true
2
- require "rspec"
3
- require "rspec/expectations"
4
- require "capybara"
5
- require "capybara/rspec" # Required here instead of in rspec_spec to avoid RSpec deprecation warning
6
- require "capybara/spec/test_app"
7
- require "nokogiri"
8
-
9
- # Alias be_truthy/be_falsey if not already defined to be able to use in RSpec 2 and 3
10
- unless RSpec::Matchers.method_defined?(:be_truthy)
11
- RSpec::Matchers.module_eval do
12
- alias be_truthy be_true
13
- alias be_falsey be_false
14
- alias be_falsy be_false
15
- end
16
- end
2
+
3
+ require 'rspec'
4
+ require 'rspec/expectations'
5
+ require 'capybara'
6
+ require 'capybara/rspec' # Required here instead of in rspec_spec to avoid RSpec deprecation warning
7
+ require 'capybara/spec/test_app'
8
+ require 'nokogiri'
9
+
10
+ Capybara.save_path = File.join(Dir.pwd, 'save_path_tmp')
17
11
 
18
12
  module Capybara
19
13
  module SpecHelper
20
14
  class << self
21
15
  def configure(config)
22
- config.filter_run_excluding :requires => method(:filter).to_proc
16
+ config.filter_run_excluding requires: method(:filter).to_proc
23
17
  config.before { Capybara::SpecHelper.reset! }
24
18
  config.after { Capybara::SpecHelper.reset! }
19
+ config.shared_context_metadata_behavior = :apply_to_host_groups
25
20
  end
26
21
 
27
22
  def reset!
@@ -31,15 +26,23 @@ module Capybara
31
26
  Capybara.default_max_wait_time = 1
32
27
  Capybara.ignore_hidden_elements = true
33
28
  Capybara.exact = false
34
- Capybara.exact_options = false
35
29
  Capybara.raise_server_errors = true
36
30
  Capybara.visible_text_only = false
37
31
  Capybara.match = :smart
38
- Capybara.wait_on_first_by_default = false
32
+ Capybara.enable_aria_label = false
33
+ Capybara.enable_aria_role = false
34
+ Capybara.default_set_options = {}
35
+ Capybara.disable_animation = false
36
+ Capybara.test_id = nil
37
+ Capybara.predicates_wait = true
38
+ Capybara.default_normalize_ws = false
39
+ Capybara.allow_gumbo = true
40
+ Capybara.w3c_click_offset = false
41
+ reset_threadsafe
39
42
  end
40
43
 
41
44
  def filter(requires, metadata)
42
- if requires and metadata[:capybara_skip]
45
+ if requires && metadata[:capybara_skip]
43
46
  requires.any? do |require|
44
47
  metadata[:capybara_skip].include?(require)
45
48
  end
@@ -48,53 +51,84 @@ module Capybara
48
51
  end
49
52
  end
50
53
 
51
- def spec(name, options={}, &block)
54
+ def spec(name, *options, &block)
52
55
  @specs ||= []
53
56
  @specs << [name, options, block]
54
57
  end
55
58
 
56
- def run_specs(session, name, options={})
59
+ def run_specs(session, name, **options, &filter_block)
57
60
  specs = @specs
58
61
  RSpec.describe Capybara::Session, name, options do
59
62
  include Capybara::SpecHelper
60
63
  include Capybara::RSpecMatchers
61
- before do
64
+
65
+ before do |example|
62
66
  @session = session
67
+ instance_exec(example, &filter_block) if filter_block
63
68
  end
69
+
64
70
  after do
65
- @session.reset_session!
71
+ session.reset_session!
66
72
  end
73
+
74
+ before :each, psc: true do
75
+ SpecHelper.reset_threadsafe(bool: true, session: session)
76
+ end
77
+
78
+ after psc: true do
79
+ SpecHelper.reset_threadsafe(session: session)
80
+ end
81
+
82
+ before :each, :exact_false do
83
+ Capybara.exact = false
84
+ end
85
+
67
86
  specs.each do |spec_name, spec_options, block|
68
- describe spec_name, spec_options do
87
+ describe spec_name, *spec_options do
69
88
  class_eval(&block)
70
89
  end
71
90
  end
72
91
  end
73
92
  end
74
- end # class << self
93
+
94
+ def reset_threadsafe(bool: false, session: nil)
95
+ # Work around limit on when threadsafe can be changed
96
+ Capybara::Session.class_variable_set(:@@instance_created, false) # rubocop:disable Style/ClassVars
97
+ Capybara.threadsafe = bool
98
+ session = session.current_session if session.respond_to?(:current_session)
99
+ session&.instance_variable_set(:@config, nil)
100
+ end
101
+ end
75
102
 
76
103
  def silence_stream(stream)
77
104
  old_stream = stream.dup
78
- stream.reopen(RbConfig::CONFIG['host_os'] =~ /rmswin|mingw/ ? 'NUL:' : '/dev/null')
105
+ stream.reopen(RbConfig::CONFIG['host_os'].match?(/rmswin|mingw/) ? 'NUL:' : '/dev/null')
79
106
  stream.sync = true
80
107
  yield
81
108
  ensure
82
109
  stream.reopen(old_stream)
83
110
  end
84
111
 
85
- def quietly
86
- silence_stream(STDOUT) do
87
- silence_stream(STDERR) do
88
- yield
89
- end
112
+ def quietly(&block)
113
+ silence_stream($stdout) do
114
+ silence_stream($stderr, &block)
90
115
  end
91
116
  end
92
117
 
93
118
  def extract_results(session)
94
119
  expect(session).to have_xpath("//pre[@id='results']")
95
- YAML.load Nokogiri::HTML(session.body).xpath("//pre[@id='results']").first.inner_html.lstrip
120
+ # YAML.load Nokogiri::HTML(session.body).xpath("//pre[@id='results']").first.inner_html.lstrip
121
+ YAML.load Capybara::HTML(session.body).xpath("//pre[@id='results']").first.inner_html.lstrip
122
+ end
123
+
124
+ def be_an_invalid_element_error(session)
125
+ satisfy { |error| session.driver.invalid_element_errors.any? { |e| error.is_a? e } }
126
+ end
127
+
128
+ def with_os_path_separators(path)
129
+ Gem.win_platform? ? path.to_s.tr('/', '\\') : path.to_s
96
130
  end
97
131
  end
98
132
  end
99
133
 
100
- Dir[File.dirname(__FILE__) + "/session/**/*.rb"].each { |file| require_relative file }
134
+ Dir["#{File.dirname(__FILE__)}/session/**/*.rb"].each { |file| require_relative file }
@@ -1,12 +1,20 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'sinatra/base'
3
4
  require 'tilt/erb'
4
5
  require 'rack'
5
6
  require 'yaml'
6
7
 
7
8
  class TestApp < Sinatra::Base
8
- class TestAppError < StandardError; end
9
+ class TestAppError < Exception; end # rubocop:disable Lint/InheritException
9
10
 
11
+ class TestAppOtherError < Exception # rubocop:disable Lint/InheritException
12
+ def initialize(string1, msg)
13
+ super()
14
+ @something = string1
15
+ @message = msg
16
+ end
17
+ end
10
18
  set :root, File.dirname(__FILE__)
11
19
  set :static, true
12
20
  set :raise_errors, true
@@ -15,7 +23,7 @@ class TestApp < Sinatra::Base
15
23
  # Also check lib/capybara/spec/views/*.erb for pages not listed here
16
24
 
17
25
  get '/' do
18
- response.set_cookie('capybara', { value: 'root cookie', domain: request.host, path: request.path} )
26
+ response.set_cookie('capybara', value: 'root cookie', domain: request.host, path: request.path)
19
27
  'Hello world! <a href="with_html">Relative</a>'
20
28
  end
21
29
 
@@ -27,13 +35,25 @@ class TestApp < Sinatra::Base
27
35
  redirect '/redirect_again'
28
36
  end
29
37
 
38
+ get '/redirect_with_fragment' do
39
+ redirect '/landed#with_fragment'
40
+ end
41
+
30
42
  get '/redirect_again' do
31
43
  redirect '/landed'
32
44
  end
33
45
 
46
+ post '/redirect_307' do
47
+ redirect '/landed', 307
48
+ end
49
+
50
+ post '/redirect_308' do
51
+ redirect '/landed', 308
52
+ end
53
+
34
54
  get '/referer_base' do
35
- '<a href="/get_referer">direct link</a>' +
36
- '<a href="/redirect_to_get_referer">link via redirect</a>' +
55
+ '<a href="/get_referer">direct link</a>' \
56
+ '<a href="/redirect_to_get_referer">link via redirect</a>' \
37
57
  '<form action="/get_referer" method="get"><input type="submit"></form>'
38
58
  end
39
59
 
@@ -42,7 +62,7 @@ class TestApp < Sinatra::Base
42
62
  end
43
63
 
44
64
  get '/get_referer' do
45
- request.referer.nil? ? "No referer" : "Got referer: #{request.referer}"
65
+ request.referer.nil? ? 'No referer' : "Got referer: #{request.referer}"
46
66
  end
47
67
 
48
68
  get '/host' do
@@ -52,26 +72,30 @@ class TestApp < Sinatra::Base
52
72
  get '/redirect/:times/times' do
53
73
  times = params[:times].to_i
54
74
  if times.zero?
55
- "redirection complete"
75
+ 'redirection complete'
56
76
  else
57
77
  redirect "/redirect/#{times - 1}/times"
58
78
  end
59
79
  end
60
80
 
61
81
  get '/landed' do
62
- "You landed"
82
+ 'You landed'
83
+ end
84
+
85
+ post '/landed' do
86
+ "You post landed: #{params.dig(:form, 'data')}"
63
87
  end
64
88
 
65
89
  get '/with-quotes' do
66
- %q{"No," he said, "you can't do that."}
90
+ %q("No," he said, "you can't do that.")
67
91
  end
68
92
 
69
93
  get '/form/get' do
70
- '<pre id="results">' + params[:form].to_yaml + '</pre>'
94
+ %(<pre id="results">#{params[:form].to_yaml}</pre>)
71
95
  end
72
96
 
73
97
  post '/relative' do
74
- '<pre id="results">' + params[:form].to_yaml + '</pre>'
98
+ %(<pre id="results">#{params[:form].to_yaml}</pre>)
75
99
  end
76
100
 
77
101
  get '/favicon.ico' do
@@ -82,12 +106,12 @@ class TestApp < Sinatra::Base
82
106
  redirect '/redirect_again'
83
107
  end
84
108
 
85
- delete "/delete" do
86
- "The requested object was deleted"
109
+ delete '/delete' do
110
+ 'The requested object was deleted'
87
111
  end
88
112
 
89
- get "/delete" do
90
- "Not deleted"
113
+ get '/delete' do
114
+ 'Not deleted'
91
115
  end
92
116
 
93
117
  get '/redirect_back' do
@@ -122,7 +146,11 @@ class TestApp < Sinatra::Base
122
146
  end
123
147
 
124
148
  get '/error' do
125
- raise TestAppError, "some error"
149
+ raise TestAppError, 'some error'
150
+ end
151
+
152
+ get '/other_error' do
153
+ raise TestAppOtherError.new('something', 'other error')
126
154
  end
127
155
 
128
156
  get '/load_error' do
@@ -133,12 +161,28 @@ class TestApp < Sinatra::Base
133
161
  erb :with_html, locals: { referrer: request.referrer }
134
162
  end
135
163
 
164
+ get '/with_title' do
165
+ <<-HTML
166
+ <title>#{params[:title] || 'Test Title'}</title>
167
+ <body>
168
+ <svg><title>abcdefg</title></svg>
169
+ </body>
170
+ HTML
171
+ end
172
+
173
+ get '/download.csv' do
174
+ content_type 'text/csv'
175
+ 'This, is, comma, separated' \
176
+ 'Thomas, Walpole, was , here'
177
+ end
178
+
136
179
  get '/:view' do |view|
137
180
  erb view.to_sym, locals: { referrer: request.referrer }
138
181
  end
139
182
 
140
183
  post '/form' do
141
- '<pre id="results">' + params[:form].to_yaml + '</pre>'
184
+ self.class.form_post_count += 1
185
+ %(<pre id="results">#{params[:form].merge('post_count' => self.class.form_post_count).to_yaml}</pre>)
142
186
  end
143
187
 
144
188
  post '/upload_empty' do
@@ -150,30 +194,35 @@ class TestApp < Sinatra::Base
150
194
  end
151
195
 
152
196
  post '/upload' do
153
- begin
154
- buffer = []
155
- buffer << "Content-type: #{params[:form][:document][:type]}"
156
- buffer << "File content: #{params[:form][:document][:tempfile].read}"
157
- buffer.join(' | ')
158
- rescue
159
- 'No file uploaded'
160
- end
197
+ buffer = []
198
+ buffer << "Content-type: #{params.dig(:form, :document, :type)}"
199
+ buffer << "File content: #{params.dig(:form, :document, :tempfile).read}"
200
+ buffer.join(' | ')
201
+ rescue StandardError
202
+ 'No file uploaded'
161
203
  end
162
204
 
163
205
  post '/upload_multiple' do
164
- begin
165
- buffer = ["#{params[:form][:multiple_documents].size}"]
166
- params[:form][:multiple_documents].each do |doc|
167
- buffer << "Content-type: #{doc[:type]}"
168
- buffer << "File content: #{doc[:tempfile].read}"
169
- end
170
- buffer.join(' | ')
171
- rescue
172
- 'No files uploaded'
206
+ docs = params.dig(:form, :multiple_documents)
207
+ buffer = [docs.size.to_s]
208
+ docs.each do |doc|
209
+ buffer << "Content-type: #{doc[:type]}"
210
+ buffer << "File content: #{doc[:tempfile].read}"
173
211
  end
212
+ buffer.join(' | ')
213
+ rescue StandardError
214
+ 'No files uploaded'
215
+ end
216
+
217
+ get '/apple-touch-icon-precomposed.png' do
218
+ halt(404)
174
219
  end
175
- end
176
220
 
177
- if __FILE__ == $0
178
- Rack::Handler::WEBrick.run TestApp, :Port => 8070
221
+ class << self
222
+ attr_accessor :form_post_count
223
+ end
224
+
225
+ @form_post_count = 0
179
226
  end
227
+
228
+ Rack::Handler::Puma.run TestApp, Port: 8070 if $PROGRAM_NAME == __FILE__