capybara 3.0.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 (312) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +891 -12
  4. data/License.txt +1 -1
  5. data/README.md +257 -84
  6. data/lib/capybara/config.rb +29 -10
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/base.rb +22 -4
  9. data/lib/capybara/driver/node.rb +38 -9
  10. data/lib/capybara/dsl.rb +9 -7
  11. data/lib/capybara/helpers.rb +57 -8
  12. data/lib/capybara/minitest/spec.rb +185 -84
  13. data/lib/capybara/minitest.rb +264 -145
  14. data/lib/capybara/node/actions.rb +248 -124
  15. data/lib/capybara/node/base.rb +35 -20
  16. data/lib/capybara/node/document.rb +14 -2
  17. data/lib/capybara/node/document_matchers.rb +13 -15
  18. data/lib/capybara/node/element.rb +350 -113
  19. data/lib/capybara/node/finders.rb +104 -82
  20. data/lib/capybara/node/matchers.rb +363 -157
  21. data/lib/capybara/node/simple.rb +54 -15
  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 +9 -10
  25. data/lib/capybara/queries/base_query.rb +25 -18
  26. data/lib/capybara/queries/current_path_query.rb +16 -6
  27. data/lib/capybara/queries/match_query.rb +11 -0
  28. data/lib/capybara/queries/selector_query.rb +617 -104
  29. data/lib/capybara/queries/sibling_query.rb +9 -7
  30. data/lib/capybara/queries/style_query.rb +45 -0
  31. data/lib/capybara/queries/text_query.rb +40 -22
  32. data/lib/capybara/queries/title_query.rb +2 -2
  33. data/lib/capybara/rack_test/browser.rb +106 -31
  34. data/lib/capybara/rack_test/driver.rb +16 -7
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +74 -49
  37. data/lib/capybara/rack_test/node.rb +120 -47
  38. data/lib/capybara/rails.rb +1 -1
  39. data/lib/capybara/registration_container.rb +41 -0
  40. data/lib/capybara/registrations/drivers.rb +42 -0
  41. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  42. data/lib/capybara/registrations/servers.rb +66 -0
  43. data/lib/capybara/result.rb +87 -53
  44. data/lib/capybara/rspec/features.rb +8 -10
  45. data/lib/capybara/rspec/matcher_proxies.rb +39 -18
  46. data/lib/capybara/rspec/matchers/base.rb +113 -0
  47. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  48. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  49. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  50. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  51. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  52. data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  53. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  54. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  55. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  56. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  57. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  58. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  59. data/lib/capybara/rspec/matchers.rb +142 -315
  60. data/lib/capybara/rspec.rb +3 -2
  61. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  62. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  63. data/lib/capybara/selector/css.rb +85 -8
  64. data/lib/capybara/selector/definition/button.rb +68 -0
  65. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  66. data/lib/capybara/selector/definition/css.rb +10 -0
  67. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  68. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  69. data/lib/capybara/selector/definition/element.rb +28 -0
  70. data/lib/capybara/selector/definition/field.rb +40 -0
  71. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  72. data/lib/capybara/selector/definition/file_field.rb +13 -0
  73. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  74. data/lib/capybara/selector/definition/frame.rb +17 -0
  75. data/lib/capybara/selector/definition/id.rb +6 -0
  76. data/lib/capybara/selector/definition/label.rb +62 -0
  77. data/lib/capybara/selector/definition/link.rb +55 -0
  78. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  79. data/lib/capybara/selector/definition/option.rb +27 -0
  80. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  81. data/lib/capybara/selector/definition/select.rb +81 -0
  82. data/lib/capybara/selector/definition/table.rb +109 -0
  83. data/lib/capybara/selector/definition/table_row.rb +21 -0
  84. data/lib/capybara/selector/definition/xpath.rb +5 -0
  85. data/lib/capybara/selector/definition.rb +280 -0
  86. data/lib/capybara/selector/filter.rb +1 -0
  87. data/lib/capybara/selector/filter_set.rb +72 -28
  88. data/lib/capybara/selector/filters/base.rb +45 -2
  89. data/lib/capybara/selector/filters/expression_filter.rb +5 -6
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +18 -4
  92. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  93. data/lib/capybara/selector/selector.rb +89 -200
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selector.rb +474 -534
  96. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  97. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  98. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  99. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  100. data/lib/capybara/selenium/driver.rb +270 -245
  101. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  102. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  103. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +84 -0
  104. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  105. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  106. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  107. data/lib/capybara/selenium/extensions/find.rb +110 -0
  108. data/lib/capybara/selenium/extensions/html5_drag.rb +229 -0
  109. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  110. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  111. data/lib/capybara/selenium/node.rb +460 -170
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +125 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +110 -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/atoms.rb +18 -0
  118. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  119. data/lib/capybara/selenium/patches/logs.rb +45 -0
  120. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  121. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  122. data/lib/capybara/server/animation_disabler.rb +80 -0
  123. data/lib/capybara/server/checker.rb +44 -0
  124. data/lib/capybara/server/middleware.rb +71 -0
  125. data/lib/capybara/server.rb +58 -67
  126. data/lib/capybara/session/config.rb +40 -6
  127. data/lib/capybara/session/matchers.rb +26 -19
  128. data/lib/capybara/session.rb +252 -194
  129. data/lib/capybara/spec/public/jquery.js +5 -5
  130. data/lib/capybara/spec/public/offset.js +6 -0
  131. data/lib/capybara/spec/public/test.js +126 -8
  132. data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
  133. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
  134. data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
  135. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  136. data/lib/capybara/spec/session/all_spec.rb +135 -44
  137. data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
  138. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
  139. data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
  140. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  141. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  142. data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +76 -52
  143. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +12 -12
  144. data/lib/capybara/spec/session/attach_file_spec.rb +126 -72
  145. data/lib/capybara/spec/session/body_spec.rb +11 -13
  146. data/lib/capybara/spec/session/check_spec.rb +112 -51
  147. data/lib/capybara/spec/session/choose_spec.rb +62 -30
  148. data/lib/capybara/spec/session/click_button_spec.rb +227 -161
  149. data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
  150. data/lib/capybara/spec/session/click_link_spec.rb +89 -55
  151. data/lib/capybara/spec/session/current_scope_spec.rb +8 -8
  152. data/lib/capybara/spec/session/current_url_spec.rb +44 -37
  153. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
  154. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
  155. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  156. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  157. data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
  158. data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
  159. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
  160. data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
  161. data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
  162. data/lib/capybara/spec/session/fill_in_spec.rb +110 -44
  163. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  164. data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
  165. data/lib/capybara/spec/session/find_field_spec.rb +33 -31
  166. data/lib/capybara/spec/session/find_link_spec.rb +42 -14
  167. data/lib/capybara/spec/session/find_spec.rb +251 -142
  168. data/lib/capybara/spec/session/first_spec.rb +45 -44
  169. data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
  170. data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
  171. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
  172. data/lib/capybara/spec/session/frame/within_frame_spec.rb +46 -19
  173. data/lib/capybara/spec/session/go_back_spec.rb +1 -1
  174. data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
  175. data/lib/capybara/spec/session/has_all_selectors_spec.rb +23 -23
  176. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  177. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  178. data/lib/capybara/spec/session/has_button_spec.rb +98 -12
  179. data/lib/capybara/spec/session/has_css_spec.rb +271 -137
  180. data/lib/capybara/spec/session/has_current_path_spec.rb +50 -35
  181. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  182. data/lib/capybara/spec/session/has_field_spec.rb +137 -58
  183. data/lib/capybara/spec/session/has_link_spec.rb +46 -6
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +33 -31
  185. data/lib/capybara/spec/session/has_select_spec.rb +84 -50
  186. data/lib/capybara/spec/session/has_selector_spec.rb +117 -69
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +181 -4
  189. data/lib/capybara/spec/session/has_text_spec.rb +101 -53
  190. data/lib/capybara/spec/session/has_title_spec.rb +19 -14
  191. data/lib/capybara/spec/session/has_xpath_spec.rb +56 -38
  192. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +1 -1
  193. data/lib/capybara/spec/session/html_spec.rb +13 -6
  194. data/lib/capybara/spec/session/matches_style_spec.rb +37 -0
  195. data/lib/capybara/spec/session/node_spec.rb +958 -122
  196. data/lib/capybara/spec/session/node_wrapper_spec.rb +15 -12
  197. data/lib/capybara/spec/session/refresh_spec.rb +9 -7
  198. data/lib/capybara/spec/session/reset_session_spec.rb +65 -37
  199. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +1 -1
  200. data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
  201. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +5 -4
  202. data/lib/capybara/spec/session/save_page_spec.rb +41 -38
  203. data/lib/capybara/spec/session/save_screenshot_spec.rb +13 -11
  204. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  205. data/lib/capybara/spec/session/scroll_spec.rb +119 -0
  206. data/lib/capybara/spec/session/select_spec.rb +102 -76
  207. data/lib/capybara/spec/session/selectors_spec.rb +51 -18
  208. data/lib/capybara/spec/session/sibling_spec.rb +9 -9
  209. data/lib/capybara/spec/session/text_spec.rb +26 -24
  210. data/lib/capybara/spec/session/title_spec.rb +8 -6
  211. data/lib/capybara/spec/session/uncheck_spec.rb +41 -22
  212. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  213. data/lib/capybara/spec/session/visit_spec.rb +79 -53
  214. data/lib/capybara/spec/session/window/become_closed_spec.rb +22 -19
  215. data/lib/capybara/spec/session/window/current_window_spec.rb +4 -3
  216. data/lib/capybara/spec/session/window/open_new_window_spec.rb +4 -3
  217. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +25 -21
  218. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +10 -5
  219. data/lib/capybara/spec/session/window/window_spec.rb +88 -54
  220. data/lib/capybara/spec/session/window/windows_spec.rb +11 -8
  221. data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
  222. data/lib/capybara/spec/session/within_spec.rb +82 -44
  223. data/lib/capybara/spec/spec_helper.rb +46 -52
  224. data/lib/capybara/spec/test_app.rb +148 -41
  225. data/lib/capybara/spec/views/animated.erb +49 -0
  226. data/lib/capybara/spec/views/form.erb +156 -42
  227. data/lib/capybara/spec/views/frame_child.erb +4 -3
  228. data/lib/capybara/spec/views/frame_one.erb +2 -1
  229. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  230. data/lib/capybara/spec/views/frame_two.erb +1 -1
  231. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  232. data/lib/capybara/spec/views/layout.erb +10 -0
  233. data/lib/capybara/spec/views/obscured.erb +47 -0
  234. data/lib/capybara/spec/views/offset.erb +33 -0
  235. data/lib/capybara/spec/views/path.erb +2 -2
  236. data/lib/capybara/spec/views/popup_one.erb +1 -1
  237. data/lib/capybara/spec/views/popup_two.erb +1 -1
  238. data/lib/capybara/spec/views/react.erb +45 -0
  239. data/lib/capybara/spec/views/scroll.erb +21 -0
  240. data/lib/capybara/spec/views/spatial.erb +31 -0
  241. data/lib/capybara/spec/views/tables.erb +68 -1
  242. data/lib/capybara/spec/views/with_animation.erb +81 -0
  243. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  244. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  245. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  246. data/lib/capybara/spec/views/with_hover.erb +3 -2
  247. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  248. data/lib/capybara/spec/views/with_html.erb +46 -11
  249. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  250. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  251. data/lib/capybara/spec/views/with_js.erb +30 -5
  252. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  253. data/lib/capybara/spec/views/with_namespace.erb +21 -0
  254. data/lib/capybara/spec/views/with_scope.erb +2 -2
  255. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  256. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  257. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  258. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  259. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  260. data/lib/capybara/spec/views/with_windows.erb +1 -1
  261. data/lib/capybara/spec/views/within_frames.erb +1 -1
  262. data/lib/capybara/version.rb +1 -1
  263. data/lib/capybara/window.rb +32 -26
  264. data/lib/capybara.rb +128 -104
  265. data/spec/basic_node_spec.rb +59 -34
  266. data/spec/capybara_spec.rb +65 -51
  267. data/spec/counter_spec.rb +35 -0
  268. data/spec/css_builder_spec.rb +101 -0
  269. data/spec/css_splitter_spec.rb +38 -0
  270. data/spec/dsl_spec.rb +84 -55
  271. data/spec/filter_set_spec.rb +24 -7
  272. data/spec/fixtures/certificate.pem +25 -0
  273. data/spec/fixtures/key.pem +27 -0
  274. data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -5
  275. data/spec/fixtures/selenium_driver_rspec_success.rb +5 -5
  276. data/spec/minitest_spec.rb +49 -5
  277. data/spec/minitest_spec_spec.rb +92 -62
  278. data/spec/per_session_config_spec.rb +6 -6
  279. data/spec/rack_test_spec.rb +183 -115
  280. data/spec/regexp_dissassembler_spec.rb +250 -0
  281. data/spec/result_spec.rb +99 -39
  282. data/spec/rspec/features_spec.rb +28 -25
  283. data/spec/rspec/scenarios_spec.rb +10 -6
  284. data/spec/rspec/shared_spec_matchers.rb +418 -364
  285. data/spec/rspec/views_spec.rb +4 -3
  286. data/spec/rspec_matchers_spec.rb +35 -10
  287. data/spec/rspec_spec.rb +109 -85
  288. data/spec/sauce_spec_chrome.rb +43 -0
  289. data/spec/selector_spec.rb +392 -62
  290. data/spec/selenium_spec_chrome.rb +183 -41
  291. data/spec/selenium_spec_chrome_remote.rb +96 -0
  292. data/spec/selenium_spec_edge.rb +41 -8
  293. data/spec/selenium_spec_firefox.rb +228 -0
  294. data/spec/selenium_spec_firefox_remote.rb +94 -0
  295. data/spec/selenium_spec_ie.rb +129 -11
  296. data/spec/selenium_spec_safari.rb +162 -0
  297. data/spec/server_spec.rb +192 -81
  298. data/spec/session_spec.rb +52 -16
  299. data/spec/shared_selenium_node.rb +79 -0
  300. data/spec/shared_selenium_session.rb +460 -123
  301. data/spec/spec_helper.rb +124 -2
  302. data/spec/whitespace_normalizer_spec.rb +54 -0
  303. data/spec/xpath_builder_spec.rb +93 -0
  304. metadata +344 -45
  305. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  306. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  307. data/.yard/yard_extensions.rb +0 -78
  308. data/lib/capybara/rspec/compound.rb +0 -90
  309. data/lib/capybara/spec/session/assert_selector.rb +0 -149
  310. data/lib/capybara/spec/session/source_spec.rb +0 -0
  311. data/lib/capybara/spec/views/with_title.erb +0 -5
  312. data/spec/selenium_spec_marionette.rb +0 -143
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Capybara
4
4
  ##
5
- # The Window class represents a browser window.
5
+ # The {Window} class represents a browser window.
6
6
  #
7
- # You can get an instance of the class by calling either of:
7
+ # You can get an instance of the class by calling any of:
8
8
  #
9
9
  # * {Capybara::Session#windows}
10
10
  # * {Capybara::Session#current_window}
@@ -12,12 +12,12 @@ module Capybara
12
12
  # * {Capybara::Session#switch_to_window}
13
13
  #
14
14
  # Note that some drivers (e.g. Selenium) support getting size of/resizing/closing only
15
- # current window. So if you invoke such method for:
15
+ # current window. So if you invoke such method for:
16
16
  #
17
- # * window that is current, Capybara will make 2 Selenium method invocations
18
- # (get handle of current window + get size/resize/close).
19
- # * window that is not current, Capybara will make 4 Selenium method invocations
20
- # (get handle of current window + switch to given handle + get size/resize/close + switch to original handle)
17
+ # * window that is current, Capybara will make 2 Selenium method invocations
18
+ # (get handle of current window + get size/resize/close).
19
+ # * window that is not current, Capybara will make 4 Selenium method invocations
20
+ # (get handle of current window + switch to given handle + get size/resize/close + switch to original handle)
21
21
  #
22
22
  class Window
23
23
  # @return [String] a string that uniquely identifies window within session
@@ -57,12 +57,12 @@ module Capybara
57
57
  # Close window.
58
58
  #
59
59
  # If this method was called for window that is current, then after calling this method
60
- # future invocations of other Capybara methods should raise
61
- # `session.driver.no_such_window_error` until another window will be switched to.
60
+ # future invocations of other Capybara methods should raise
61
+ # {Capybara::Driver::Base#no_such_window_error session.driver.no_such_window_error} until another window will be switched to.
62
62
  #
63
63
  # @!macro about_current
64
64
  # If this method was called for window that is not current, then after calling this method
65
- # current window shouldn remain the same as it was before calling this method.
65
+ # current window should remain the same as it was before calling this method.
66
66
  #
67
67
  def close
68
68
  @driver.close_window(handle)
@@ -82,8 +82,8 @@ module Capybara
82
82
  # Resize window.
83
83
  #
84
84
  # @macro about_current
85
- # @param width [String] the new window width in pixels
86
- # @param height [String] the new window height in pixels
85
+ # @param width [Integer] the new window width in pixels
86
+ # @param height [Integer] the new window height in pixels
87
87
  #
88
88
  def resize_to(width, height)
89
89
  wait_for_stable_size { @driver.resize_window_to(handle, width, height) }
@@ -93,7 +93,7 @@ module Capybara
93
93
  # Maximize window.
94
94
  #
95
95
  # If a particular driver (e.g. headless driver) doesn't have concept of maximizing it
96
- # may not support this method.
96
+ # may not support this method.
97
97
  #
98
98
  # @macro about_current
99
99
  #
@@ -101,13 +101,24 @@ module Capybara
101
101
  wait_for_stable_size { @driver.maximize_window(handle) }
102
102
  end
103
103
 
104
+ ##
105
+ # Fullscreen window.
106
+ #
107
+ # If a particular driver doesn't have concept of fullscreen it may not support this method.
108
+ #
109
+ # @macro about_current
110
+ #
111
+ def fullscreen
112
+ @driver.fullscreen_window(handle)
113
+ end
114
+
104
115
  def eql?(other)
105
116
  other.is_a?(self.class) && @session == other.session && @handle == other.handle
106
117
  end
107
118
  alias_method :==, :eql?
108
119
 
109
120
  def hash
110
- @session.hash ^ @handle.hash
121
+ [@session, @handle].hash
111
122
  end
112
123
 
113
124
  def inspect
@@ -118,19 +129,14 @@ module Capybara
118
129
 
119
130
  def wait_for_stable_size(seconds = session.config.default_max_wait_time)
120
131
  res = yield if block_given?
121
- prev_size = size
122
- start_time = Capybara::Helpers.monotonic_time
123
- begin
124
- sleep 0.05
125
- cur_size = size
126
- return res if cur_size == prev_size
127
- prev_size = cur_size
128
- end while (Capybara::Helpers.monotonic_time - start_time) < seconds
132
+ timer = Capybara::Helpers.timer(expire_in: seconds)
133
+ loop do
134
+ prev_size = size
135
+ sleep 0.025
136
+ return res if prev_size == size
137
+ break if timer.expired?
138
+ end
129
139
  raise Capybara::WindowError, "Window size not stable within #{seconds} seconds."
130
140
  end
131
-
132
- def raise_unless_current(what)
133
- raise Capybara::WindowError, "#{what} not current window is not possible." unless current?
134
- end
135
141
  end
136
142
  end
data/lib/capybara.rb CHANGED
@@ -5,6 +5,7 @@ require 'nokogiri'
5
5
  require 'xpath'
6
6
  require 'forwardable'
7
7
  require 'capybara/config'
8
+ require 'capybara/registration_container'
8
9
 
9
10
  module Capybara
10
11
  class CapybaraError < StandardError; end
@@ -38,6 +39,8 @@ module Capybara
38
39
  # See {Capybara.configure}
39
40
  # @!method javascript_driver
40
41
  # See {Capybara.configure}
42
+ # @!method use_html5_parsing
43
+ # See {Capybara.configure}
41
44
  Config::OPTIONS.each do |method|
42
45
  def_delegators :config, method, "#{method}="
43
46
  end
@@ -64,31 +67,49 @@ module Capybara
64
67
  # config.app_host = 'http://www.google.com'
65
68
  # end
66
69
  #
67
- # === Configurable options
68
- #
69
- # [app_host = String/nil] The default host to use when giving a relative URL to visit, must be a valid URL e.g. http://www.example.com
70
- # [always_include_port = Boolean] Whether the Rack server's port should automatically be inserted into every visited URL unless another port is explicitly specified (Default: false)
71
- # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
72
- # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
73
- # [raise_server_errors = Boolean] Should errors raised in the server be raised in the tests? (Default: true)
74
- # [server_errors = Array\<Class\>] Error classes that should be raised in the tests if they are raised in the server and Capybara.raise_server_errors is true (Default: [StandardError])
75
- # [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: :css)
76
- # [default_max_wait_time = Numeric] The maximum number of seconds to wait for asynchronous processes to finish (Default: 2)
77
- # [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: true)
78
- # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
79
- # [save_path = String] Where to put pages saved through save_(page|screenshot), save_and_open_(page|screenshot) (Default: Dir.pwd)
80
- # [automatic_label_click = Boolean] Whether Node#choose, Node#check, Node#uncheck will attempt to click the associated label element if the checkbox/radio button are non-visible (Default: false)
81
- # [enable_aria_label = Boolean] Whether fields, links, and buttons will match against aria-label attribute (Default: false)
82
- # [reuse_server = Boolean] Reuse the server thread between multiple sessions using the same app object (Default: true)
83
- # [threadsafe = Boolean] Whether sessions can be configured individually (Default: false)
84
- # [server = Symbol] The name of the registered server to use when running the app under test (Default: :webrick)
85
- #
86
- # === DSL Options
87
- #
88
- # when using capybara/dsl, the following options are also available:
89
- #
90
- # [default_driver = Symbol] The name of the driver to use by default. (Default: :rack_test)
91
- # [javascript_driver = Symbol] The name of a driver to use for JavaScript enabled tests. (Default: :selenium)
70
+ # #### Configurable options
71
+ #
72
+ # - **use_html5_parsing** (Boolean = `false`) - When Nokogiri >= 1.12.0 or `nokogumbo` is installed, whether HTML5 parsing will be used for HTML strings.
73
+ # - **always_include_port** (Boolean = `false`) - Whether the Rack server's port should automatically be inserted into every visited URL
74
+ # unless another port is explicitly specified.
75
+ # - **app_host** (String, `nil`) - The default host to use when giving a relative URL to visit, must be a valid URL e.g. `http://www.example.com`.
76
+ # - **asset_host** (String = `nil`) - Where dynamic assets are hosted - will be prepended to relative asset locations if present.
77
+ # - **automatic_label_click** (Boolean = `false`) - Whether {Capybara::Node::Element#choose Element#choose}, {Capybara::Node::Element#check Element#check},
78
+ # {Capybara::Node::Element#uncheck Element#uncheck} will attempt to click the associated `<label>` element if the checkbox/radio button are non-visible.
79
+ # - **automatic_reload** (Boolean = `true`) - Whether to automatically reload elements as Capybara is waiting.
80
+ # - **default_max_wait_time** (Numeric = `2`) - The maximum number of seconds to wait for asynchronous processes to finish.
81
+ # - **default_normalize_ws** (Boolean = `false`) - Whether text predicates and matchers use normalize whitespace behavior.
82
+ # - **default_retry_interval** (Numeric = `0.01`) - The number of seconds to delay the next check in asynchronous processes.
83
+ # - **default_selector** (`:css`, `:xpath` = `:css`) - Methods which take a selector use the given type by default. See also {Capybara::Selector}.
84
+ # - **default_set_options** (Hash = `{}`) - The default options passed to {Capybara::Node::Element#set Element#set}.
85
+ # - **enable_aria_label** (Boolean = `false`) - Whether fields, links, and buttons will match against `aria-label` attribute.
86
+ # - **enable_aria_role** (Boolean = `false`) - Selectors will check for relevant aria role (currently only `button`).
87
+ # - **exact** (Boolean = `false`) - Whether locators are matched exactly or with substrings. Only affects selector conditions
88
+ # written using the `XPath#is` method.
89
+ # - **exact_text** (Boolean = `false`) - Whether the text matchers and `:text` filter match exactly or on substrings.
90
+ # - **ignore_hidden_elements** (Boolean = `true`) - Whether to ignore hidden elements on the page.
91
+ # - **match** (`:one`, `:first`, `:prefer_exact`, `:smart` = `:smart`) - The matching strategy to find nodes.
92
+ # - **predicates_wait** (Boolean = `true`) - Whether Capybara's predicate matchers use waiting behavior by default.
93
+ # - **raise_server_errors** (Boolean = `true`) - Should errors raised in the server be raised in the tests?
94
+ # - **reuse_server** (Boolean = `true`) - Whether to reuse the server thread between multiple sessions using the same app object.
95
+ # - **run_server** (Boolean = `true`) - Whether to start a Rack server for the given Rack app.
96
+ # - **save_path** (String = `Dir.pwd`) - Where to put pages saved through {Capybara::Session#save_page save_page}, {Capybara::Session#save_screenshot save_screenshot},
97
+ # {Capybara::Session#save_and_open_page save_and_open_page}, or {Capybara::Session#save_and_open_screenshot save_and_open_screenshot}.
98
+ # - **server** (Symbol = `:default` (which uses puma)) - The name of the registered server to use when running the app under test.
99
+ # - **server_port** (Integer) - The port Capybara will run the application server on, if not specified a random port will be used.
100
+ # - **server_host** (String = "127.0.0.1") - The IP address Capybara will bind the application server to. If the test application is to be accessed from an external host, you will want to change this to "0.0.0.0" or to a more specific IP address that your test client can reach.
101
+ # - **server_errors** (Array\<Class> = `[Exception]`) - Error classes that should be raised in the tests if they are raised in the server
102
+ # and {configure raise_server_errors} is `true`.
103
+ # - **test_id** (Symbol, String, `nil` = `nil`) - Optional attribute to match locator against with built-in selectors along with id.
104
+ # - **threadsafe** (Boolean = `false`) - Whether sessions can be configured individually.
105
+ # - **w3c_click_offset** (Boolean = 'true') - Whether click offsets should be from element center (true) or top left (false)
106
+ #
107
+ # #### DSL Options
108
+ #
109
+ # When using `capybara/dsl`, the following options are also available:
110
+ #
111
+ # - **default_driver** (Symbol = `:rack_test`) - The name of the driver to use by default.
112
+ # - **javascript_driver** (Symbol = `:selenium`) - The name of a driver to use for JavaScript enabled tests.
92
113
  #
93
114
  def configure
94
115
  yield config
@@ -108,7 +129,7 @@ module Capybara
108
129
  # @yieldreturn [Capybara::Driver::Base] A Capybara driver instance
109
130
  #
110
131
  def register_driver(name, &block)
111
- drivers[name] = block
132
+ drivers.send(:register, name, block)
112
133
  end
113
134
 
114
135
  ##
@@ -127,7 +148,7 @@ module Capybara
127
148
  # @yieldparam host The host/ip to bind to
128
149
  #
129
150
  def register_server(name, &block)
130
- servers[name.to_sym] = block
151
+ servers.send(:register, name.to_sym, block)
131
152
  end
132
153
 
133
154
  ##
@@ -158,8 +179,8 @@ module Capybara
158
179
  # @param [Symbol] name The name of the selector to add
159
180
  # @yield A block executed in the context of the new {Capybara::Selector}
160
181
  #
161
- def add_selector(name, &block)
162
- Capybara::Selector.add(name, &block)
182
+ def add_selector(name, **options, &block)
183
+ Capybara::Selector.add(name, **options, &block)
163
184
  end
164
185
 
165
186
  ##
@@ -169,7 +190,7 @@ module Capybara
169
190
  # button style (a class) might look like this
170
191
  #
171
192
  # Capybara.modify_selector(:button) do
172
- # filter (:style, valid_values: [:primary, :secondary]) { |node, style| node[:class].split.include? "btn-#{style}" }
193
+ # filter (:btn_style, valid_values: [:primary, :secondary]) { |node, style| node[:class].split.include? "btn-#{style}" }
173
194
  # end
174
195
  #
175
196
  #
@@ -181,11 +202,11 @@ module Capybara
181
202
  end
182
203
 
183
204
  def drivers
184
- @drivers ||= {}
205
+ @drivers ||= RegistrationContainer.new
185
206
  end
186
207
 
187
208
  def servers
188
- @servers ||= {}
209
+ @servers ||= RegistrationContainer.new
189
210
  end
190
211
 
191
212
  # Wraps the given string, which should contain an HTML document or fragment
@@ -194,15 +215,13 @@ module Capybara
194
215
  # any string containing HTML in the exact same way you would query the current document in a Capybara
195
216
  # session.
196
217
  #
197
- # Example: A single element
198
- #
218
+ # @example A single element
199
219
  # node = Capybara.string('<a href="foo">bar</a>')
200
220
  # anchor = node.first('a')
201
221
  # anchor[:href] #=> 'foo'
202
222
  # anchor.text #=> 'bar'
203
223
  #
204
- # Example: Multiple elements
205
- #
224
+ # @example Multiple elements
206
225
  # node = Capybara.string <<-HTML
207
226
  # <ul>
208
227
  # <li id="home">Home</li>
@@ -241,7 +260,7 @@ module Capybara
241
260
  #
242
261
  def current_driver
243
262
  if threadsafe
244
- Thread.current['capybara_current_driver']
263
+ Thread.current.thread_variable_get :capybara_current_driver
245
264
  else
246
265
  @current_driver
247
266
  end || default_driver
@@ -250,7 +269,7 @@ module Capybara
250
269
 
251
270
  def current_driver=(name)
252
271
  if threadsafe
253
- Thread.current['capybara_current_driver'] = name
272
+ Thread.current.thread_variable_set :capybara_current_driver, name
254
273
  else
255
274
  @current_driver = name
256
275
  end
@@ -290,12 +309,12 @@ module Capybara
290
309
 
291
310
  ##
292
311
  #
293
- # The current Capybara::Session based on what is set as Capybara.app and Capybara.current_driver
312
+ # The current {Capybara::Session} based on what is set as {app} and {current_driver}.
294
313
  #
295
314
  # @return [Capybara::Session] The currently used session
296
315
  #
297
316
  def current_session
298
- session_pool["#{current_driver}:#{session_name}:#{app.object_id}"] ||= Capybara::Session.new(current_driver, app)
317
+ specified_session || session_pool["#{current_driver}:#{session_name}:#{app.object_id}"]
299
318
  end
300
319
 
301
320
  ##
@@ -317,7 +336,8 @@ module Capybara
317
336
  #
318
337
  def session_name
319
338
  if threadsafe
320
- Thread.current['capybara_session_name'] ||= :default
339
+ Thread.current.thread_variable_get(:capybara_session_name) ||
340
+ Thread.current.thread_variable_set(:capybara_session_name, :default)
321
341
  else
322
342
  @session_name ||= :default
323
343
  end
@@ -325,7 +345,7 @@ module Capybara
325
345
 
326
346
  def session_name=(name)
327
347
  if threadsafe
328
- Thread.current['capybara_session_name'] = name
348
+ Thread.current.thread_variable_set :capybara_session_name, name
329
349
  else
330
350
  @session_name = name
331
351
  end
@@ -333,22 +353,31 @@ module Capybara
333
353
 
334
354
  ##
335
355
  #
336
- # Yield a block using a specific session name.
356
+ # Yield a block using a specific session name or {Capybara::Session} instance.
337
357
  #
338
- def using_session(name)
358
+ def using_session(name_or_session, &block)
359
+ previous_session = current_session
339
360
  previous_session_info = {
361
+ specified_session: specified_session,
340
362
  session_name: session_name,
341
363
  current_driver: current_driver,
342
364
  app: app
343
365
  }
344
- self.session_name = name
345
- yield
346
- ensure
347
- self.session_name = previous_session_info[:session_name]
348
- if threadsafe
349
- self.current_driver = previous_session_info[:current_driver]
350
- self.app = previous_session_info[:app]
366
+ self.specified_session = self.session_name = nil
367
+ if name_or_session.is_a? Capybara::Session
368
+ self.specified_session = name_or_session
369
+ else
370
+ self.session_name = name_or_session
351
371
  end
372
+
373
+ if block.arity.zero?
374
+ yield
375
+ else
376
+ yield current_session, previous_session
377
+ end
378
+ ensure
379
+ self.session_name, self.specified_session = previous_session_info.values_at(:session_name, :specified_session)
380
+ self.current_driver, self.app = previous_session_info.values_at(:current_driver, :app) if threadsafe
352
381
  end
353
382
 
354
383
  ##
@@ -359,9 +388,21 @@ module Capybara
359
388
  # @return [Nokogiri::HTML::Document] HTML document
360
389
  #
361
390
  def HTML(html) # rubocop:disable Naming/MethodName
362
- Nokogiri::HTML(html).tap do |document|
391
+ # Nokogiri >= 1.12.0 or Nokogumbo installed and allowed for use
392
+ html_parser, using_html5 = if defined?(Nokogiri::HTML5) && Capybara.use_html5_parsing
393
+ [Nokogiri::HTML5, true]
394
+ else
395
+ [defined?(Nokogiri::HTML4) ? Nokogiri::HTML4 : Nokogiri::HTML, false]
396
+ end
397
+
398
+ html_parser.parse(html).tap do |document|
399
+ document.xpath('//template').each do |template|
400
+ # template elements content is not part of the document
401
+ template.inner_html = ''
402
+ end
363
403
  document.xpath('//textarea').each do |textarea|
364
- textarea['_capybara_raw_value'] = textarea.content.sub(/\A\n/, '')
404
+ # The Nokogiri HTML5 parser already returns spec compliant contents
405
+ textarea['_capybara_raw_value'] = using_html5 ? textarea.content : textarea.content.delete_prefix("\n")
365
406
  end
366
407
  end
367
408
  end
@@ -377,7 +418,25 @@ module Capybara
377
418
  end
378
419
 
379
420
  def session_pool
380
- @session_pool ||= {}
421
+ @session_pool ||= Hash.new do |hash, name|
422
+ hash[name] = Capybara::Session.new(current_driver, app)
423
+ end
424
+ end
425
+
426
+ def specified_session
427
+ if threadsafe
428
+ Thread.current.thread_variable_get :capybara_specified_session
429
+ else
430
+ @specified_session ||= nil
431
+ end
432
+ end
433
+
434
+ def specified_session=(session)
435
+ if threadsafe
436
+ Thread.current.thread_variable_set :capybara_specified_session, session
437
+ else
438
+ @specified_session = session
439
+ end
381
440
  end
382
441
  end
383
442
 
@@ -405,6 +464,8 @@ module Capybara
405
464
  require 'capybara/queries/match_query'
406
465
  require 'capybara/queries/ancestor_query'
407
466
  require 'capybara/queries/sibling_query'
467
+ require 'capybara/queries/style_query'
468
+ require 'capybara/queries/active_element_query'
408
469
 
409
470
  require 'capybara/node/finders'
410
471
  require 'capybara/node/matchers'
@@ -422,40 +483,14 @@ module Capybara
422
483
  require 'capybara/rack_test/node'
423
484
  require 'capybara/rack_test/form'
424
485
  require 'capybara/rack_test/browser'
425
- require 'capybara/rack_test/css_handlers.rb'
486
+ require 'capybara/rack_test/css_handlers'
426
487
 
427
488
  require 'capybara/selenium/node'
428
489
  require 'capybara/selenium/driver'
429
490
  end
430
491
 
431
- Capybara.register_server :default do |app, port, _host|
432
- Capybara.run_default_server(app, port)
433
- end
434
-
435
- Capybara.register_server :webrick do |app, port, host, **options|
436
- require 'rack/handler/webrick'
437
- Rack::Handler::WEBrick.run(app, { Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log.new(nil, 0) }.merge(options))
438
- end
439
-
440
- Capybara.register_server :puma do |app, port, host, **options|
441
- require 'rack/handler/puma'
442
- # If we just run the Puma Rack handler it installs signal handlers which prevent us from being able to interrupt tests.
443
- # Therefore construct and run the Server instance ourselves.
444
- # Rack::Handler::Puma.run(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
445
-
446
- conf = Rack::Handler::Puma.config(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
447
- events = conf.options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
448
-
449
- events.log "Capybara starting Puma..."
450
- events.log "* Version #{Puma::Const::PUMA_VERSION} , codename: #{Puma::Const::CODE_NAME}"
451
- events.log "* Min threads: #{conf.options[:min_threads]}, max threads: #{conf.options[:max_threads]}"
452
-
453
- Puma::Server.new(conf.app, events, conf.options).tap do |s|
454
- s.binder.parse conf.options[:binds], s.events
455
- s.min_threads = conf.options[:min_threads]
456
- s.max_threads = conf.options[:max_threads]
457
- end.run.join
458
- end
492
+ require 'capybara/registrations/servers'
493
+ require 'capybara/registrations/drivers'
459
494
 
460
495
  Capybara.configure do |config|
461
496
  config.always_include_port = false
@@ -463,35 +498,24 @@ Capybara.configure do |config|
463
498
  config.server = :default
464
499
  config.default_selector = :css
465
500
  config.default_max_wait_time = 2
501
+ config.default_retry_interval = 0.01
466
502
  config.ignore_hidden_elements = true
467
- config.default_host = "http://www.example.com"
503
+ config.default_host = 'http://www.example.com'
468
504
  config.automatic_reload = true
469
505
  config.match = :smart
470
506
  config.exact = false
471
507
  config.exact_text = false
472
508
  config.raise_server_errors = true
473
- config.server_errors = [StandardError]
509
+ config.server_errors = [Exception]
474
510
  config.visible_text_only = false
475
511
  config.automatic_label_click = false
476
512
  config.enable_aria_label = false
513
+ config.enable_aria_role = false
477
514
  config.reuse_server = true
478
- end
479
-
480
- Capybara.register_driver :rack_test do |app|
481
- Capybara::RackTest::Driver.new(app)
482
- end
483
-
484
- Capybara.register_driver :selenium do |app|
485
- Capybara::Selenium::Driver.new(app)
486
- end
487
-
488
- Capybara.register_driver :selenium_chrome do |app|
489
- Capybara::Selenium::Driver.new(app, browser: :chrome)
490
- end
491
-
492
- Capybara.register_driver :selenium_chrome_headless do |app|
493
- browser_options = ::Selenium::WebDriver::Chrome::Options.new
494
- browser_options.args << '--headless'
495
- browser_options.args << '--disable-gpu'
496
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
515
+ config.default_set_options = {}
516
+ config.test_id = nil
517
+ config.predicates_wait = true
518
+ config.default_normalize_ws = false
519
+ config.use_html5_parsing = false
520
+ config.w3c_click_offset = true
497
521
  end