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
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'capybara/session/config'
5
+
6
+ module Capybara
7
+ class Config
8
+ extend Forwardable
9
+
10
+ OPTIONS = %i[app reuse_server threadsafe server default_driver javascript_driver allow_gumbo].freeze
11
+
12
+ attr_accessor :app, :allow_gumbo
13
+ attr_reader :reuse_server, :threadsafe, :session_options
14
+ attr_writer :default_driver, :javascript_driver
15
+
16
+ SessionConfig::OPTIONS.each do |method|
17
+ def_delegators :session_options, method, "#{method}="
18
+ end
19
+
20
+ def initialize
21
+ @session_options = Capybara::SessionConfig.new
22
+ @javascript_driver = nil
23
+ end
24
+
25
+ attr_writer :reuse_server
26
+
27
+ def threadsafe=(bool)
28
+ if (bool != threadsafe) && Session.instance_created?
29
+ raise 'Threadsafe setting cannot be changed once a session is created'
30
+ end
31
+
32
+ @threadsafe = bool
33
+ end
34
+
35
+ ##
36
+ #
37
+ # Return the proc that Capybara will call to run the Rack application.
38
+ # The block returned receives a rack app, port, and host/ip and should run a Rack handler
39
+ # By default, Capybara will try to use puma.
40
+ #
41
+ attr_reader :server
42
+
43
+ ##
44
+ #
45
+ # Set the server to use.
46
+ #
47
+ # Capybara.server = :webrick
48
+ # Capybara.server = :puma, { Silent: true }
49
+ #
50
+ # @overload server=(name)
51
+ # @param [Symbol] name Name of the server type to use
52
+ # @overload server=([name, options])
53
+ # @param [Symbol] name Name of the server type to use
54
+ # @param [Hash] options Options to pass to the server block
55
+ # @see register_server
56
+ #
57
+ def server=(name)
58
+ name, options = *name if name.is_a? Array
59
+ @server = if name.respond_to? :call
60
+ name
61
+ elsif options
62
+ proc { |app, port, host| Capybara.servers[name.to_sym].call(app, port, host, **options) }
63
+ else
64
+ Capybara.servers[name.to_sym]
65
+ end
66
+ end
67
+
68
+ ##
69
+ #
70
+ # @return [Symbol] The name of the driver to use by default
71
+ #
72
+ def default_driver
73
+ @default_driver || :rack_test
74
+ end
75
+
76
+ ##
77
+ #
78
+ # @return [Symbol] The name of the driver used when JavaScript is needed
79
+ #
80
+ def javascript_driver
81
+ @javascript_driver || :selenium
82
+ end
83
+
84
+ def deprecate(method, alternate_method, once: false)
85
+ @deprecation_notified ||= {}
86
+ unless once && @deprecation_notified[method]
87
+ Capybara::Helpers.warn "DEPRECATED: ##{method} is deprecated, please use ##{alternate_method} instead: #{Capybara::Helpers.filter_backtrace(caller)}"
88
+ end
89
+ @deprecation_notified[method] = true
90
+ end
91
+ end
92
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'capybara/dsl'
3
4
  require 'capybara/rspec/matchers'
5
+ require 'capybara/rspec/matcher_proxies'
4
6
 
5
7
  World(Capybara::DSL)
6
8
  World(Capybara::RSpecMatchers)
@@ -20,8 +22,6 @@ end
20
22
  Before do |scenario|
21
23
  scenario.source_tag_names.each do |tag|
22
24
  driver_name = tag.sub(/^@/, '').to_sym
23
- if Capybara.drivers.has_key?(driver_name)
24
- Capybara.current_driver = driver_name
25
- end
25
+ Capybara.current_driver = driver_name if Capybara.drivers[driver_name]
26
26
  end
27
27
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Capybara::Driver::Base
4
+ attr_writer :session
5
+
3
6
  def current_url
4
7
  raise NotImplementedError
5
8
  end
@@ -8,11 +11,15 @@ class Capybara::Driver::Base
8
11
  raise NotImplementedError
9
12
  end
10
13
 
11
- def find_xpath(query)
14
+ def refresh
12
15
  raise NotImplementedError
13
16
  end
14
17
 
15
- def find_css(query)
18
+ def find_xpath(query, **options)
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def find_css(query, **options)
16
23
  raise NotImplementedError
17
24
  end
18
25
 
@@ -28,15 +35,19 @@ class Capybara::Driver::Base
28
35
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#go_forward'
29
36
  end
30
37
 
31
- def execute_script(script)
38
+ def execute_script(script, *args)
32
39
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#execute_script'
33
40
  end
34
41
 
35
- def evaluate_script(script)
42
+ def evaluate_script(script, *args)
36
43
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#evaluate_script'
37
44
  end
38
45
 
39
- def save_screenshot(path, options={})
46
+ def evaluate_async_script(script, *args)
47
+ raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#evaluate_script_asnyc'
48
+ end
49
+
50
+ def save_screenshot(path, **options)
40
51
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#save_screenshot'
41
52
  end
42
53
 
@@ -48,8 +59,26 @@ class Capybara::Driver::Base
48
59
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#status_code'
49
60
  end
50
61
 
51
- def within_frame(frame_handle)
52
- raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#within_frame'
62
+ def send_keys(*)
63
+ raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#send_keys'
64
+ end
65
+
66
+ ##
67
+ #
68
+ # @param frame [Capybara::Node::Element, :parent, :top] The iframe element to switch to
69
+ #
70
+ def switch_to_frame(frame)
71
+ raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#switch_to_frame'
72
+ end
73
+
74
+ def frame_title
75
+ find_xpath('/html/head/title').map(&:all_text).first.to_s
76
+ end
77
+
78
+ def frame_url
79
+ evaluate_script('document.location.href')
80
+ rescue Capybara::NotSupportedByDriverError
81
+ raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#frame_title'
53
82
  end
54
83
 
55
84
  def current_window_handle
@@ -65,7 +94,11 @@ class Capybara::Driver::Base
65
94
  end
66
95
 
67
96
  def maximize_window(handle)
68
- raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#maximize_current_window'
97
+ raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#maximize_window'
98
+ end
99
+
100
+ def fullscreen_window(handle)
101
+ raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#fullscreen_window'
69
102
  end
70
103
 
71
104
  def close_window(handle)
@@ -84,15 +117,10 @@ class Capybara::Driver::Base
84
117
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#switch_to_window'
85
118
  end
86
119
 
87
- def within_window(locator)
88
- raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#within_window'
89
- end
90
-
91
120
  def no_such_window_error
92
121
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#no_such_window_error'
93
122
  end
94
123
 
95
-
96
124
  ##
97
125
  #
98
126
  # Execute the block, and then accept the modal opened.
@@ -103,7 +131,7 @@ class Capybara::Driver::Base
103
131
  # @return [String] the message shown in the modal
104
132
  # @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
105
133
  #
106
- def accept_modal(type, options={}, &blk)
134
+ def accept_modal(type, **options, &blk)
107
135
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#accept_modal'
108
136
  end
109
137
 
@@ -116,7 +144,7 @@ class Capybara::Driver::Base
116
144
  # @return [String] the message shown in the modal
117
145
  # @raise [Capybara::ModalNotFound] if modal dialog hasn't been found
118
146
  #
119
- def dismiss_modal(type, options={}, &blk)
147
+ def dismiss_modal(type, **options, &blk)
120
148
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#dismiss_modal'
121
149
  end
122
150
 
@@ -128,16 +156,19 @@ class Capybara::Driver::Base
128
156
  false
129
157
  end
130
158
 
131
- def reset!
132
- end
159
+ def reset!; end
133
160
 
134
161
  def needs_server?
135
162
  false
136
163
  end
137
164
 
138
- # @deprecated This method is being removed
139
- def browser_initialized?
140
- warn "DEPRECATED: #browser_initialized? is deprecated and will be removed in the next version of Capybara"
141
- true
165
+ def session_options
166
+ session&.config || Capybara.session_options
167
+ end
168
+
169
+ private
170
+
171
+ def session
172
+ @session ||= nil
142
173
  end
143
174
  end
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  module Driver
4
5
  class Node
5
- attr_reader :driver, :native
6
+ attr_reader :driver, :native, :initial_cache
6
7
 
7
- def initialize(driver, native)
8
+ def initialize(driver, native, initial_cache = {})
8
9
  @driver = driver
9
10
  @native = native
11
+ @initial_cache = initial_cache
10
12
  end
11
13
 
12
14
  def all_text
@@ -25,9 +27,13 @@ module Capybara
25
27
  raise NotImplementedError
26
28
  end
27
29
 
28
- # @param value String or Array. Array is only allowed if node has 'multiple' attribute
29
- # @param options [Hash{}] Driver specific options for how to set a value on a node
30
- def set(value, options={})
30
+ def style(styles)
31
+ raise NotImplementedError
32
+ end
33
+
34
+ # @param value [String, Array] Array is only allowed if node has 'multiple' attribute
35
+ # @param options [Hash] Driver specific options for how to set a value on a node
36
+ def set(value, **options)
31
37
  raise NotImplementedError
32
38
  end
33
39
 
@@ -39,27 +45,39 @@ module Capybara
39
45
  raise NotImplementedError
40
46
  end
41
47
 
42
- def click
48
+ def click(keys = [], **options)
43
49
  raise NotImplementedError
44
50
  end
45
-
46
- def right_click
51
+
52
+ def right_click(keys = [], **options)
47
53
  raise NotImplementedError
48
54
  end
49
-
50
- def double_click
55
+
56
+ def double_click(keys = [], **options)
51
57
  raise NotImplementedError
52
58
  end
53
-
59
+
54
60
  def send_keys(*args)
55
61
  raise NotImplementedError
56
62
  end
57
-
63
+
58
64
  def hover
59
65
  raise NotImplementedError
60
66
  end
61
-
62
- def drag_to(element)
67
+
68
+ def drag_to(element, **options)
69
+ raise NotImplementedError
70
+ end
71
+
72
+ def drop(*args)
73
+ raise NotImplementedError
74
+ end
75
+
76
+ def scroll_by(x, y)
77
+ raise NotImplementedError
78
+ end
79
+
80
+ def scroll_to(element, alignment, position = nil)
63
81
  raise NotImplementedError
64
82
  end
65
83
 
@@ -71,6 +89,10 @@ module Capybara
71
89
  raise NotImplementedError
72
90
  end
73
91
 
92
+ def obscured?
93
+ raise NotImplementedError
94
+ end
95
+
74
96
  def checked?
75
97
  raise NotImplementedError
76
98
  end
@@ -83,6 +105,18 @@ module Capybara
83
105
  raise NotImplementedError
84
106
  end
85
107
 
108
+ def readonly?
109
+ !!self[:readonly]
110
+ end
111
+
112
+ def multiple?
113
+ !!self[:multiple]
114
+ end
115
+
116
+ def rect
117
+ raise NotSupportedByDriverError, 'Capybara::Driver::Node#rect'
118
+ end
119
+
86
120
  def path
87
121
  raise NotSupportedByDriverError, 'Capybara::Driver::Node#path'
88
122
  end
data/lib/capybara/dsl.rb CHANGED
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'capybara'
3
4
 
4
5
  module Capybara
5
6
  module DSL
6
7
  def self.included(base)
7
- warn "including Capybara::DSL in the global scope is not recommended!" if base == Object
8
+ warn 'including Capybara::DSL in the global scope is not recommended!' if base == Object
8
9
  super
9
10
  end
10
11
 
11
12
  def self.extended(base)
12
- warn "extending the main object with Capybara::DSL is not recommended!" if base == TOPLEVEL_BINDING.eval("self")
13
+ warn 'extending the main object with Capybara::DSL is not recommended!' if base == TOPLEVEL_BINDING.eval('self')
13
14
  super
14
15
  end
15
16
 
@@ -17,16 +18,14 @@ module Capybara
17
18
  #
18
19
  # Shortcut to working in a different session.
19
20
  #
20
- def using_session(name, &block)
21
- Capybara.using_session(name, &block)
21
+ def using_session(name_or_session, &block)
22
+ Capybara.using_session(name_or_session, &block)
22
23
  end
23
24
 
24
- ##
25
- #
26
25
  # Shortcut to using a different wait time.
27
26
  #
28
27
  def using_wait_time(seconds, &block)
29
- Capybara.using_wait_time(seconds, &block)
28
+ page.using_wait_time(seconds, &block)
30
29
  end
31
30
 
32
31
  ##
@@ -48,8 +47,16 @@ module Capybara
48
47
  end
49
48
 
50
49
  Session::DSL_METHODS.each do |method|
51
- define_method method do |*args, &block|
52
- page.send method, *args, &block
50
+ if RUBY_VERSION >= '2.7'
51
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
52
+ def #{method}(...)
53
+ page.method("#{method}").call(...)
54
+ end
55
+ METHOD
56
+ else
57
+ define_method method do |*args, &block|
58
+ page.send method, *args, &block
59
+ end
53
60
  end
54
61
  end
55
62
  end
@@ -1,14 +1,12 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Capybara
5
-
6
4
  # @api private
7
5
  module Helpers
8
- extend self
6
+ module_function
9
7
 
10
8
  ##
11
- #
9
+ # @deprecated
12
10
  # Normalizes whitespace space by stripping leading and trailing
13
11
  # whitespace and replacing sequences of whitespace characters
14
12
  # with a single space.
@@ -17,6 +15,7 @@ module Capybara
17
15
  # @return [String] Normalized text
18
16
  #
19
17
  def normalize_whitespace(text)
18
+ Capybara::Helpers.warn 'DEPRECATED: Capybara::Helpers::normalize_whitespace is deprecated, please update your driver'
20
19
  text.to_s.gsub(/[[:space:]]+/, ' ').strip
21
20
  end
22
21
 
@@ -26,90 +25,37 @@ module Capybara
26
25
  # if text is not a regexp
27
26
  #
28
27
  # @param [String] text Text to escape
29
- # @return [String] Escaped text
28
+ # @param [Boolean] exact (false) Whether or not this should be an exact text match
29
+ # @param [Fixnum, Boolean, nil] options Options passed to Regexp.new when creating the Regexp
30
+ # @return [Regexp] Regexp to match the passed in text and options
30
31
  #
31
- def to_regexp(text)
32
- text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(normalize_whitespace(text)))
32
+ def to_regexp(text, exact: false, all_whitespace: false, options: nil)
33
+ return text if text.is_a?(Regexp)
34
+
35
+ escaped = Regexp.escape(text)
36
+ escaped = escaped.gsub('\\ ', '[[:blank:]]') if all_whitespace
37
+ escaped = "\\A#{escaped}\\z" if exact
38
+ Regexp.new(escaped, options)
33
39
  end
34
40
 
35
41
  ##
36
42
  #
37
43
  # Injects a `<base>` tag into the given HTML code, pointing to
38
- # `Capybara.asset_host`.
44
+ # {Capybara.configure asset_host}.
39
45
  #
40
46
  # @param [String] html HTML code to inject into
47
+ # @param [URL] host (Capybara.asset_host) The host from which assets should be loaded
41
48
  # @return [String] The modified HTML code
42
49
  #
43
- def inject_asset_host(html)
44
- if Capybara.asset_host && Nokogiri::HTML(html).css("base").empty?
45
- match = html.match(/<head[^<]*?>/)
46
- if match
47
- return html.clone.insert match.end(0), "<base href='#{Capybara.asset_host}' />"
50
+ def inject_asset_host(html, host: Capybara.asset_host)
51
+ if host && Nokogiri::HTML(html).css('base').empty?
52
+ html.match(/<head[^<]*?>/) do |m|
53
+ return html.clone.insert m.end(0), "<base href='#{host}' />"
48
54
  end
49
55
  end
50
-
51
56
  html
52
57
  end
53
58
 
54
- ##
55
- #
56
- # Checks if the given count matches the given count options.
57
- # Defaults to true if no options are specified. If multiple
58
- # options are provided, it tests that all conditions are met;
59
- # however, if :count is supplied, all other options are ignored.
60
- #
61
- # @param [Integer] count The actual number. Should be coercible via Integer()
62
- # @option [Range] between Count must be within the given range
63
- # @option [Integer] count Count must be exactly this
64
- # @option [Integer] maximum Count must be smaller than or equal to this value
65
- # @option [Integer] minimum Count must be larger than or equal to this value
66
- #
67
- def matches_count?(count, options={})
68
- return (Integer(options[:count]) == count) if options[:count]
69
- return false if options[:maximum] && (Integer(options[:maximum]) < count)
70
- return false if options[:minimum] && (Integer(options[:minimum]) > count)
71
- return false if options[:between] && !(options[:between] === count)
72
- return true
73
- end
74
-
75
- ##
76
- #
77
- # Checks if a count of 0 is valid for the given options hash.
78
- # Returns false if options hash does not specify any count options.
79
- #
80
- def expects_none?(options={})
81
- if [:count, :maximum, :minimum, :between].any? { |k| options.has_key? k }
82
- matches_count?(0,options)
83
- else
84
- false
85
- end
86
- end
87
-
88
- ##
89
- #
90
- # Generates a failure message given a description of the query and count
91
- # options.
92
- #
93
- # @param [String] description Description of a query
94
- # @option [Range] between Count should have been within the given range
95
- # @option [Integer] count Count should have been exactly this
96
- # @option [Integer] maximum Count should have been smaller than or equal to this value
97
- # @option [Integer] minimum Count should have been larger than or equal to this value
98
- #
99
- def failure_message(description, options={})
100
- message = String.new("expected to find #{description}")
101
- if options[:count]
102
- message << " #{options[:count]} #{declension('time', 'times', options[:count])}"
103
- elsif options[:between]
104
- message << " between #{options[:between].first} and #{options[:between].last} times"
105
- elsif options[:maximum]
106
- message << " at most #{options[:maximum]} #{declension('time', 'times', options[:maximum])}"
107
- elsif options[:minimum]
108
- message << " at least #{options[:minimum]} #{declension('time', 'times', options[:minimum])}"
109
- end
110
- message
111
- end
112
-
113
59
  ##
114
60
  #
115
61
  # A poor man's `pluralize`. Given two declensions, one singular and one
@@ -121,20 +67,65 @@ module Capybara
121
67
  # @param [Integer] count The number of items
122
68
  #
123
69
  def declension(singular, plural, count)
124
- if count == 1
125
- singular
70
+ count == 1 ? singular : plural
71
+ end
72
+
73
+ def filter_backtrace(trace)
74
+ return 'No backtrace' unless trace
75
+
76
+ filter = %r{lib/capybara/|lib/rspec/|lib/minitest/}
77
+ new_trace = trace.take_while { |line| line !~ filter }
78
+ new_trace = trace.reject { |line| line =~ filter } if new_trace.empty?
79
+ new_trace = trace.dup if new_trace.empty?
80
+
81
+ new_trace.first.split(/:in /, 2).first
82
+ end
83
+
84
+ def warn(message, uplevel: 1)
85
+ return Kernel.warn(message, uplevel: uplevel) if RUBY_VERSION >= '2.6'
86
+
87
+ # TODO: Remove when we drop support for Ruby 2.5
88
+ # Workaround for emulating `warn '...', uplevel: n` in Ruby 2.5 or lower.
89
+ if (match = /^(?<file>.+?):(?<line>\d+)(?::in `.*')?/.match(caller[uplevel]))
90
+ location = [match[:file], match[:line]].join(':')
91
+ Kernel.warn "#{location}: #{message}"
126
92
  else
127
- plural
93
+ Kernel.warn message
128
94
  end
129
95
  end
130
96
 
131
97
  if defined?(Process::CLOCK_MONOTONIC)
132
- def monotonic_time
133
- Process.clock_gettime Process::CLOCK_MONOTONIC
134
- end
98
+ def monotonic_time; Process.clock_gettime Process::CLOCK_MONOTONIC; end
135
99
  else
136
- def monotonic_time
137
- Time.now.to_f
100
+ def monotonic_time; Time.now.to_f; end
101
+ end
102
+
103
+ def timer(expire_in:)
104
+ Timer.new(expire_in)
105
+ end
106
+
107
+ class Timer
108
+ def initialize(expire_in)
109
+ @start = current
110
+ @expire_in = expire_in
111
+ end
112
+
113
+ def expired?
114
+ if stalled?
115
+ raise Capybara::FrozenInTime, 'Time appears to be frozen. Capybara does not work with libraries which freeze time, consider using time travelling instead'
116
+ end
117
+
118
+ current - @start >= @expire_in
119
+ end
120
+
121
+ def stalled?
122
+ @start == current
123
+ end
124
+
125
+ private
126
+
127
+ def current
128
+ Capybara::Helpers.monotonic_time
138
129
  end
139
130
  end
140
131
  end