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
data/spec/server_spec.rb CHANGED
@@ -3,194 +3,305 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe Capybara::Server do
6
- it "should spool up a rack server" do
7
- @app = proc { |_env| [200, {}, ["Hello Server!"]] }
8
- @server = Capybara::Server.new(@app).boot
6
+ it 'should spool up a rack server' do
7
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
8
+ server = described_class.new(app).boot
9
9
 
10
- @res = Net::HTTP.start(@server.host, @server.port) { |http| http.get('/') }
10
+ res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
11
11
 
12
- expect(@res.body).to include('Hello Server')
12
+ expect(res.body).to include('Hello Server')
13
13
  end
14
14
 
15
- it "should do nothing when no server given" do
15
+ it 'should do nothing when no server given' do
16
16
  expect do
17
- @server = Capybara::Server.new(nil).boot
17
+ described_class.new(nil).boot
18
18
  end.not_to raise_error
19
19
  end
20
20
 
21
- it "should bind to the specified host" do
21
+ it 'should bind to the specified host' do
22
22
  # TODO: travis with jruby in container mode has an issue with this test
23
+ skip 'This platform has an issue with this test' if (ENV.fetch('TRAVIS', nil) && (RUBY_ENGINE == 'jruby')) || Gem.win_platform?
24
+
23
25
  begin
24
26
  app = proc { |_env| [200, {}, ['Hello Server!']] }
25
27
 
26
28
  Capybara.server_host = '127.0.0.1'
27
- server = Capybara::Server.new(app).boot
29
+ server = described_class.new(app).boot
28
30
  res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
29
31
  expect(res).to eq('Hello Server!')
30
32
 
31
33
  Capybara.server_host = '0.0.0.0'
32
- server = Capybara::Server.new(app).boot
34
+ server = described_class.new(app).boot
33
35
  res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
34
36
  expect(res).to eq('Hello Server!')
35
37
  ensure
36
38
  Capybara.server_host = nil
37
39
  end
38
- end unless ENV['TRAVIS'] && (RUBY_ENGINE == 'jruby') or Gem.win_platform?
40
+ end
39
41
 
40
- it "should use specified port" do
42
+ it 'should use specified port' do
41
43
  Capybara.server_port = 22789
42
44
 
43
- @app = proc { |_env| [200, {}, ["Hello Server!"]] }
44
- @server = Capybara::Server.new(@app).boot
45
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
46
+ server = described_class.new(app).boot
45
47
 
46
- @res = Net::HTTP.start(@server.host, 22789) { |http| http.get('/') }
47
- expect(@res.body).to include('Hello Server')
48
+ res = Net::HTTP.start(server.host, 22789) { |http| http.get('/') }
49
+ expect(res.body).to include('Hello Server')
48
50
 
49
51
  Capybara.server_port = nil
50
52
  end
51
53
 
52
- it "should use given port" do
53
- @app = proc { |_env| [200, {}, ["Hello Server!"]] }
54
- @server = Capybara::Server.new(@app, 22790).boot
54
+ it 'should use given port' do
55
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
56
+ server = described_class.new(app, port: 22790).boot
55
57
 
56
- @res = Net::HTTP.start(@server.host, 22790) { |http| http.get('/') }
57
- expect(@res.body).to include('Hello Server')
58
+ res = Net::HTTP.start(server.host, 22790) { |http| http.get('/') }
59
+ expect(res.body).to include('Hello Server')
58
60
 
59
61
  Capybara.server_port = nil
60
62
  end
61
63
 
62
- it "should find an available port" do
63
- @app1 = proc { |_env| [200, {}, ["Hello Server!"]] }
64
- @app2 = proc { |_env| [200, {}, ["Hello Second Server!"]] }
64
+ it 'should find an available port' do
65
+ responses = ['Hello Server!', 'Hello Second Server!']
66
+ apps = responses.map do |response|
67
+ proc { |_env| [200, {}, [response]] }
68
+ end
69
+ servers = apps.map { |app| described_class.new(app).boot }
65
70
 
66
- @server1 = Capybara::Server.new(@app1).boot
67
- @server2 = Capybara::Server.new(@app2).boot
71
+ servers.each_with_index do |server, idx|
72
+ result = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
73
+ expect(result.body).to include(responses[idx])
74
+ end
75
+ end
68
76
 
69
- @res1 = Net::HTTP.start(@server1.host, @server1.port) { |http| http.get('/') }
70
- expect(@res1.body).to include('Hello Server')
77
+ it 'should handle that getting available ports fails randomly' do
78
+ # Use a port to force a EADDRINUSE error to be generated
79
+ server = TCPServer.new('0.0.0.0', 0)
80
+ server_port = server.addr[1]
81
+ d_server = instance_double(TCPServer, addr: [nil, server_port, nil, nil], close: nil)
82
+ call_count = 0
83
+ allow(TCPServer).to receive(:new).and_wrap_original do |m, *args|
84
+ call_count.zero? ? d_server : m.call(*args)
85
+ ensure
86
+ call_count += 1
87
+ end
71
88
 
72
- @res2 = Net::HTTP.start(@server2.host, @server2.port) { |http| http.get('/') }
73
- expect(@res2.body).to include('Hello Second Server')
89
+ port = described_class.new(Object.new, host: '0.0.0.0').port
90
+ expect(port).not_to eq(server_port)
91
+ ensure
92
+ server&.close
74
93
  end
75
94
 
76
- context "When Capybara.reuse_server is true" do
95
+ it 'should return its #base_url' do
96
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
97
+ server = described_class.new(app).boot
98
+ uri = Addressable::URI.parse(server.base_url)
99
+ expect(uri.to_hash).to include(scheme: 'http', host: server.host, port: server.port)
100
+ end
101
+
102
+ it 'should call #clamp on the puma configuration to ensure that environment is a string' do
103
+ Capybara.server = :puma
104
+ app_proc = proc { |_env| [200, {}, ['Hello Puma!']] }
105
+ require 'puma'
106
+ allow(Puma::Server).to receive(:new).and_wrap_original do |method, app, events, options|
107
+ # If #clamp is not called on the puma config then this will be a Proc
108
+ expect(options.fetch(:environment)).to be_a(String)
109
+ method.call(app, events, options)
110
+ end
111
+ server = described_class.new(app_proc).boot
112
+ expect(Puma::Server).to have_received(:new).with(
113
+ anything,
114
+ anything,
115
+ satisfy { |opts| opts.final_options[:Port] == server.port }
116
+ )
117
+ ensure
118
+ Capybara.server = :default
119
+ end
120
+
121
+ it 'should not emit any warnings when booting puma' do
122
+ Capybara.server = :puma
123
+ app_proc = proc { |_env| [200, {}, ['Hello Puma!']] }
124
+ require 'puma'
125
+
126
+ expect do
127
+ described_class.new(app_proc).boot
128
+ end.not_to output.to_stderr
129
+ ensure
130
+ Capybara.server = :default
131
+ end
132
+
133
+ it 'should support SSL' do
134
+ key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem')
135
+ cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem')
136
+ Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" }
137
+ app = proc { |_env| [200, {}, ['Hello SSL Server!']] }
138
+ server = described_class.new(app).boot
139
+
140
+ expect do
141
+ Net::HTTP.start(server.host, server.port, max_retries: 0) { |http| http.get('/__identify__') }
142
+ end.to(raise_error do |e|
143
+ expect(e.is_a?(EOFError) || e.is_a?(Net::ReadTimeout)).to be true
144
+ end)
145
+
146
+ res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
147
+ https.get('/')
148
+ end
149
+
150
+ expect(res.body).to include('Hello SSL Server!')
151
+ uri = Addressable::URI.parse(server.base_url)
152
+ expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port)
153
+ ensure
154
+ Capybara.server = :default
155
+ end
156
+
157
+ context 'When Capybara.reuse_server is true' do
158
+ let!(:old_reuse_server) { Capybara.reuse_server }
159
+
77
160
  before do
78
- @old_reuse_server = Capybara.reuse_server
79
161
  Capybara.reuse_server = true
80
162
  end
81
163
 
82
164
  after do
83
- Capybara.reuse_server = @old_reuse_server
165
+ Capybara.reuse_server = old_reuse_server
84
166
  end
85
167
 
86
- it "should use the existing server if it already running" do
87
- @app = proc { |_env| [200, {}, ["Hello Server!"]] }
88
-
89
- @server1 = Capybara::Server.new(@app).boot
90
- @server2 = Capybara::Server.new(@app).boot
168
+ it 'should use the existing server if it already running' do
169
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
91
170
 
92
- res = Net::HTTP.start(@server1.host, @server1.port) { |http| http.get('/') }
93
- expect(res.body).to include('Hello Server')
171
+ servers = Array.new(2) { described_class.new(app).boot }
94
172
 
95
- res = Net::HTTP.start(@server2.host, @server2.port) { |http| http.get('/') }
96
- expect(res.body).to include('Hello Server')
173
+ servers.each do |server|
174
+ res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
175
+ expect(res.body).to include('Hello Server')
176
+ end
97
177
 
98
- expect(@server1.port).to eq(@server2.port)
178
+ expect(servers[0].port).to eq(servers[1].port)
99
179
  end
100
180
 
101
- it "detects and waits for all reused server sessions pending requests" do
181
+ it 'detects and waits for all reused server sessions pending requests' do
102
182
  done = 0
103
183
 
104
184
  app = proc do |env|
105
185
  request = Rack::Request.new(env)
106
186
  sleep request.params['wait_time'].to_f
107
187
  done += 1
108
- [200, {}, ["Hello Server!"]]
188
+ [200, {}, ['Hello Server!']]
109
189
  end
110
190
 
111
- server1 = Capybara::Server.new(app).boot
112
- server2 = Capybara::Server.new(app).boot
191
+ server1 = described_class.new(app).boot
192
+ server2 = described_class.new(app).boot
113
193
 
114
194
  expect do
115
195
  start_request(server1, 1.0)
116
196
  start_request(server2, 3.0)
117
197
  server1.wait_for_pending_requests
118
198
  end.to change { done }.from(0).to(2)
119
- expect(server2.send(:pending_requests?)).to eq(false)
199
+ expect(server2.send(:pending_requests?)).to be(false)
120
200
  end
121
201
  end
122
202
 
123
- context "When Capybara.reuse_server is false" do
203
+ context 'When Capybara.reuse_server is false' do
124
204
  before do
125
205
  @old_reuse_server = Capybara.reuse_server
126
206
  Capybara.reuse_server = false
127
207
  end
128
208
 
129
209
  after do
130
- Capybara.reuse_server = @old_reuse_server
210
+ Capybara.reuse_server = @old_reuse_server # rubocop:disable RSpec/InstanceVariable
131
211
  end
132
212
 
133
- it "should not reuse an already running server" do
134
- @app = proc { |_env| [200, {}, ["Hello Server!"]] }
135
-
136
- @server1 = Capybara::Server.new(@app).boot
137
- @server2 = Capybara::Server.new(@app).boot
213
+ it 'should not reuse an already running server' do
214
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
138
215
 
139
- res = Net::HTTP.start(@server1.host, @server1.port) { |http| http.get('/') }
140
- expect(res.body).to include('Hello Server')
216
+ servers = Array.new(2) { described_class.new(app).boot }
141
217
 
142
- res = Net::HTTP.start(@server2.host, @server2.port) { |http| http.get('/') }
143
- expect(res.body).to include('Hello Server')
218
+ servers.each do |server|
219
+ res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
220
+ expect(res.body).to include('Hello Server')
221
+ end
144
222
 
145
- expect(@server1.port).not_to eq(@server2.port)
223
+ expect(servers[0].port).not_to eq(servers[1].port)
146
224
  end
147
225
 
148
- it "detects and waits for only one sessions pending requests" do
226
+ it 'detects and waits for only one sessions pending requests' do
149
227
  done = 0
150
228
 
151
229
  app = proc do |env|
152
230
  request = Rack::Request.new(env)
153
231
  sleep request.params['wait_time'].to_f
154
232
  done += 1
155
- [200, {}, ["Hello Server!"]]
233
+ [200, {}, ['Hello Server!']]
156
234
  end
157
235
 
158
- server1 = Capybara::Server.new(app).boot
159
- server2 = Capybara::Server.new(app).boot
236
+ server1 = described_class.new(app).boot
237
+ server2 = described_class.new(app).boot
160
238
 
161
239
  expect do
162
240
  start_request(server1, 1.0)
163
241
  start_request(server2, 3.0)
164
242
  server1.wait_for_pending_requests
165
243
  end.to change { done }.from(0).to(1)
166
- expect(server2.send(:pending_requests?)).to eq(true)
244
+ expect(server2.send(:pending_requests?)).to be(true)
167
245
  expect do
168
246
  server2.wait_for_pending_requests
169
247
  end.to change { done }.from(1).to(2)
170
248
  end
171
249
  end
172
250
 
173
- it "should raise server errors when the server errors before the timeout" do
174
- begin
175
- Capybara.register_server :kaboom do
176
- sleep 0.1
177
- raise 'kaboom'
178
- end
179
- Capybara.server = :kaboom
251
+ it 'should raise server errors when the server errors before the timeout' do
252
+ Capybara.register_server :kaboom do
253
+ sleep 0.1
254
+ raise 'kaboom'
255
+ end
256
+ Capybara.server = :kaboom
180
257
 
181
- expect do
182
- Capybara::Server.new(proc { |e| }).boot
183
- end.to raise_error(RuntimeError, 'kaboom')
184
- ensure
185
- Capybara.server = :default
258
+ expect do
259
+ described_class.new(proc { |e| }).boot
260
+ end.to raise_error(RuntimeError, 'kaboom')
261
+ ensure
262
+ Capybara.server = :default
263
+ end
264
+
265
+ it 'should raise an error when there are pending requests' do
266
+ app = proc do |env|
267
+ request = Rack::Request.new(env)
268
+ sleep request.params['wait_time'].to_f
269
+ [200, {}, ['Hello Server!']]
186
270
  end
271
+
272
+ server = described_class.new(app).boot
273
+
274
+ expect do
275
+ start_request(server, 59.0)
276
+ server.wait_for_pending_requests
277
+ end.not_to raise_error
278
+
279
+ expect do
280
+ start_request(server, 61.0)
281
+ server.wait_for_pending_requests
282
+ end.to raise_error('Requests did not finish in 60 seconds: ["/?wait_time=61.0"]')
187
283
  end
188
284
 
189
- it "is not #responsive? when Net::HTTP raises a SystemCallError" do
285
+ it 'is not #responsive? when Net::HTTP raises a SystemCallError' do
190
286
  app = -> { [200, {}, ['Hello, world']] }
191
- server = Capybara::Server.new(app)
192
- expect(Net::HTTP).to receive(:start).and_raise(SystemCallError.allocate)
193
- expect(server.responsive?).to eq false
287
+ server = described_class.new(app)
288
+ allow(Net::HTTP).to receive(:start).and_raise(SystemCallError.allocate)
289
+ expect(server.responsive?).to be false
290
+ end
291
+
292
+ [EOFError, Net::ReadTimeout].each do |err|
293
+ it "should attempt an HTTPS connection if HTTP connection returns #{err}" do
294
+ app = -> { [200, {}, ['Hello, world']] }
295
+ ordered_errors = [Errno::ECONNREFUSED, err]
296
+ allow(Net::HTTP).to receive(:start).with(anything, anything, hash_excluding(:use_ssl)) do
297
+ raise ordered_errors.shift
298
+ end
299
+ response = Net::HTTPSuccess.allocate
300
+ allow(response).to receive(:body).and_return app.object_id.to_s
301
+ allow(Net::HTTP).to receive(:start).with(anything, anything, hash_including(use_ssl: true)).and_return(response).once
302
+ described_class.new(app).boot
303
+ expect(Net::HTTP).to have_received(:start).exactly(3).times
304
+ end
194
305
  end
195
306
 
196
307
  def start_request(server, wait_time)
data/spec/session_spec.rb CHANGED
@@ -3,14 +3,28 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe Capybara::Session do
6
- it "verifies a passed app is a rack app" do
7
- expect do
8
- Capybara::Session.new(:unknown, random: "hash")
9
- end.to raise_error TypeError, "The second parameter to Session::new should be a rack app if passed."
6
+ describe '#new' do
7
+ it 'should raise an error if passed non-existent driver' do
8
+ expect do
9
+ described_class.new(:quox, TestApp).driver
10
+ end.to raise_error(Capybara::DriverNotFoundError)
11
+ end
12
+
13
+ it 'verifies a passed app is a rack app' do
14
+ expect do
15
+ described_class.new(:unknown, random: 'hash')
16
+ end.to raise_error TypeError, 'The second parameter to Session::new should be a rack app if passed.'
17
+ end
10
18
  end
11
19
 
12
- context "current_driver" do
13
- it "is global when threadsafe false" do
20
+ context 'current_driver' do
21
+ around do |example|
22
+ orig_driver = Capybara.current_driver
23
+ example.run
24
+ Capybara.current_driver = orig_driver
25
+ end
26
+
27
+ it 'is global when threadsafe false' do
14
28
  Capybara.threadsafe = false
15
29
  Capybara.current_driver = :selenium
16
30
  thread = Thread.new do
@@ -20,7 +34,7 @@ RSpec.describe Capybara::Session do
20
34
  expect(Capybara.current_driver).to eq :random
21
35
  end
22
36
 
23
- it "is thread specific threadsafe true" do
37
+ it 'is thread specific threadsafe true' do
24
38
  Capybara.threadsafe = true
25
39
  Capybara.current_driver = :selenium
26
40
  thread = Thread.new do
@@ -31,25 +45,47 @@ RSpec.describe Capybara::Session do
31
45
  end
32
46
  end
33
47
 
34
- context "session_name" do
35
- it "is global when threadsafe false" do
48
+ context 'session_name' do
49
+ around do |example|
50
+ orig_name = Capybara.session_name
51
+ example.run
52
+ Capybara.session_name = orig_name
53
+ end
54
+
55
+ it 'is global when threadsafe false' do
36
56
  Capybara.threadsafe = false
37
- Capybara.session_name = "sess1"
57
+ Capybara.session_name = 'sess1'
38
58
  thread = Thread.new do
39
- Capybara.session_name = "sess2"
59
+ Capybara.session_name = 'sess2'
40
60
  end
41
61
  thread.join
42
- expect(Capybara.session_name).to eq "sess2"
62
+ expect(Capybara.session_name).to eq 'sess2'
43
63
  end
44
64
 
45
- it "is thread specific when threadsafe true" do
65
+ it 'is thread specific when threadsafe true' do
46
66
  Capybara.threadsafe = true
47
- Capybara.session_name = "sess1"
67
+ Capybara.session_name = 'sess1'
48
68
  thread = Thread.new do
49
- Capybara.session_name = "sess2"
69
+ Capybara.session_name = 'sess2'
50
70
  end
51
71
  thread.join
52
- expect(Capybara.session_name).to eq "sess1"
72
+ expect(Capybara.session_name).to eq 'sess1'
73
+ end
74
+ end
75
+
76
+ context 'quit' do
77
+ it 'will reset the driver' do
78
+ session = described_class.new(:rack_test, TestApp)
79
+ driver = session.driver
80
+ session.quit
81
+ expect(session.driver).not_to eql driver
82
+ end
83
+
84
+ it 'resets the document' do
85
+ session = described_class.new(:rack_test, TestApp)
86
+ document = session.document
87
+ session.quit
88
+ expect(session.document.base).not_to eql document.base
53
89
  end
54
90
  end
55
91
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'selenium-webdriver'
5
+
6
+ RSpec.shared_examples 'Capybara::Node' do |session, _mode|
7
+ let(:session) { session }
8
+
9
+ describe '#content_editable?' do
10
+ it 'returns true when the element is content editable' do
11
+ session.visit('/with_js')
12
+ expect(session.find(:css, '#existing_content_editable').base.content_editable?).to be true
13
+ expect(session.find(:css, '#existing_content_editable_child').base.content_editable?).to be true
14
+ end
15
+
16
+ it 'returns false when the element is not content editable' do
17
+ session.visit('/with_js')
18
+ expect(session.find(:css, '#drag').base.content_editable?).to be false
19
+ end
20
+ end
21
+
22
+ describe '#send_keys' do
23
+ it 'should process space' do
24
+ session.visit('/form')
25
+ session.find(:css, '#address1_city').send_keys('ocean', [:shift, :space, 'side'])
26
+ expect(session.find(:css, '#address1_city').value).to eq 'ocean SIDE'
27
+ end
28
+ end
29
+
30
+ describe '#[]' do
31
+ it 'should work for spellcheck' do
32
+ session.visit('/with_html')
33
+ expect(session.find('//input[@spellcheck="TRUE"]')[:spellcheck]).to eq('true')
34
+ expect(session.find('//input[@spellcheck="FALSE"]')[:spellcheck]).to eq('false')
35
+ end
36
+ end
37
+
38
+ describe '#set' do
39
+ it 'respects maxlength when using rapid set' do
40
+ session.visit('/form')
41
+ inp = session.find(:css, '#long_length')
42
+ value = (0...50).map { |i| ((i % 26) + 65).chr }.join
43
+ inp.set(value, rapid: true)
44
+ expect(inp.value).to eq value[0...35]
45
+ end
46
+ end
47
+
48
+ describe '#visible?' do
49
+ let(:bridge) do
50
+ session.driver.browser.send(:bridge)
51
+ end
52
+
53
+ around do |example|
54
+ native_displayed = session.driver.options[:native_displayed]
55
+ example.run
56
+ session.driver.options[:native_displayed] = native_displayed
57
+ end
58
+
59
+ before do
60
+ allow(bridge).to receive(:execute_atom).and_call_original
61
+ end
62
+
63
+ it 'will use native displayed if told to' do
64
+ session.driver.options[:native_displayed] = true
65
+ session.visit('/form')
66
+ session.find(:css, '#address1_city', visible: true)
67
+
68
+ expect(bridge).not_to have_received(:execute_atom)
69
+ end
70
+
71
+ it "won't use native displayed if told not to" do
72
+ session.driver.options[:native_displayed] = false
73
+ session.visit('/form')
74
+ session.find(:css, '#address1_city', visible: true)
75
+
76
+ expect(bridge).to have_received(:execute_atom).with(:isDisplayed, any_args)
77
+ end
78
+ end
79
+ end