capybara 2.18.0 → 3.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +945 -12
  4. data/License.txt +1 -1
  5. data/README.md +264 -90
  6. data/lib/capybara/config.rb +29 -57
  7. data/lib/capybara/cucumber.rb +2 -3
  8. data/lib/capybara/driver/base.rb +35 -18
  9. data/lib/capybara/driver/node.rb +40 -10
  10. data/lib/capybara/dsl.rb +10 -7
  11. data/lib/capybara/helpers.rb +70 -31
  12. data/lib/capybara/minitest/spec.rb +185 -83
  13. data/lib/capybara/minitest.rb +232 -112
  14. data/lib/capybara/node/actions.rb +274 -171
  15. data/lib/capybara/node/base.rb +42 -34
  16. data/lib/capybara/node/document.rb +15 -3
  17. data/lib/capybara/node/document_matchers.rb +19 -21
  18. data/lib/capybara/node/element.rb +362 -135
  19. data/lib/capybara/node/finders.rb +151 -137
  20. data/lib/capybara/node/matchers.rb +394 -209
  21. data/lib/capybara/node/simple.rb +59 -26
  22. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  23. data/lib/capybara/queries/active_element_query.rb +18 -0
  24. data/lib/capybara/queries/ancestor_query.rb +12 -9
  25. data/lib/capybara/queries/base_query.rb +39 -28
  26. data/lib/capybara/queries/current_path_query.rb +21 -27
  27. data/lib/capybara/queries/match_query.rb +14 -7
  28. data/lib/capybara/queries/selector_query.rb +659 -149
  29. data/lib/capybara/queries/sibling_query.rb +11 -9
  30. data/lib/capybara/queries/style_query.rb +45 -0
  31. data/lib/capybara/queries/text_query.rb +56 -38
  32. data/lib/capybara/queries/title_query.rb +8 -11
  33. data/lib/capybara/rack_test/browser.rb +114 -42
  34. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  35. data/lib/capybara/rack_test/driver.rb +22 -17
  36. data/lib/capybara/rack_test/errors.rb +6 -0
  37. data/lib/capybara/rack_test/form.rb +93 -58
  38. data/lib/capybara/rack_test/node.rb +184 -81
  39. data/lib/capybara/rails.rb +3 -7
  40. data/lib/capybara/registration_container.rb +41 -0
  41. data/lib/capybara/registrations/drivers.rb +42 -0
  42. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  43. data/lib/capybara/registrations/servers.rb +66 -0
  44. data/lib/capybara/result.rb +97 -63
  45. data/lib/capybara/rspec/features.rb +17 -50
  46. data/lib/capybara/rspec/matcher_proxies.rb +52 -15
  47. data/lib/capybara/rspec/matchers/base.rb +113 -0
  48. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  49. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  50. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  51. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  52. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  53. data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  54. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  55. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  56. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  57. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  58. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  59. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  60. data/lib/capybara/rspec/matchers.rb +146 -310
  61. data/lib/capybara/rspec.rb +7 -11
  62. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  63. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  64. data/lib/capybara/selector/css.rb +85 -13
  65. data/lib/capybara/selector/definition/button.rb +68 -0
  66. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  67. data/lib/capybara/selector/definition/css.rb +10 -0
  68. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  69. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  70. data/lib/capybara/selector/definition/element.rb +28 -0
  71. data/lib/capybara/selector/definition/field.rb +40 -0
  72. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  73. data/lib/capybara/selector/definition/file_field.rb +13 -0
  74. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  75. data/lib/capybara/selector/definition/frame.rb +17 -0
  76. data/lib/capybara/selector/definition/id.rb +6 -0
  77. data/lib/capybara/selector/definition/label.rb +62 -0
  78. data/lib/capybara/selector/definition/link.rb +55 -0
  79. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  80. data/lib/capybara/selector/definition/option.rb +27 -0
  81. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  82. data/lib/capybara/selector/definition/select.rb +81 -0
  83. data/lib/capybara/selector/definition/table.rb +109 -0
  84. data/lib/capybara/selector/definition/table_row.rb +21 -0
  85. data/lib/capybara/selector/definition/xpath.rb +5 -0
  86. data/lib/capybara/selector/definition.rb +280 -0
  87. data/lib/capybara/selector/filter.rb +2 -17
  88. data/lib/capybara/selector/filter_set.rb +80 -33
  89. data/lib/capybara/selector/filters/base.rb +50 -6
  90. data/lib/capybara/selector/filters/expression_filter.rb +8 -26
  91. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  92. data/lib/capybara/selector/filters/node_filter.rb +16 -12
  93. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  94. data/lib/capybara/selector/selector.rb +93 -210
  95. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  96. data/lib/capybara/selector.rb +475 -523
  97. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  98. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  99. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  100. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  101. data/lib/capybara/selenium/driver.rb +298 -267
  102. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  103. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  104. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
  105. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  106. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  107. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  108. data/lib/capybara/selenium/extensions/find.rb +110 -0
  109. data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
  110. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  111. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  112. data/lib/capybara/selenium/node.rb +517 -145
  113. data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
  114. data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  115. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  116. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  117. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  118. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  119. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  120. data/lib/capybara/selenium/patches/logs.rb +45 -0
  121. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  122. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  123. data/lib/capybara/server/animation_disabler.rb +80 -0
  124. data/lib/capybara/server/checker.rb +44 -0
  125. data/lib/capybara/server/middleware.rb +71 -0
  126. data/lib/capybara/server.rb +59 -67
  127. data/lib/capybara/session/config.rb +81 -67
  128. data/lib/capybara/session/matchers.rb +28 -20
  129. data/lib/capybara/session.rb +337 -365
  130. data/lib/capybara/spec/public/jquery.js +5 -5
  131. data/lib/capybara/spec/public/offset.js +6 -0
  132. data/lib/capybara/spec/public/test.js +151 -12
  133. data/lib/capybara/spec/session/accept_alert_spec.rb +12 -11
  134. data/lib/capybara/spec/session/accept_confirm_spec.rb +6 -5
  135. data/lib/capybara/spec/session/accept_prompt_spec.rb +10 -10
  136. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  137. data/lib/capybara/spec/session/all_spec.rb +161 -57
  138. data/lib/capybara/spec/session/ancestor_spec.rb +27 -24
  139. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +68 -38
  140. data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
  141. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  142. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  143. data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
  144. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +22 -12
  145. data/lib/capybara/spec/session/attach_file_spec.rb +144 -69
  146. data/lib/capybara/spec/session/body_spec.rb +12 -13
  147. data/lib/capybara/spec/session/check_spec.rb +117 -55
  148. data/lib/capybara/spec/session/choose_spec.rb +64 -31
  149. data/lib/capybara/spec/session/click_button_spec.rb +231 -173
  150. data/lib/capybara/spec/session/click_link_or_button_spec.rb +55 -35
  151. data/lib/capybara/spec/session/click_link_spec.rb +93 -58
  152. data/lib/capybara/spec/session/current_scope_spec.rb +12 -11
  153. data/lib/capybara/spec/session/current_url_spec.rb +57 -39
  154. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +4 -4
  155. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +3 -2
  156. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  157. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  158. data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
  159. data/lib/capybara/spec/session/element/matches_selector_spec.rb +71 -57
  160. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +8 -7
  161. data/lib/capybara/spec/session/evaluate_script_spec.rb +29 -8
  162. data/lib/capybara/spec/session/execute_script_spec.rb +10 -8
  163. data/lib/capybara/spec/session/fill_in_spec.rb +134 -43
  164. data/lib/capybara/spec/session/find_button_spec.rb +25 -24
  165. data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
  166. data/lib/capybara/spec/session/find_field_spec.rb +37 -41
  167. data/lib/capybara/spec/session/find_link_spec.rb +46 -17
  168. data/lib/capybara/spec/session/find_spec.rb +260 -145
  169. data/lib/capybara/spec/session/first_spec.rb +80 -52
  170. data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  171. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  172. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +33 -20
  173. data/lib/capybara/spec/session/frame/within_frame_spec.rb +52 -32
  174. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  175. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  176. data/lib/capybara/spec/session/has_all_selectors_spec.rb +31 -31
  177. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  178. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  179. data/lib/capybara/spec/session/has_button_spec.rb +100 -13
  180. data/lib/capybara/spec/session/has_css_spec.rb +272 -137
  181. data/lib/capybara/spec/session/has_current_path_spec.rb +60 -61
  182. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  183. data/lib/capybara/spec/session/has_field_spec.rb +139 -59
  184. data/lib/capybara/spec/session/has_link_spec.rb +47 -6
  185. data/lib/capybara/spec/session/has_none_selectors_spec.rb +42 -40
  186. data/lib/capybara/spec/session/has_select_spec.rb +107 -72
  187. data/lib/capybara/spec/session/has_selector_spec.rb +120 -71
  188. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  189. data/lib/capybara/spec/session/has_table_spec.rb +183 -5
  190. data/lib/capybara/spec/session/has_text_spec.rb +106 -62
  191. data/lib/capybara/spec/session/has_title_spec.rb +20 -14
  192. data/lib/capybara/spec/session/has_xpath_spec.rb +57 -38
  193. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +3 -2
  194. data/lib/capybara/spec/session/html_spec.rb +14 -6
  195. data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
  196. data/lib/capybara/spec/session/node_spec.rb +1024 -153
  197. data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
  198. data/lib/capybara/spec/session/refresh_spec.rb +12 -6
  199. data/lib/capybara/spec/session/reset_session_spec.rb +82 -35
  200. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +2 -1
  201. data/lib/capybara/spec/session/save_and_open_page_spec.rb +3 -2
  202. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +8 -12
  203. data/lib/capybara/spec/session/save_page_spec.rb +42 -55
  204. data/lib/capybara/spec/session/save_screenshot_spec.rb +16 -14
  205. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  206. data/lib/capybara/spec/session/scroll_spec.rb +119 -0
  207. data/lib/capybara/spec/session/select_spec.rb +107 -81
  208. data/lib/capybara/spec/session/selectors_spec.rb +52 -19
  209. data/lib/capybara/spec/session/sibling_spec.rb +10 -10
  210. data/lib/capybara/spec/session/text_spec.rb +37 -21
  211. data/lib/capybara/spec/session/title_spec.rb +17 -5
  212. data/lib/capybara/spec/session/uncheck_spec.rb +43 -23
  213. data/lib/capybara/spec/session/unselect_spec.rb +39 -38
  214. data/lib/capybara/spec/session/visit_spec.rb +85 -53
  215. data/lib/capybara/spec/session/window/become_closed_spec.rb +24 -20
  216. data/lib/capybara/spec/session/window/current_window_spec.rb +5 -3
  217. data/lib/capybara/spec/session/window/open_new_window_spec.rb +5 -3
  218. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +27 -22
  219. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +12 -6
  220. data/lib/capybara/spec/session/window/window_spec.rb +97 -63
  221. data/lib/capybara/spec/session/window/windows_spec.rb +12 -10
  222. data/lib/capybara/spec/session/window/within_window_spec.rb +31 -86
  223. data/lib/capybara/spec/session/within_spec.rb +83 -44
  224. data/lib/capybara/spec/spec_helper.rb +54 -44
  225. data/lib/capybara/spec/test_app.rb +158 -43
  226. data/lib/capybara/spec/views/animated.erb +49 -0
  227. data/lib/capybara/spec/views/form.erb +163 -42
  228. data/lib/capybara/spec/views/frame_child.erb +4 -3
  229. data/lib/capybara/spec/views/frame_one.erb +2 -1
  230. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  231. data/lib/capybara/spec/views/frame_two.erb +1 -1
  232. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  233. data/lib/capybara/spec/views/layout.erb +10 -0
  234. data/lib/capybara/spec/views/obscured.erb +47 -0
  235. data/lib/capybara/spec/views/offset.erb +33 -0
  236. data/lib/capybara/spec/views/path.erb +2 -2
  237. data/lib/capybara/spec/views/popup_one.erb +1 -1
  238. data/lib/capybara/spec/views/popup_two.erb +1 -1
  239. data/lib/capybara/spec/views/react.erb +45 -0
  240. data/lib/capybara/spec/views/scroll.erb +21 -0
  241. data/lib/capybara/spec/views/spatial.erb +31 -0
  242. data/lib/capybara/spec/views/tables.erb +68 -1
  243. data/lib/capybara/spec/views/with_animation.erb +81 -0
  244. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  245. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  246. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  247. data/lib/capybara/spec/views/with_hover.erb +3 -2
  248. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  249. data/lib/capybara/spec/views/with_html.erb +69 -12
  250. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  251. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  252. data/lib/capybara/spec/views/with_js.erb +30 -5
  253. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  254. data/lib/capybara/spec/views/with_namespace.erb +21 -0
  255. data/lib/capybara/spec/views/with_scope.erb +2 -2
  256. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  257. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  258. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  259. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  260. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  261. data/lib/capybara/spec/views/with_windows.erb +1 -1
  262. data/lib/capybara/spec/views/within_frames.erb +5 -2
  263. data/lib/capybara/version.rb +2 -1
  264. data/lib/capybara/window.rb +36 -34
  265. data/lib/capybara.rb +134 -107
  266. data/spec/basic_node_spec.rb +60 -34
  267. data/spec/capybara_spec.rb +63 -88
  268. data/spec/counter_spec.rb +35 -0
  269. data/spec/css_builder_spec.rb +101 -0
  270. data/spec/css_splitter_spec.rb +38 -0
  271. data/spec/dsl_spec.rb +85 -64
  272. data/spec/filter_set_spec.rb +27 -9
  273. data/spec/fixtures/certificate.pem +25 -0
  274. data/spec/fixtures/key.pem +27 -0
  275. data/spec/fixtures/selenium_driver_rspec_failure.rb +6 -5
  276. data/spec/fixtures/selenium_driver_rspec_success.rb +6 -5
  277. data/spec/minitest_spec.rb +52 -7
  278. data/spec/minitest_spec_spec.rb +94 -63
  279. data/spec/per_session_config_spec.rb +14 -13
  280. data/spec/rack_test_spec.rb +194 -125
  281. data/spec/regexp_dissassembler_spec.rb +250 -0
  282. data/spec/result_spec.rb +111 -50
  283. data/spec/rspec/features_spec.rb +37 -31
  284. data/spec/rspec/scenarios_spec.rb +10 -8
  285. data/spec/rspec/shared_spec_matchers.rb +473 -422
  286. data/spec/rspec/views_spec.rb +5 -3
  287. data/spec/rspec_matchers_spec.rb +52 -11
  288. data/spec/rspec_spec.rb +109 -89
  289. data/spec/sauce_spec_chrome.rb +43 -0
  290. data/spec/selector_spec.rb +397 -68
  291. data/spec/selenium_spec_chrome.rb +187 -40
  292. data/spec/selenium_spec_chrome_remote.rb +96 -0
  293. data/spec/selenium_spec_edge.rb +60 -0
  294. data/spec/selenium_spec_firefox.rb +201 -41
  295. data/spec/selenium_spec_firefox_remote.rb +94 -0
  296. data/spec/selenium_spec_ie.rb +149 -0
  297. data/spec/selenium_spec_safari.rb +162 -0
  298. data/spec/server_spec.rb +213 -102
  299. data/spec/session_spec.rb +53 -16
  300. data/spec/shared_selenium_node.rb +79 -0
  301. data/spec/shared_selenium_session.rb +473 -122
  302. data/spec/spec_helper.rb +126 -7
  303. data/spec/whitespace_normalizer_spec.rb +54 -0
  304. data/spec/xpath_builder_spec.rb +93 -0
  305. metadata +355 -73
  306. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  307. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  308. data/.yard/yard_extensions.rb +0 -78
  309. data/lib/capybara/query.rb +0 -7
  310. data/lib/capybara/rspec/compound.rb +0 -95
  311. data/lib/capybara/spec/session/assert_current_path.rb +0 -72
  312. data/lib/capybara/spec/session/assert_selector.rb +0 -148
  313. data/lib/capybara/spec/session/assert_text.rb +0 -234
  314. data/lib/capybara/spec/session/source_spec.rb +0 -0
  315. data/lib/capybara/spec/views/with_title.erb +0 -5
  316. data/spec/selenium_spec_marionette.rb +0 -127
data/License.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2009-2016 Jonas Nicklas
3
+ Copyright (c) 2009-2018 Thomas Walpole, Jonas Nicklas
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,9 +1,8 @@
1
1
  # Capybara
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/teamcapybara/capybara.svg)](https://travis-ci.org/teamcapybara/capybara)
4
- [![Dependency Status](https://gemnasium.com/teamcapybara/capybara.svg)](https://gemnasium.com/teamcapybara/capybara)
3
+ [![Build Status](https://github.com/teamcapybara/capybara/actions/workflows/build.yml/badge.svg)](https://github.com/teamcapybara/capybara/actions/workflows/build.yml)
5
4
  [![Code Climate](https://codeclimate.com/github/teamcapybara/capybara.svg)](https://codeclimate.com/github/teamcapybara/capybara)
6
- [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5
+ [![Coverage Status](https://coveralls.io/repos/github/teamcapybara/capybara/badge.svg?branch=master)](https://coveralls.io/github/teamcapybara/capybara?branch=master)
7
6
 
8
7
  Capybara helps you test web applications by simulating how a real user would
9
8
  interact with your app. It is agnostic about the driver running your tests and
@@ -16,8 +15,7 @@ If you and/or your company find value in Capybara and would like to contribute f
16
15
  <a href="https://www.patreon.com/capybara">Patreon</a>
17
16
 
18
17
 
19
- **Need help?** Ask on the mailing list (please do not open an issue on
20
- GitHub): http://groups.google.com/group/ruby-capybara
18
+ **Need help?** Ask on the discussions (please do not open an issue): https://github.com/orgs/teamcapybara/discussions/categories/q-a
21
19
 
22
20
  ## Table of contents
23
21
 
@@ -32,8 +30,6 @@ GitHub): http://groups.google.com/group/ruby-capybara
32
30
  - [Selecting the Driver](#selecting-the-driver)
33
31
  - [RackTest](#racktest)
34
32
  - [Selenium](#selenium)
35
- - [Capybara-webkit](#capybara-webkit)
36
- - [Poltergeist](#poltergeist)
37
33
  - [The DSL](#the-dsl)
38
34
  - [Navigating](#navigating)
39
35
  - [Clicking links and buttons](#clicking-links-and-buttons)
@@ -45,6 +41,10 @@ GitHub): http://groups.google.com/group/ruby-capybara
45
41
  - [Scripting](#scripting)
46
42
  - [Modals](#modals)
47
43
  - [Debugging](#debugging)
44
+ - [Selectors](#selectors)
45
+ - [Name](#selectors-name)
46
+ - [Locator](#selectors-locator)
47
+ - [Filters](#selectors-filters)
48
48
  - [Matching](#matching)
49
49
  - [Exactness](#exactness)
50
50
  - [Strategy](#strategy)
@@ -53,11 +53,13 @@ GitHub): http://groups.google.com/group/ruby-capybara
53
53
  - [Using the DSL elsewhere](#using-the-dsl-elsewhere)
54
54
  - [Calling remote servers](#calling-remote-servers)
55
55
  - [Using sessions](#using-sessions)
56
+ - [Named sessions](#named-sessions)
57
+ - [Using sessions manually](#using-sessions-manually)
56
58
  - [XPath, CSS and selectors](#xpath-css-and-selectors)
57
59
  - [Beware the XPath // trap](#beware-the-xpath--trap)
58
60
  - [Configuring and adding drivers](#configuring-and-adding-drivers)
59
61
  - [Gotchas:](#gotchas)
60
- - ["Threadsafe" mode](#threadsafe)
62
+ - ["Threadsafe" mode](#threadsafe-mode)
61
63
  - [Development](#development)
62
64
 
63
65
  ## <a name="key-benefits"></a>Key benefits
@@ -71,24 +73,19 @@ GitHub): http://groups.google.com/group/ruby-capybara
71
73
 
72
74
  ## <a name="setup"></a>Setup
73
75
 
74
- Capybara requires Ruby 1.9.3 or later. To install, add this line to your
76
+ Capybara requires Ruby 3.0.0 or later. To install, add this line to your
75
77
  `Gemfile` and run `bundle install`:
76
78
 
77
79
  ```ruby
78
80
  gem 'capybara'
79
81
  ```
80
82
 
81
- **Note:** If using Ruby < 2.0 you will also need to limit the version of rack to < 2.0
82
-
83
83
  If the application that you are testing is a Rails app, add this line to your test helper file:
84
84
 
85
85
  ```ruby
86
86
  require 'capybara/rails'
87
87
  ```
88
88
 
89
- **Note:** In Rails 4.0/4.1 the default test environment (`config/environments/test.rb`) is [not threadsafe](https://github.com/rails/rails/issues/15089).
90
- If you experience random errors about missing constants, add `config.allow_concurrency = false` to `config/environments/test.rb`.
91
-
92
89
  If the application that you are testing is a Rack app, but not Rails, set Capybara.app to your Rack app:
93
90
 
94
91
  ```ruby
@@ -140,28 +137,30 @@ There are also explicit tags for each registered driver set up for you (`@seleni
140
137
 
141
138
  ## <a name="using-capybara-with-rspec"></a>Using Capybara with RSpec
142
139
 
143
- Load RSpec 2+ support by adding the following line (typically to your
140
+ Load RSpec 3.5+ support by adding the following line (typically to your
144
141
  `spec_helper.rb` file):
145
142
 
146
143
  ```ruby
147
144
  require 'capybara/rspec'
148
145
  ```
149
146
 
150
- If you are using Rails, put your Capybara specs in `spec/features` (only works
151
- if [you have it configured in
152
- RSpec](https://www.relishapp.com/rspec/rspec-rails/docs/upgrade#file-type-inference-disabled))
153
- and if you have your Capybara specs in a different directory, then tag the
154
- example groups with `:type => :feature`.
147
+ If you are using Rails, put your Capybara specs in `spec/features` or `spec/system` (only works if
148
+ [you have it configured in RSpec](https://rspec.info/features/6-0/rspec-rails/directory-structure/))
149
+ and if you have your Capybara specs in a different directory, then tag the example groups with
150
+ `type: :feature` or `type: :system` depending on which type of test you're writing.
151
+
152
+ If you are using Rails system specs please see [their documentation](https://rspec.info/features/6-0/rspec-rails/system-specs/system-specs)
153
+ for selecting the driver you wish to use.
155
154
 
156
155
  If you are not using Rails, tag all the example groups in which you want to use
157
- Capybara with `:type => :feature`.
156
+ Capybara with `type: :feature`.
158
157
 
159
158
  You can now write your specs like so:
160
159
 
161
160
  ```ruby
162
- describe "the signin process", :type => :feature do
161
+ describe "the signin process", type: :feature do
163
162
  before :each do
164
- User.make(email: 'user@example.com', password: 'password')
163
+ User.create(email: 'user@example.com', password: 'password')
165
164
  end
166
165
 
167
166
  it "signs me in" do
@@ -183,7 +182,7 @@ to one specific driver. For example:
183
182
  ```ruby
184
183
  describe 'some stuff which requires js', js: true do
185
184
  it 'will use the default js driver'
186
- it 'will switch to one specific driver', :driver => :webkit
185
+ it 'will switch to one specific driver', driver: :selenium
187
186
  end
188
187
  ```
189
188
 
@@ -192,7 +191,7 @@ Capybara also comes with a built in DSL for creating descriptive acceptance test
192
191
  ```ruby
193
192
  feature "Signing in" do
194
193
  background do
195
- User.make(email: 'user@example.com', password: 'caplin')
194
+ User.create(email: 'user@example.com', password: 'caplin')
196
195
  end
197
196
 
198
197
  scenario "Signing in with correct credentials" do
@@ -205,7 +204,7 @@ feature "Signing in" do
205
204
  expect(page).to have_content 'Success'
206
205
  end
207
206
 
208
- given(:other_user) { User.make(email: 'other@example.com', password: 'rous') }
207
+ given(:other_user) { User.create(email: 'other@example.com', password: 'rous') }
209
208
 
210
209
  scenario "Signing in as another user" do
211
210
  visit '/sessions/new'
@@ -219,11 +218,11 @@ feature "Signing in" do
219
218
  end
220
219
  ```
221
220
 
222
- `feature` is in fact just an alias for `describe ..., :type => :feature`,
221
+ `feature` is in fact just an alias for `describe ..., type: :feature`,
223
222
  `background` is an alias for `before`, `scenario` for `it`, and
224
223
  `given`/`given!` aliases for `let`/`let!`, respectively.
225
224
 
226
- Finally, Capybara matchers are supported in view specs:
225
+ Finally, Capybara matchers are also supported in view specs:
227
226
 
228
227
  ```ruby
229
228
  RSpec.describe "todos/show.html.erb", type: :view do
@@ -260,7 +259,9 @@ end
260
259
 
261
260
  ## <a name="using-capybara-with-minitest"></a>Using Capybara with Minitest
262
261
 
263
- * If you are using Rails, add the following code in your `test_helper.rb`
262
+ * If you are using Rails system tests please see their documentation for information on selecting the driver you wish to use.
263
+
264
+ * If you are using Rails, but not using Rails system tests, add the following code in your `test_helper.rb`
264
265
  file to make Capybara available in all test cases deriving from
265
266
  `ActionDispatch::IntegrationTest`:
266
267
 
@@ -275,8 +276,7 @@ end
275
276
  include Capybara::Minitest::Assertions
276
277
 
277
278
  # Reset sessions and driver between tests
278
- # Use super wherever this method is redefined in your individual test classes
279
- def teardown
279
+ teardown do
280
280
  Capybara.reset_sessions!
281
281
  Capybara.use_default_driver
282
282
  end
@@ -335,15 +335,15 @@ By default, Capybara uses the `:rack_test` driver, which is fast but limited: it
335
335
  does not support JavaScript, nor is it able to access HTTP resources outside of
336
336
  your Rack application, such as remote APIs and OAuth services. To get around
337
337
  these limitations, you can set up a different default driver for your features.
338
- For example if you'd prefer to run everything in Selenium, you could do:
338
+ For example, if you'd prefer to run everything in Selenium, you could do:
339
339
 
340
340
  ```ruby
341
341
  Capybara.default_driver = :selenium # :selenium_chrome and :selenium_chrome_headless are also registered
342
342
  ```
343
343
 
344
- However, if you are using RSpec or Cucumber, you may instead want to consider
345
- leaving the faster `:rack_test` as the __default_driver__, and marking only those
346
- tests that require a JavaScript-capable driver using `js: true` or
344
+ However, if you are using RSpec or Cucumber (and your app runs correctly without JS),
345
+ you may instead want to consider leaving the faster `:rack_test` as the __default_driver__, and
346
+ marking only those tests that require a JavaScript-capable driver using `js: true` or
347
347
  `@javascript`, respectively. By default, JavaScript tests are run using the
348
348
  `:selenium` driver. You can change this by setting
349
349
  `Capybara.javascript_driver`.
@@ -352,7 +352,7 @@ You can also change the driver temporarily (typically in the Before/setup and
352
352
  After/teardown blocks):
353
353
 
354
354
  ```ruby
355
- Capybara.current_driver = :webkit # temporarily select different driver
355
+ Capybara.current_driver = :selenium # temporarily select different driver
356
356
  # tests here
357
357
  Capybara.use_default_driver # switch back to default driver
358
358
  ```
@@ -387,42 +387,26 @@ See the section on adding and configuring drivers.
387
387
 
388
388
  ### <a name="selenium"></a>Selenium
389
389
 
390
- At the moment, Capybara supports [Selenium 2.0+
391
- (Webdriver)](http://seleniumhq.org/docs/01_introducing_selenium.html#selenium-2-aka-selenium-webdriver),
392
- *not* Selenium RC. In order to use Selenium, you'll need to install the
393
- `selenium-webdriver` gem, and add it to your Gemfile if you're using bundler.
394
- Provided Firefox is installed, everything is set up for you, and you should be
395
- able to start using Selenium right away.
396
-
397
- **Note**: drivers which run the server in a different thread may not share the
398
- same transaction as your tests, causing data not to be shared between your test
399
- and test server, see "Transactions and database setup" below.
400
-
401
- ### <a name="capybara-webkit"></a>Capybara-webkit
390
+ Capybara supports [Selenium 3.5+
391
+ (Webdriver)](https://www.seleniumhq.org/projects/webdriver/).
392
+ In order to use Selenium, you'll need to install the `selenium-webdriver` gem,
393
+ and add it to your Gemfile if you're using bundler.
402
394
 
403
- The [capybara-webkit driver](https://github.com/thoughtbot/capybara-webkit) is for true headless
404
- testing. It uses QtWebKit to start a rendering engine process. It can execute JavaScript as well.
405
- It is significantly faster than drivers like Selenium since it does not load an entire browser.
395
+ Capybara pre-registers a number of named drivers that use Selenium - they are:
406
396
 
407
- You can install it with:
397
+ * :selenium => Selenium driving Firefox
398
+ * :selenium_headless => Selenium driving Firefox in a headless configuration
399
+ * :selenium_chrome => Selenium driving Chrome
400
+ * :selenium_chrome_headless => Selenium driving Chrome in a headless configuration
408
401
 
409
- ```bash
410
- gem install capybara-webkit
411
- ```
402
+ These should work (with relevant software installation) in a local desktop configuration but you may
403
+ need to customize them if using in a CI environment where additional options may need to be passed
404
+ to the browsers. See the section on adding and configuring drivers.
412
405
 
413
- And you can use it by:
414
406
 
415
- ```ruby
416
- Capybara.javascript_driver = :webkit
417
- ```
418
-
419
- ### <a name="poltergeist"></a>Poltergeist
420
-
421
- [Poltergeist](https://github.com/teampoltergeist/poltergeist) is another
422
- headless driver which integrates Capybara with
423
- [PhantomJS](http://phantomjs.org/). It is truly headless, so doesn't
424
- require Xvfb to run on your CI server. It will also detect and report
425
- any Javascript errors that happen within the page.
407
+ **Note**: drivers which run the server in a different thread may not share the
408
+ same transaction as your tests, causing data not to be shared between your test
409
+ and test server, see [Transactions and database setup](#transactions-and-database-setup) below.
426
410
 
427
411
  ## <a name="the-dsl"></a>The DSL
428
412
 
@@ -617,21 +601,31 @@ In drivers which support it, you can easily execute JavaScript:
617
601
  page.execute_script("$('body').empty()")
618
602
  ```
619
603
 
620
- For simple expressions, you can return the result of the script. Note
621
- that this may break with more complicated expressions:
604
+ For simple expressions, you can return the result of the script.
622
605
 
623
606
  ```ruby
624
607
  result = page.evaluate_script('4 + 4');
625
608
  ```
626
609
 
610
+ For more complicated scripts you'll need to write them as one expression.
611
+
612
+ ```ruby
613
+ result = page.evaluate_script(<<~JS, 3, element)
614
+ (function(n, el){
615
+ var val = parseInt(el.value, 10);
616
+ return n+val;
617
+ })(arguments[0], arguments[1])
618
+ JS
619
+ ```
620
+
627
621
  ### <a name="modals"></a>Modals
628
622
 
629
- In drivers which support it, you can accept, dismiss and respond to alerts, confirms and prompts.
623
+ In drivers which support it, you can accept, dismiss and respond to alerts, confirms, and prompts.
630
624
 
631
- You can accept or dismiss alert messages by wrapping the code that produces an alert in a block:
625
+ You can accept alert messages by wrapping the code that produces an alert in a block:
632
626
 
633
627
  ```ruby
634
- accept_alert do
628
+ accept_alert 'optional text or regex' do
635
629
  click_link('Show Alert')
636
630
  end
637
631
  ```
@@ -639,7 +633,13 @@ end
639
633
  You can accept or dismiss a confirmation by wrapping it in a block, as well:
640
634
 
641
635
  ```ruby
642
- dismiss_confirm do
636
+ accept_confirm 'optional text' do
637
+ click_link('Show Confirm')
638
+ end
639
+ ```
640
+
641
+ ```ruby
642
+ dismiss_confirm 'optional text' do
643
643
  click_link('Show Confirm')
644
644
  end
645
645
  ```
@@ -647,7 +647,13 @@ end
647
647
  You can accept or dismiss prompts as well, and also provide text to fill in for the response:
648
648
 
649
649
  ```ruby
650
- accept_prompt(with: 'Linus Torvalds') do
650
+ accept_prompt('optional text', with: 'Linus Torvalds') do
651
+ click_link('Show Prompt About Linux')
652
+ end
653
+ ```
654
+
655
+ ```ruby
656
+ dismiss_prompt('optional text') do
651
657
  click_link('Show Prompt About Linux')
652
658
  end
653
659
  ```
@@ -697,6 +703,148 @@ Screenshots are saved to `Capybara.save_path`, relative to the app directory.
697
703
  If you have required `capybara/rails`, `Capybara.save_path` will default to
698
704
  `tmp/capybara`.
699
705
 
706
+ ## <a name="selectors"></a>Selectors
707
+
708
+ Helpers and matchers that accept Selectors share a common method signature that
709
+ includes:
710
+
711
+ 1. a positional Name argument
712
+ 2. a positional Locator argument
713
+ 3. keyword Filter arguments
714
+ 4. a predicate Filter block argument
715
+
716
+ These arguments are usually optional in one way or another.
717
+
718
+ ### <a name="selectors-name"></a>Name
719
+
720
+ The name argument determines the Selector to use. The argument is optional when
721
+ a helper explicitly conveys the selector name (for example, [`find_field`][]
722
+ uses `:field`, [`find_link`][] uses `:link`, etc):
723
+
724
+ ```ruby
725
+ page.html # => '<a href="/">Home</a>'
726
+
727
+ page.find(:link) == page.find_link
728
+
729
+ page.html # => '<input>'
730
+
731
+ page.find(:field) == page.find_field
732
+ ```
733
+
734
+ ### <a name="selectors-locator"></a>Locator
735
+
736
+ The locator argument usually represents information that can most meaningfully
737
+ distinguish an element that matches the selector from an element that does not:
738
+
739
+ ```ruby
740
+ page.html # => '<div id="greeting">Hello world</div>'
741
+
742
+ page.find(:css, 'div').text # => 'Hello world'
743
+ page.find(:xpath, './/div').text # => 'Hello world'
744
+ ```
745
+
746
+ General purpose finder methods like [`find`][] and [`all`][] can accept the
747
+ locator as their first positional argument when the method can infer the default
748
+ value from the [`Capybara.default_selector`][] configuration:
749
+
750
+ ```ruby
751
+ page.html # => '<div id="greeting">Hello world</div>'
752
+
753
+ Capybara.default_selector = :css
754
+
755
+ page.find('div').text # => 'Hello world'
756
+
757
+ Capybara.default_selector = :xpath
758
+
759
+ page.find('.//div').text # => 'Hello world'
760
+ ```
761
+
762
+ The locator argument's semantics are context-specific, and depend on the
763
+ selector. The types of arguments are varied. Some selectors support `String` or
764
+ `Regexp` arguments, while others like `:table_row` support `Array<String>` and
765
+ `Hash<String, String>`:
766
+
767
+ ```ruby
768
+ page.html # => '<label for="greeting">Greeting</label>
769
+ <input id="greeting" name="content">'
770
+
771
+ # find by the <input> element's [id] attribute
772
+ page.find(:id, 'greeting') == page.find_by_id('greeting') # => true
773
+
774
+ # find by the <input> element's [id] attribute
775
+ page.find(:field, 'greeting') == page.find_field('greeting') # => true
776
+
777
+ # find by the <input> element's [name] attribute
778
+ page.find(:field, 'content') == page.find_field('content') # => true
779
+
780
+ # find by the <label> element's text
781
+ page.find(:field, 'Greeting') == page.find_field('Greeting') # => true
782
+
783
+ page.html # => '<table>
784
+ <tr>
785
+ <th>A</th>
786
+ <th>B</th>
787
+ </tr>
788
+ <tr>
789
+ <td>1</td>
790
+ <td>2</td>
791
+ </tr>
792
+ </table>'
793
+
794
+ # find by <td> content
795
+ page.find(:table_row, ['1', '2']) == page.find(:css, 'tr:last-of-type') # => true
796
+
797
+ # find by <th> content paired with corresponding <td> content
798
+ page.find(:table_row, 'A' => '1') == page.find(:table_row, 'B' => '2') # => true
799
+ ```
800
+
801
+ ### <a name="selectors-filters"></a> Filters
802
+
803
+ All filters are optional. The supported set of keys is a mixture of both global
804
+ and context-specific filters.The supported types of values depend on the
805
+ context:
806
+
807
+ ```ruby
808
+ page.html # => '<a href="/">Home</a>'
809
+
810
+ # find by the [href] attribute
811
+ page.find_link(href: '/') == page.find_link(text: 'Home') # => true
812
+
813
+ page.html # => '<div id="element" data-attribute="value">Content</div>'
814
+
815
+ # find by the [id] attribute
816
+ page.find(id: 'element') == page.find(text: 'Content') # => true
817
+
818
+ # find by the [data-attribute] attribute
819
+ page.find(:element, 'data-attribute': /value/) == page.find(text: 'Content') # => true
820
+
821
+ page.html # => '<input type="checkbox">'
822
+
823
+ # find by the absence of the [checked] attribute
824
+ page.find_field(checked: false) == page.find_field(unchecked: true) # => true
825
+ ```
826
+
827
+ The predicate block is always optional. When there are results for a selector
828
+ query, the block is called with each item in the result set. When the block
829
+ evaluates to true, the item is included from the result set. Otherwise, the item
830
+ is excluded:
831
+
832
+ ```ruby
833
+ page.html # => '<input role="switch" type="checkbox" checked>'
834
+
835
+ switch = page.find_field { |input| input["role"] == "switch" }
836
+ field = page.find_field(checked: true)
837
+
838
+ switch == field # => true
839
+ ```
840
+
841
+ [`find`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:find
842
+ [`all`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:all
843
+ [`Capybara.default_selector`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2Econfigure
844
+ [`find_by_id`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:find_by_id
845
+ [`find_field`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:find_field
846
+ [`find_link`]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders:find_link
847
+
700
848
  ## <a name="matching"></a>Matching
701
849
 
702
850
  It is possible to customize how Capybara finds elements. At your disposal
@@ -742,7 +890,7 @@ Capybara 1.x, set `Capybara.match` to `:prefer_exact`.
742
890
 
743
891
  ## <a name="transactions-and-database-setup"></a>Transactions and database setup
744
892
 
745
- **Note:** Rails 5.1+ now "safely" shares the database connection between the app and test threads. Therefore,
893
+ **Note:** Rails 5.1+ "safely" shares the database connection between the app and test threads. Therefore,
746
894
  if using Rails 5.1+ you SHOULD be able to ignore this section.
747
895
 
748
896
  Some Capybara drivers need to run against an actual HTTP server. Capybara takes
@@ -777,7 +925,7 @@ expect(page).to have_content('baz')
777
925
  If clicking on the *foo* link triggers an asynchronous process, such as
778
926
  an Ajax request, which, when complete will add the *bar* link to the page,
779
927
  clicking on the *bar* link would be expected to fail, since that link doesn't
780
- exist yet. However Capybara is smart enough to retry finding the link for a
928
+ exist yet. However, Capybara is smart enough to retry finding the link for a
781
929
  brief period of time before giving up and throwing an error. The same is true of
782
930
  the next line, which looks for the content *baz* on the page; it will retry
783
931
  looking for that content for a brief time. You can adjust how long this period
@@ -791,13 +939,25 @@ Be aware that because of this behaviour, the following two statements are **not*
791
939
  equivalent, and you should **always** use the latter!
792
940
 
793
941
  ```ruby
794
- !page.has_xpath?('a')
795
- page.has_no_xpath?('a')
942
+ # Given use of a driver where the page is loaded when visit returns
943
+ # and that Capybara.predicates_wait is `true`
944
+ # consider a page where the `a` tag is removed through AJAX after 1s
945
+ visit(some_path)
946
+ !page.has_xpath?('a') # is false
947
+ page.has_no_xpath?('a') # is true
796
948
  ```
797
949
 
798
- The former would immediately fail because the content has not yet been removed.
799
- Only the latter would wait for the asynchronous process to remove the content
800
- from the page.
950
+ First expression:
951
+ - `has_xpath?('a')` is called right after `visit` returns. It is `true` because the link has not yet been removed
952
+ - Capybara does not wait upon successful predicates/assertions, therefore **has_xpath? returns `true` immediately**
953
+ - The expression returns `false` (because it is negated with the leading `!`)
954
+
955
+ Second expression:
956
+ - `has_no_xpath?('a')` is called right after `visit` returns. It is `false` because the link has not yet been removed.
957
+ - Capybara waits upon failed predicates/assertions, therefore **has_no_xpath? does not return `false` immediately**
958
+ - Capybara will periodically re-check the predicate/assertion up to the `default_max_wait_time` defined
959
+ - after 1s, the predicate becomes `true` (because the link has been removed)
960
+ - The expression returns `true`
801
961
 
802
962
  Capybara's RSpec matchers, however, are smart enough to handle either form.
803
963
  The two following statements are functionally equivalent:
@@ -932,12 +1092,17 @@ Capybara.default_selector = :xpath
932
1092
  find('.//ul/li').text
933
1093
  ```
934
1094
 
935
- Capybara allows you to add custom selectors, which can be very useful if you
936
- find yourself using the same kinds of selectors very often:
1095
+ Capybara provides a number of other built-in selector types. The full list, along
1096
+ with applicable filters, can be seen at [built-in selectors](https://www.rubydoc.info/github/teamcapybara/capybara/Capybara/Selector)
1097
+
1098
+ Capybara also allows you to add custom selectors, which can be very useful if you
1099
+ find yourself using the same kinds of selectors very often. The examples below are very
1100
+ simple, and there are many available features not demonstrated. For more in-depth examples
1101
+ please see Capybaras built-in selector definitions.
937
1102
 
938
1103
  ```ruby
939
- Capybara.add_selector(:id) do
940
- xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
1104
+ Capybara.add_selector(:my_attribute) do
1105
+ xpath { |id| XPath.descendant[XPath.attr(:my_attribute) == id.to_s] }
941
1106
  end
942
1107
 
943
1108
  Capybara.add_selector(:row) do
@@ -954,9 +1119,9 @@ an XPath expression generated through the XPath gem. You can now use these
954
1119
  selectors like this:
955
1120
 
956
1121
  ```ruby
957
- find(:id, 'post_123')
958
- find(:row, 3)
959
- find(:flash_type, :notice)
1122
+ find(:my_attribute, 'post_123') # find element with matching attribute
1123
+ find(:row, 3) # find 3rd row in table body
1124
+ find(:flash_type, :notice) # find element with id of 'flash' and class of 'notice'
960
1125
  ```
961
1126
 
962
1127
  ## <a name="beware-the-xpath--trap"></a>Beware the XPath // trap
@@ -1002,6 +1167,7 @@ end
1002
1167
  However, it's also possible to give this configuration a different name.
1003
1168
 
1004
1169
  ```ruby
1170
+ # Note: Capybara registers this by default
1005
1171
  Capybara.register_driver :selenium_chrome do |app|
1006
1172
  Capybara::Selenium::Driver.new(app, :browser => :chrome)
1007
1173
  end
@@ -1047,7 +1213,14 @@ additional info about how the underlying driver can be configured.
1047
1213
  are testing for specific server errors and using multiple sessions make sure to test for the
1048
1214
  errors using the initial session (usually :default)
1049
1215
 
1050
- ## <a name="threadsafe"></a>"Threadsafe" mode - BETA - may change
1216
+ * If WebMock is enabled, you may encounter a "Too many open files"
1217
+ error. A simple `page.find` call may cause thousands of HTTP requests
1218
+ until the timeout occurs. By default, WebMock will cause each of these
1219
+ requests to spawn a new connection. To work around this problem, you
1220
+ may need to [enable WebMock's `net_http_connect_on_start: true`
1221
+ parameter](https://github.com/bblimke/webmock/blob/master/README.md#connecting-on-nethttpstart).
1222
+
1223
+ ## <a name="threadsafe"></a>"Threadsafe" mode
1051
1224
 
1052
1225
  In normal mode most of Capybara's configuration options are global settings which can cause issues
1053
1226
  if using multiple sessions and wanting to change a setting for only one of the sessions. To provide
@@ -1082,7 +1255,8 @@ To set up a development environment, simply do:
1082
1255
 
1083
1256
  ```bash
1084
1257
  bundle install
1085
- bundle exec rake # run the test suite
1258
+ bundle exec rake # run the test suite with Firefox - requires `geckodriver` to be installed
1259
+ bundle exec rake spec_chrome # run the test suite with Chrome - require `chromedriver` to be installed
1086
1260
  ```
1087
1261
 
1088
1262
  See