capybara 2.18.0 → 3.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (315) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +889 -12
  4. data/License.txt +1 -1
  5. data/README.md +108 -78
  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 +173 -83
  13. data/lib/capybara/minitest.rb +219 -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 +149 -137
  20. data/lib/capybara/node/matchers.rb +369 -209
  21. data/lib/capybara/node/simple.rb +59 -26
  22. data/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/lib/capybara/queries/ancestor_query.rb +12 -9
  24. data/lib/capybara/queries/base_query.rb +39 -28
  25. data/lib/capybara/queries/current_path_query.rb +21 -27
  26. data/lib/capybara/queries/match_query.rb +14 -7
  27. data/lib/capybara/queries/selector_query.rb +658 -149
  28. data/lib/capybara/queries/sibling_query.rb +11 -9
  29. data/lib/capybara/queries/style_query.rb +45 -0
  30. data/lib/capybara/queries/text_query.rb +56 -38
  31. data/lib/capybara/queries/title_query.rb +8 -11
  32. data/lib/capybara/rack_test/browser.rb +113 -42
  33. data/lib/capybara/rack_test/css_handlers.rb +6 -4
  34. data/lib/capybara/rack_test/driver.rb +22 -17
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +93 -58
  37. data/lib/capybara/rack_test/node.rb +188 -81
  38. data/lib/capybara/rails.rb +3 -7
  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 +53 -0
  43. data/lib/capybara/result.rb +96 -62
  44. data/lib/capybara/rspec/features.rb +17 -50
  45. data/lib/capybara/rspec/matcher_proxies.rb +52 -15
  46. data/lib/capybara/rspec/matchers/base.rb +111 -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 +77 -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 -311
  60. data/lib/capybara/rspec.rb +7 -11
  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 +89 -17
  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 +54 -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 +2 -17
  87. data/lib/capybara/selector/filter_set.rb +80 -33
  88. data/lib/capybara/selector/filters/base.rb +50 -6
  89. data/lib/capybara/selector/filters/expression_filter.rb +8 -26
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +16 -12
  92. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  93. data/lib/capybara/selector/selector.rb +93 -210
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selector.rb +227 -526
  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 +332 -261
  101. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  102. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
  103. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -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 +226 -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/logger_suppressor.rb +44 -0
  112. data/lib/capybara/selenium/node.rb +545 -144
  113. data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
  114. data/lib/capybara/selenium/nodes/edge_node.rb +104 -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/action_pauser.rb +26 -0
  119. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  120. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  121. data/lib/capybara/selenium/patches/logs.rb +45 -0
  122. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  123. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  124. data/lib/capybara/server/animation_disabler.rb +81 -0
  125. data/lib/capybara/server/checker.rb +44 -0
  126. data/lib/capybara/server/middleware.rb +71 -0
  127. data/lib/capybara/server.rb +59 -67
  128. data/lib/capybara/session/config.rb +81 -67
  129. data/lib/capybara/session/matchers.rb +28 -20
  130. data/lib/capybara/session.rb +336 -365
  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 +147 -12
  134. data/lib/capybara/spec/session/accept_alert_spec.rb +12 -11
  135. data/lib/capybara/spec/session/accept_confirm_spec.rb +6 -5
  136. data/lib/capybara/spec/session/accept_prompt_spec.rb +10 -10
  137. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  138. data/lib/capybara/spec/session/all_spec.rb +160 -56
  139. data/lib/capybara/spec/session/ancestor_spec.rb +27 -24
  140. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +68 -38
  141. data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
  142. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  143. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  144. data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
  145. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +22 -12
  146. data/lib/capybara/spec/session/attach_file_spec.rb +144 -69
  147. data/lib/capybara/spec/session/body_spec.rb +12 -13
  148. data/lib/capybara/spec/session/check_spec.rb +117 -55
  149. data/lib/capybara/spec/session/choose_spec.rb +64 -31
  150. data/lib/capybara/spec/session/click_button_spec.rb +231 -173
  151. data/lib/capybara/spec/session/click_link_or_button_spec.rb +55 -35
  152. data/lib/capybara/spec/session/click_link_spec.rb +82 -58
  153. data/lib/capybara/spec/session/current_scope_spec.rb +12 -11
  154. data/lib/capybara/spec/session/current_url_spec.rb +57 -39
  155. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +4 -4
  156. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +3 -2
  157. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  158. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  159. data/lib/capybara/spec/session/element/match_xpath_spec.rb +9 -7
  160. data/lib/capybara/spec/session/element/matches_selector_spec.rb +71 -57
  161. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +8 -7
  162. data/lib/capybara/spec/session/evaluate_script_spec.rb +29 -8
  163. data/lib/capybara/spec/session/execute_script_spec.rb +10 -8
  164. data/lib/capybara/spec/session/fill_in_spec.rb +134 -43
  165. data/lib/capybara/spec/session/find_button_spec.rb +25 -24
  166. data/lib/capybara/spec/session/find_by_id_spec.rb +10 -9
  167. data/lib/capybara/spec/session/find_field_spec.rb +37 -41
  168. data/lib/capybara/spec/session/find_link_spec.rb +36 -17
  169. data/lib/capybara/spec/session/find_spec.rb +251 -144
  170. data/lib/capybara/spec/session/first_spec.rb +79 -51
  171. data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  172. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  173. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +33 -20
  174. data/lib/capybara/spec/session/frame/within_frame_spec.rb +50 -32
  175. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  176. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  177. data/lib/capybara/spec/session/has_all_selectors_spec.rb +31 -31
  178. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  179. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  180. data/lib/capybara/spec/session/has_button_spec.rb +100 -13
  181. data/lib/capybara/spec/session/has_css_spec.rb +272 -137
  182. data/lib/capybara/spec/session/has_current_path_spec.rb +59 -60
  183. data/lib/capybara/spec/session/has_field_spec.rb +139 -59
  184. data/lib/capybara/spec/session/has_link_spec.rb +43 -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 +172 -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 +35 -0
  196. data/lib/capybara/spec/session/node_spec.rb +1002 -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 +117 -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 +42 -22
  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 +53 -43
  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 +154 -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 +67 -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 +129 -103
  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 +45 -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 +102 -50
  283. data/spec/rspec/features_spec.rb +37 -31
  284. data/spec/rspec/scenarios_spec.rb +9 -7
  285. data/spec/rspec/shared_spec_matchers.rb +449 -422
  286. data/spec/rspec/views_spec.rb +5 -3
  287. data/spec/rspec_matchers_spec.rb +27 -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 +186 -40
  292. data/spec/selenium_spec_chrome_remote.rb +103 -0
  293. data/spec/selenium_spec_edge.rb +49 -0
  294. data/spec/selenium_spec_firefox.rb +194 -41
  295. data/spec/selenium_spec_firefox_remote.rb +82 -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 +201 -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 +474 -122
  302. data/spec/spec_helper.rb +93 -7
  303. data/spec/xpath_builder_spec.rb +93 -0
  304. metadata +360 -73
  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/query.rb +0 -7
  309. data/lib/capybara/rspec/compound.rb +0 -95
  310. data/lib/capybara/spec/session/assert_current_path.rb +0 -72
  311. data/lib/capybara/spec/session/assert_selector.rb +0 -148
  312. data/lib/capybara/spec/session/assert_text.rb +0 -234
  313. data/lib/capybara/spec/session/source_spec.rb +0 -0
  314. data/lib/capybara/spec/views/with_title.erb +0 -5
  315. data/spec/selenium_spec_marionette.rb +0 -127
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Capybara
3
4
  ##
4
- # The Window class represents a browser window.
5
+ # The {Window} class represents a browser window.
5
6
  #
6
- # 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:
7
8
  #
8
9
  # * {Capybara::Session#windows}
9
10
  # * {Capybara::Session#current_window}
@@ -11,12 +12,12 @@ module Capybara
11
12
  # * {Capybara::Session#switch_to_window}
12
13
  #
13
14
  # Note that some drivers (e.g. Selenium) support getting size of/resizing/closing only
14
- # current window. So if you invoke such method for:
15
+ # current window. So if you invoke such method for:
15
16
  #
16
- # * window that is current, Capybara will make 2 Selenium method invocations
17
- # (get handle of current window + get size/resize/close).
18
- # * window that is not current, Capybara will make 4 Selenium method invocations
19
- # (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)
20
21
  #
21
22
  class Window
22
23
  # @return [String] a string that uniquely identifies window within session
@@ -56,12 +57,12 @@ module Capybara
56
57
  # Close window.
57
58
  #
58
59
  # If this method was called for window that is current, then after calling this method
59
- # future invocations of other Capybara methods should raise
60
- # `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.
61
62
  #
62
63
  # @!macro about_current
63
64
  # If this method was called for window that is not current, then after calling this method
64
- # 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.
65
66
  #
66
67
  def close
67
68
  @driver.close_window(handle)
@@ -81,8 +82,8 @@ module Capybara
81
82
  # Resize window.
82
83
  #
83
84
  # @macro about_current
84
- # @param width [String] the new window width in pixels
85
- # @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
86
87
  #
87
88
  def resize_to(width, height)
88
89
  wait_for_stable_size { @driver.resize_window_to(handle, width, height) }
@@ -92,7 +93,7 @@ module Capybara
92
93
  # Maximize window.
93
94
  #
94
95
  # If a particular driver (e.g. headless driver) doesn't have concept of maximizing it
95
- # may not support this method.
96
+ # may not support this method.
96
97
  #
97
98
  # @macro about_current
98
99
  #
@@ -100,41 +101,42 @@ module Capybara
100
101
  wait_for_stable_size { @driver.maximize_window(handle) }
101
102
  end
102
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
+
103
115
  def eql?(other)
104
- other.kind_of?(self.class) && @session == other.session && @handle == other.handle
116
+ other.is_a?(self.class) && @session == other.session && @handle == other.handle
105
117
  end
106
118
  alias_method :==, :eql?
107
119
 
108
120
  def hash
109
- @session.hash ^ @handle.hash
121
+ [@session, @handle].hash
110
122
  end
111
123
 
112
124
  def inspect
113
125
  "#<Window @handle=#{@handle.inspect}>"
114
126
  end
115
127
 
116
- private
128
+ private
117
129
 
118
- def wait_for_stable_size(seconds=session.config.default_max_wait_time)
130
+ def wait_for_stable_size(seconds = session.config.default_max_wait_time)
119
131
  res = yield if block_given?
120
- prev_size = size
121
- start_time = Capybara::Helpers.monotonic_time
122
- begin
123
- sleep 0.05
124
- cur_size = size
125
- return res if cur_size == prev_size
126
- prev_size = cur_size
127
- end while (Capybara::Helpers.monotonic_time - start_time) < seconds
128
- #TODO raise error in 3.0
129
- #raise Capybara::WindowError, "Window size not stable."
130
- warn "Window size not stable in #{seconds} seconds. This will raise an exception in a future version of Capybara"
131
- return res
132
- end
133
-
134
- def raise_unless_current(what)
135
- unless current?
136
- raise Capybara::WindowError, "#{what} not current window is not possible."
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?
137
138
  end
139
+ raise Capybara::WindowError, "Window size not stable within #{seconds} seconds."
138
140
  end
139
141
  end
140
142
  end
data/lib/capybara.rb CHANGED
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'timeout'
3
4
  require 'nokogiri'
4
5
  require 'xpath'
5
6
  require 'forwardable'
6
7
  require 'capybara/config'
8
+ require 'capybara/registration_container'
7
9
 
8
10
  module Capybara
9
11
  class CapybaraError < StandardError; end
@@ -21,7 +23,6 @@ module Capybara
21
23
  class WindowError < CapybaraError; end
22
24
  class ReadOnlyElementError < CapybaraError; end
23
25
 
24
-
25
26
  class << self
26
27
  extend Forwardable
27
28
 
@@ -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
@@ -51,8 +54,6 @@ module Capybara
51
54
  # See {Capybara.configure}
52
55
  # @!method always_include_port
53
56
  # See {Capybara.configure}
54
- # @!method wait_on_first_by_default
55
- # See {Capybara.configure}
56
57
  SessionConfig::OPTIONS.each do |method|
57
58
  def_delegators :config, method, "#{method}="
58
59
  end
@@ -66,35 +67,52 @@ module Capybara
66
67
  # config.app_host = 'http://www.google.com'
67
68
  # end
68
69
  #
69
- # === Configurable options
70
- #
71
- # [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
72
- # [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)
73
- # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
74
- # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
75
- # [raise_server_errors = Boolean] Should errors raised in the server be raised in the tests? (Default: true)
76
- # [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])
77
- # [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: :css)
78
- # [default_max_wait_time = Numeric] The maximum number of seconds to wait for asynchronous processes to finish (Default: 2)
79
- # [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: true)
80
- # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
81
- # [save_path = String] Where to put pages saved through save_(page|screenshot), save_and_open_(page|screenshot) (Default: Dir.pwd)
82
- # [wait_on_first_by_default = Boolean] Whether Node#first defaults to Capybara waiting behavior for at least 1 element to match (Default: false)
83
- # [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)
84
- # [enable_aria_label = Boolean] Whether fields, links, and buttons will match against aria-label attribute (Default: false)
85
- # [reuse_server = Boolean] Reuse the server thread between multiple sessions using the same app object (Default: true)
86
- # [threadsafe = Boolean] Whether sessions can be configured individually (Default: false)
87
- # [server = Symbol] The name of the registered server to use when running the app under test (Default: :webrick)
88
- #
89
- # === DSL Options
90
- #
91
- # when using capybara/dsl, the following options are also available:
92
- #
93
- # [default_driver = Symbol] The name of the driver to use by default. (Default: :rack_test)
94
- # [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.
95
113
  #
96
114
  def configure
97
- yield ConfigureDeprecator.new(config)
115
+ yield config
98
116
  end
99
117
 
100
118
  ##
@@ -111,7 +129,7 @@ module Capybara
111
129
  # @yieldreturn [Capybara::Driver::Base] A Capybara driver instance
112
130
  #
113
131
  def register_driver(name, &block)
114
- drivers[name] = block
132
+ drivers.send(:register, name, block)
115
133
  end
116
134
 
117
135
  ##
@@ -128,10 +146,9 @@ module Capybara
128
146
  # @yieldparam [<Rack>] app The rack application that this server will contain.
129
147
  # @yieldparam port The port number the server should listen on
130
148
  # @yieldparam host The host/ip to bind to
131
- # @yieldreturn [Capybara::Driver::Base] A Capybara driver instance
132
149
  #
133
150
  def register_server(name, &block)
134
- servers[name.to_sym] = block
151
+ servers.send(:register, name.to_sym, block)
135
152
  end
136
153
 
137
154
  ##
@@ -162,8 +179,8 @@ module Capybara
162
179
  # @param [Symbol] name The name of the selector to add
163
180
  # @yield A block executed in the context of the new {Capybara::Selector}
164
181
  #
165
- def add_selector(name, &block)
166
- Capybara::Selector.add(name, &block)
182
+ def add_selector(name, **options, &block)
183
+ Capybara::Selector.add(name, **options, &block)
167
184
  end
168
185
 
169
186
  ##
@@ -173,7 +190,7 @@ module Capybara
173
190
  # button style (a class) might look like this
174
191
  #
175
192
  # Capybara.modify_selector(:button) do
176
- # 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}" }
177
194
  # end
178
195
  #
179
196
  #
@@ -185,30 +202,26 @@ module Capybara
185
202
  end
186
203
 
187
204
  def drivers
188
- @drivers ||= {}
205
+ @drivers ||= RegistrationContainer.new
189
206
  end
190
207
 
191
208
  def servers
192
- @servers ||= {}
209
+ @servers ||= RegistrationContainer.new
193
210
  end
194
211
 
195
- ##
196
- #
197
212
  # Wraps the given string, which should contain an HTML document or fragment
198
213
  # in a {Capybara::Node::Simple} which exposes all {Capybara::Node::Matchers},
199
214
  # {Capybara::Node::Finders} and {Capybara::Node::DocumentMatchers}. This allows you to query
200
215
  # any string containing HTML in the exact same way you would query the current document in a Capybara
201
216
  # session.
202
217
  #
203
- # Example: A single element
204
- #
218
+ # @example A single element
205
219
  # node = Capybara.string('<a href="foo">bar</a>')
206
220
  # anchor = node.first('a')
207
221
  # anchor[:href] #=> 'foo'
208
222
  # anchor.text #=> 'bar'
209
223
  #
210
- # Example: Multiple elements
211
- #
224
+ # @example Multiple elements
212
225
  # node = Capybara.string <<-HTML
213
226
  # <ul>
214
227
  # <li id="home">Home</li>
@@ -238,7 +251,7 @@ module Capybara
238
251
  # @param [Integer] port The port to run the application on
239
252
  #
240
253
  def run_default_server(app, port)
241
- servers[:webrick].call(app, port, server_host)
254
+ servers[:puma].call(app, port, server_host)
242
255
  end
243
256
 
244
257
  ##
@@ -296,12 +309,12 @@ module Capybara
296
309
 
297
310
  ##
298
311
  #
299
- # 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}.
300
313
  #
301
314
  # @return [Capybara::Session] The currently used session
302
315
  #
303
316
  def current_session
304
- 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}"]
305
318
  end
306
319
 
307
320
  ##
@@ -310,7 +323,7 @@ module Capybara
310
323
  # as cookies.
311
324
  #
312
325
  def reset_sessions!
313
- #reset in reverse so sessions that started servers are reset last
326
+ # reset in reverse so sessions that started servers are reset last
314
327
  session_pool.reverse_each { |_mode, session| session.reset! }
315
328
  end
316
329
  alias_method :reset!, :reset_sessions!
@@ -339,22 +352,31 @@ module Capybara
339
352
 
340
353
  ##
341
354
  #
342
- # Yield a block using a specific session name.
355
+ # Yield a block using a specific session name or {Capybara::Session} instance.
343
356
  #
344
- def using_session(name)
357
+ def using_session(name_or_session, &block)
358
+ previous_session = current_session
345
359
  previous_session_info = {
360
+ specified_session: specified_session,
346
361
  session_name: session_name,
347
362
  current_driver: current_driver,
348
363
  app: app
349
364
  }
350
- self.session_name = name
351
- yield
352
- ensure
353
- self.session_name = previous_session_info[:session_name]
354
- if threadsafe
355
- self.current_driver = previous_session_info[:current_driver]
356
- self.app = previous_session_info[:app]
365
+ self.specified_session = self.session_name = nil
366
+ if name_or_session.is_a? Capybara::Session
367
+ self.specified_session = name_or_session
368
+ else
369
+ self.session_name = name_or_session
370
+ end
371
+
372
+ if block.arity.zero?
373
+ yield
374
+ else
375
+ yield current_session, previous_session
357
376
  end
377
+ ensure
378
+ self.session_name, self.specified_session = previous_session_info.values_at(:session_name, :specified_session)
379
+ self.current_driver, self.app = previous_session_info.values_at(:current_driver, :app) if threadsafe
358
380
  end
359
381
 
360
382
  ##
@@ -364,10 +386,22 @@ module Capybara
364
386
  # @param [String] html The raw html
365
387
  # @return [Nokogiri::HTML::Document] HTML document
366
388
  #
367
- def HTML(html)
368
- Nokogiri::HTML(html).tap do |document|
389
+ def HTML(html) # rubocop:disable Naming/MethodName
390
+ # Nokogiri >= 1.12.0 or Nokogumbo installed and allowed for use
391
+ html_parser, using_html5 = if defined?(Nokogiri::HTML5) && Capybara.use_html5_parsing
392
+ [Nokogiri::HTML5, true]
393
+ else
394
+ [defined?(Nokogiri::HTML4) ? Nokogiri::HTML4 : Nokogiri::HTML, false]
395
+ end
396
+
397
+ html_parser.parse(html).tap do |document|
398
+ document.xpath('//template').each do |template|
399
+ # template elements content is not part of the document
400
+ template.inner_html = ''
401
+ end
369
402
  document.xpath('//textarea').each do |textarea|
370
- textarea['_capybara_raw_value'] = textarea.content.sub(/\A\n/,'')
403
+ # The Nokogiri HTML5 parser already returns spec compliant contents
404
+ textarea['_capybara_raw_value'] = using_html5 ? textarea.content : textarea.content.delete_prefix("\n")
371
405
  end
372
406
  end
373
407
  end
@@ -376,18 +410,32 @@ module Capybara
376
410
  config.session_options
377
411
  end
378
412
 
379
- def included(base)
380
- base.send(:include, Capybara::DSL)
381
- warn "`include Capybara` is deprecated. Please use `include Capybara::DSL` instead."
382
- end
383
-
384
413
  private
414
+
385
415
  def config
386
416
  @config ||= Capybara::Config.new
387
417
  end
388
418
 
389
419
  def session_pool
390
- @session_pool ||= {}
420
+ @session_pool ||= Hash.new do |hash, name|
421
+ hash[name] = Capybara::Session.new(current_driver, app)
422
+ end
423
+ end
424
+
425
+ def specified_session
426
+ if threadsafe
427
+ Thread.current['capybara_specified_session']
428
+ else
429
+ @specified_session ||= nil
430
+ end
431
+ end
432
+
433
+ def specified_session=(session)
434
+ if threadsafe
435
+ Thread.current['capybara_specified_session'] = session
436
+ else
437
+ @specified_session = session
438
+ end
391
439
  end
392
440
  end
393
441
 
@@ -415,7 +463,8 @@ module Capybara
415
463
  require 'capybara/queries/match_query'
416
464
  require 'capybara/queries/ancestor_query'
417
465
  require 'capybara/queries/sibling_query'
418
- require 'capybara/query'
466
+ require 'capybara/queries/style_query'
467
+ require 'capybara/queries/active_element_query'
419
468
 
420
469
  require 'capybara/node/finders'
421
470
  require 'capybara/node/matchers'
@@ -433,25 +482,14 @@ module Capybara
433
482
  require 'capybara/rack_test/node'
434
483
  require 'capybara/rack_test/form'
435
484
  require 'capybara/rack_test/browser'
436
- require 'capybara/rack_test/css_handlers.rb'
485
+ require 'capybara/rack_test/css_handlers'
437
486
 
438
487
  require 'capybara/selenium/node'
439
488
  require 'capybara/selenium/driver'
440
489
  end
441
490
 
442
- Capybara.register_server :default do |app, port, _host|
443
- Capybara.run_default_server(app, port)
444
- end
445
-
446
- Capybara.register_server :webrick do |app, port, host, options={}|
447
- require 'rack/handler/webrick'
448
- Rack::Handler::WEBrick.run(app, {Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log::new(nil, 0)}.merge(options))
449
- end
450
-
451
- Capybara.register_server :puma do |app, port, host, options={}|
452
- require 'rack/handler/puma'
453
- Rack::Handler::Puma.run(app, {Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false}.merge(options))
454
- end
491
+ require 'capybara/registrations/servers'
492
+ require 'capybara/registrations/drivers'
455
493
 
456
494
  Capybara.configure do |config|
457
495
  config.always_include_port = false
@@ -459,36 +497,24 @@ Capybara.configure do |config|
459
497
  config.server = :default
460
498
  config.default_selector = :css
461
499
  config.default_max_wait_time = 2
500
+ config.default_retry_interval = 0.01
462
501
  config.ignore_hidden_elements = true
463
- config.default_host = "http://www.example.com"
502
+ config.default_host = 'http://www.example.com'
464
503
  config.automatic_reload = true
465
504
  config.match = :smart
466
505
  config.exact = false
467
506
  config.exact_text = false
468
507
  config.raise_server_errors = true
469
- config.server_errors = [StandardError]
508
+ config.server_errors = [Exception]
470
509
  config.visible_text_only = false
471
- config.wait_on_first_by_default = false
472
510
  config.automatic_label_click = false
473
511
  config.enable_aria_label = false
512
+ config.enable_aria_role = false
474
513
  config.reuse_server = true
475
- end
476
-
477
- Capybara.register_driver :rack_test do |app|
478
- Capybara::RackTest::Driver.new(app)
479
- end
480
-
481
- Capybara.register_driver :selenium do |app|
482
- Capybara::Selenium::Driver.new(app)
483
- end
484
-
485
- Capybara.register_driver :selenium_chrome do |app|
486
- Capybara::Selenium::Driver.new(app, :browser => :chrome)
487
- end
488
-
489
- Capybara.register_driver :selenium_chrome_headless do |app|
490
- browser_options = ::Selenium::WebDriver::Chrome::Options.new()
491
- browser_options.args << '--headless'
492
- browser_options.args << '--disable-gpu'
493
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
514
+ config.default_set_options = {}
515
+ config.test_id = nil
516
+ config.predicates_wait = true
517
+ config.default_normalize_ws = false
518
+ config.use_html5_parsing = false
519
+ config.w3c_click_offset = true
494
520
  end