capybara 3.32.2

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 (313) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/History.md +1813 -0
  4. data/License.txt +22 -0
  5. data/README.md +1099 -0
  6. data/lib/capybara.rb +511 -0
  7. data/lib/capybara/config.rb +94 -0
  8. data/lib/capybara/cucumber.rb +27 -0
  9. data/lib/capybara/driver/base.rb +170 -0
  10. data/lib/capybara/driver/node.rb +139 -0
  11. data/lib/capybara/dsl.rb +65 -0
  12. data/lib/capybara/helpers.rb +108 -0
  13. data/lib/capybara/minitest.rb +386 -0
  14. data/lib/capybara/minitest/spec.rb +264 -0
  15. data/lib/capybara/node/actions.rb +420 -0
  16. data/lib/capybara/node/base.rb +143 -0
  17. data/lib/capybara/node/document.rb +48 -0
  18. data/lib/capybara/node/document_matchers.rb +67 -0
  19. data/lib/capybara/node/element.rb +606 -0
  20. data/lib/capybara/node/finders.rb +325 -0
  21. data/lib/capybara/node/matchers.rb +883 -0
  22. data/lib/capybara/node/simple.rb +208 -0
  23. data/lib/capybara/queries/ancestor_query.rb +27 -0
  24. data/lib/capybara/queries/base_query.rb +106 -0
  25. data/lib/capybara/queries/current_path_query.rb +51 -0
  26. data/lib/capybara/queries/match_query.rb +26 -0
  27. data/lib/capybara/queries/selector_query.rb +710 -0
  28. data/lib/capybara/queries/sibling_query.rb +26 -0
  29. data/lib/capybara/queries/style_query.rb +45 -0
  30. data/lib/capybara/queries/text_query.rb +110 -0
  31. data/lib/capybara/queries/title_query.rb +39 -0
  32. data/lib/capybara/rack_test/browser.rb +140 -0
  33. data/lib/capybara/rack_test/css_handlers.rb +13 -0
  34. data/lib/capybara/rack_test/driver.rb +109 -0
  35. data/lib/capybara/rack_test/errors.rb +6 -0
  36. data/lib/capybara/rack_test/form.rb +127 -0
  37. data/lib/capybara/rack_test/node.rb +325 -0
  38. data/lib/capybara/rails.rb +16 -0
  39. data/lib/capybara/registrations/drivers.rb +36 -0
  40. data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
  41. data/lib/capybara/registrations/servers.rb +44 -0
  42. data/lib/capybara/result.rb +190 -0
  43. data/lib/capybara/rspec.rb +29 -0
  44. data/lib/capybara/rspec/features.rb +23 -0
  45. data/lib/capybara/rspec/matcher_proxies.rb +82 -0
  46. data/lib/capybara/rspec/matchers.rb +201 -0
  47. data/lib/capybara/rspec/matchers/base.rb +111 -0
  48. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  49. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  50. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  51. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  52. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  53. data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
  54. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  55. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  56. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  57. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  58. data/lib/capybara/rspec/matchers/match_style.rb +38 -0
  59. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  60. data/lib/capybara/selector.rb +233 -0
  61. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  62. data/lib/capybara/selector/builders/xpath_builder.rb +69 -0
  63. data/lib/capybara/selector/css.rb +102 -0
  64. data/lib/capybara/selector/definition.rb +276 -0
  65. data/lib/capybara/selector/definition/button.rb +51 -0
  66. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  67. data/lib/capybara/selector/definition/css.rb +10 -0
  68. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  69. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  70. data/lib/capybara/selector/definition/element.rb +27 -0
  71. data/lib/capybara/selector/definition/field.rb +40 -0
  72. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  73. data/lib/capybara/selector/definition/file_field.rb +13 -0
  74. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  75. data/lib/capybara/selector/definition/frame.rb +17 -0
  76. data/lib/capybara/selector/definition/id.rb +6 -0
  77. data/lib/capybara/selector/definition/label.rb +62 -0
  78. data/lib/capybara/selector/definition/link.rb +46 -0
  79. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  80. data/lib/capybara/selector/definition/option.rb +27 -0
  81. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  82. data/lib/capybara/selector/definition/select.rb +81 -0
  83. data/lib/capybara/selector/definition/table.rb +109 -0
  84. data/lib/capybara/selector/definition/table_row.rb +21 -0
  85. data/lib/capybara/selector/definition/xpath.rb +5 -0
  86. data/lib/capybara/selector/filter.rb +5 -0
  87. data/lib/capybara/selector/filter_set.rb +124 -0
  88. data/lib/capybara/selector/filters/base.rb +77 -0
  89. data/lib/capybara/selector/filters/expression_filter.rb +22 -0
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +31 -0
  92. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  93. data/lib/capybara/selector/selector.rb +147 -0
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  96. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  97. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  98. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  99. data/lib/capybara/selenium/driver.rb +496 -0
  100. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +119 -0
  101. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +126 -0
  102. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
  103. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  104. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  105. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  106. data/lib/capybara/selenium/extensions/find.rb +110 -0
  107. data/lib/capybara/selenium/extensions/html5_drag.rb +228 -0
  108. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  109. data/lib/capybara/selenium/extensions/scroll.rb +78 -0
  110. data/lib/capybara/selenium/logger_suppressor.rb +34 -0
  111. data/lib/capybara/selenium/node.rb +610 -0
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +119 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  114. data/lib/capybara/selenium/nodes/firefox_node.rb +131 -0
  115. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  116. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  117. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  118. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  119. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  120. data/lib/capybara/selenium/patches/logs.rb +47 -0
  121. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  122. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  123. data/lib/capybara/server.rb +126 -0
  124. data/lib/capybara/server/animation_disabler.rb +58 -0
  125. data/lib/capybara/server/checker.rb +44 -0
  126. data/lib/capybara/server/middleware.rb +69 -0
  127. data/lib/capybara/session.rb +942 -0
  128. data/lib/capybara/session/config.rb +124 -0
  129. data/lib/capybara/session/matchers.rb +87 -0
  130. data/lib/capybara/spec/fixtures/another_test_file.txt +1 -0
  131. data/lib/capybara/spec/fixtures/capybara.jpg +3 -0
  132. data/lib/capybara/spec/fixtures/no_extension +1 -0
  133. data/lib/capybara/spec/fixtures/test_file.txt +1 -0
  134. data/lib/capybara/spec/public/jquery-ui.js +13 -0
  135. data/lib/capybara/spec/public/jquery.js +5 -0
  136. data/lib/capybara/spec/public/offset.js +6 -0
  137. data/lib/capybara/spec/public/test.js +268 -0
  138. data/lib/capybara/spec/session/accept_alert_spec.rb +81 -0
  139. data/lib/capybara/spec/session/accept_confirm_spec.rb +32 -0
  140. data/lib/capybara/spec/session/accept_prompt_spec.rb +78 -0
  141. data/lib/capybara/spec/session/all_spec.rb +278 -0
  142. data/lib/capybara/spec/session/ancestor_spec.rb +88 -0
  143. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +140 -0
  144. data/lib/capybara/spec/session/assert_current_path_spec.rb +75 -0
  145. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  146. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  147. data/lib/capybara/spec/session/assert_text_spec.rb +258 -0
  148. data/lib/capybara/spec/session/assert_title_spec.rb +93 -0
  149. data/lib/capybara/spec/session/attach_file_spec.rb +216 -0
  150. data/lib/capybara/spec/session/body_spec.rb +23 -0
  151. data/lib/capybara/spec/session/check_spec.rb +235 -0
  152. data/lib/capybara/spec/session/choose_spec.rb +121 -0
  153. data/lib/capybara/spec/session/click_button_spec.rb +506 -0
  154. data/lib/capybara/spec/session/click_link_or_button_spec.rb +129 -0
  155. data/lib/capybara/spec/session/click_link_spec.rb +229 -0
  156. data/lib/capybara/spec/session/current_scope_spec.rb +31 -0
  157. data/lib/capybara/spec/session/current_url_spec.rb +115 -0
  158. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +36 -0
  159. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +21 -0
  160. data/lib/capybara/spec/session/element/assert_match_selector_spec.rb +38 -0
  161. data/lib/capybara/spec/session/element/match_css_spec.rb +31 -0
  162. data/lib/capybara/spec/session/element/match_xpath_spec.rb +25 -0
  163. data/lib/capybara/spec/session/element/matches_selector_spec.rb +120 -0
  164. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +23 -0
  165. data/lib/capybara/spec/session/evaluate_script_spec.rb +49 -0
  166. data/lib/capybara/spec/session/execute_script_spec.rb +28 -0
  167. data/lib/capybara/spec/session/fill_in_spec.rb +286 -0
  168. data/lib/capybara/spec/session/find_button_spec.rb +74 -0
  169. data/lib/capybara/spec/session/find_by_id_spec.rb +33 -0
  170. data/lib/capybara/spec/session/find_field_spec.rb +113 -0
  171. data/lib/capybara/spec/session/find_link_spec.rb +70 -0
  172. data/lib/capybara/spec/session/find_spec.rb +531 -0
  173. data/lib/capybara/spec/session/first_spec.rb +156 -0
  174. data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
  175. data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
  176. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +116 -0
  177. data/lib/capybara/spec/session/frame/within_frame_spec.rb +112 -0
  178. data/lib/capybara/spec/session/go_back_spec.rb +12 -0
  179. data/lib/capybara/spec/session/go_forward_spec.rb +14 -0
  180. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  181. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  182. data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
  183. data/lib/capybara/spec/session/has_button_spec.rb +69 -0
  184. data/lib/capybara/spec/session/has_css_spec.rb +374 -0
  185. data/lib/capybara/spec/session/has_current_path_spec.rb +138 -0
  186. data/lib/capybara/spec/session/has_field_spec.rb +349 -0
  187. data/lib/capybara/spec/session/has_link_spec.rb +39 -0
  188. data/lib/capybara/spec/session/has_none_selectors_spec.rb +78 -0
  189. data/lib/capybara/spec/session/has_select_spec.rb +310 -0
  190. data/lib/capybara/spec/session/has_selector_spec.rb +202 -0
  191. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  192. data/lib/capybara/spec/session/has_table_spec.rb +198 -0
  193. data/lib/capybara/spec/session/has_text_spec.rb +394 -0
  194. data/lib/capybara/spec/session/has_title_spec.rb +71 -0
  195. data/lib/capybara/spec/session/has_xpath_spec.rb +149 -0
  196. data/lib/capybara/spec/session/headers_spec.rb +8 -0
  197. data/lib/capybara/spec/session/html_spec.rb +47 -0
  198. data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
  199. data/lib/capybara/spec/session/node_spec.rb +1292 -0
  200. data/lib/capybara/spec/session/node_wrapper_spec.rb +39 -0
  201. data/lib/capybara/spec/session/refresh_spec.rb +33 -0
  202. data/lib/capybara/spec/session/reset_session_spec.rb +148 -0
  203. data/lib/capybara/spec/session/response_code_spec.rb +8 -0
  204. data/lib/capybara/spec/session/save_and_open_page_spec.rb +21 -0
  205. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +43 -0
  206. data/lib/capybara/spec/session/save_page_spec.rb +110 -0
  207. data/lib/capybara/spec/session/save_screenshot_spec.rb +55 -0
  208. data/lib/capybara/spec/session/screenshot_spec.rb +18 -0
  209. data/lib/capybara/spec/session/scroll_spec.rb +117 -0
  210. data/lib/capybara/spec/session/select_spec.rb +229 -0
  211. data/lib/capybara/spec/session/selectors_spec.rb +98 -0
  212. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  213. data/lib/capybara/spec/session/source_spec.rb +0 -0
  214. data/lib/capybara/spec/session/text_spec.rb +74 -0
  215. data/lib/capybara/spec/session/title_spec.rb +29 -0
  216. data/lib/capybara/spec/session/uncheck_spec.rb +100 -0
  217. data/lib/capybara/spec/session/unselect_spec.rb +116 -0
  218. data/lib/capybara/spec/session/visit_spec.rb +204 -0
  219. data/lib/capybara/spec/session/window/become_closed_spec.rb +89 -0
  220. data/lib/capybara/spec/session/window/current_window_spec.rb +28 -0
  221. data/lib/capybara/spec/session/window/open_new_window_spec.rb +31 -0
  222. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +132 -0
  223. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +99 -0
  224. data/lib/capybara/spec/session/window/window_spec.rb +203 -0
  225. data/lib/capybara/spec/session/window/windows_spec.rb +34 -0
  226. data/lib/capybara/spec/session/window/within_window_spec.rb +157 -0
  227. data/lib/capybara/spec/session/within_spec.rb +199 -0
  228. data/lib/capybara/spec/spec_helper.rb +134 -0
  229. data/lib/capybara/spec/test_app.rb +226 -0
  230. data/lib/capybara/spec/views/animated.erb +49 -0
  231. data/lib/capybara/spec/views/buttons.erb +5 -0
  232. data/lib/capybara/spec/views/fieldsets.erb +30 -0
  233. data/lib/capybara/spec/views/form.erb +685 -0
  234. data/lib/capybara/spec/views/frame_child.erb +18 -0
  235. data/lib/capybara/spec/views/frame_one.erb +10 -0
  236. data/lib/capybara/spec/views/frame_parent.erb +9 -0
  237. data/lib/capybara/spec/views/frame_two.erb +9 -0
  238. data/lib/capybara/spec/views/header_links.erb +8 -0
  239. data/lib/capybara/spec/views/host_links.erb +13 -0
  240. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  241. data/lib/capybara/spec/views/obscured.erb +47 -0
  242. data/lib/capybara/spec/views/offset.erb +32 -0
  243. data/lib/capybara/spec/views/path.erb +13 -0
  244. data/lib/capybara/spec/views/popup_one.erb +9 -0
  245. data/lib/capybara/spec/views/popup_two.erb +9 -0
  246. data/lib/capybara/spec/views/postback.erb +14 -0
  247. data/lib/capybara/spec/views/react.erb +45 -0
  248. data/lib/capybara/spec/views/scroll.erb +20 -0
  249. data/lib/capybara/spec/views/spatial.erb +31 -0
  250. data/lib/capybara/spec/views/tables.erb +130 -0
  251. data/lib/capybara/spec/views/with_animation.erb +74 -0
  252. data/lib/capybara/spec/views/with_base_tag.erb +11 -0
  253. data/lib/capybara/spec/views/with_count.erb +8 -0
  254. data/lib/capybara/spec/views/with_dragula.erb +22 -0
  255. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  256. data/lib/capybara/spec/views/with_hover.erb +24 -0
  257. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  258. data/lib/capybara/spec/views/with_html.erb +208 -0
  259. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  260. data/lib/capybara/spec/views/with_html_entities.erb +2 -0
  261. data/lib/capybara/spec/views/with_js.erb +160 -0
  262. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  263. data/lib/capybara/spec/views/with_namespace.erb +20 -0
  264. data/lib/capybara/spec/views/with_scope.erb +42 -0
  265. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  266. data/lib/capybara/spec/views/with_simple_html.erb +2 -0
  267. data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
  268. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  269. data/lib/capybara/spec/views/with_title.erb +5 -0
  270. data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
  271. data/lib/capybara/spec/views/with_windows.erb +54 -0
  272. data/lib/capybara/spec/views/within_frames.erb +15 -0
  273. data/lib/capybara/version.rb +5 -0
  274. data/lib/capybara/window.rb +146 -0
  275. data/spec/basic_node_spec.rb +154 -0
  276. data/spec/capybara_spec.rb +112 -0
  277. data/spec/css_builder_spec.rb +101 -0
  278. data/spec/css_splitter_spec.rb +38 -0
  279. data/spec/dsl_spec.rb +276 -0
  280. data/spec/filter_set_spec.rb +46 -0
  281. data/spec/fixtures/capybara.csv +1 -0
  282. data/spec/fixtures/certificate.pem +25 -0
  283. data/spec/fixtures/key.pem +27 -0
  284. data/spec/fixtures/selenium_driver_rspec_failure.rb +13 -0
  285. data/spec/fixtures/selenium_driver_rspec_success.rb +13 -0
  286. data/spec/minitest_spec.rb +163 -0
  287. data/spec/minitest_spec_spec.rb +162 -0
  288. data/spec/per_session_config_spec.rb +68 -0
  289. data/spec/rack_test_spec.rb +268 -0
  290. data/spec/regexp_dissassembler_spec.rb +250 -0
  291. data/spec/result_spec.rb +196 -0
  292. data/spec/rspec/features_spec.rb +99 -0
  293. data/spec/rspec/scenarios_spec.rb +19 -0
  294. data/spec/rspec/shared_spec_matchers.rb +947 -0
  295. data/spec/rspec/views_spec.rb +14 -0
  296. data/spec/rspec_matchers_spec.rb +62 -0
  297. data/spec/rspec_spec.rb +145 -0
  298. data/spec/sauce_spec_chrome.rb +43 -0
  299. data/spec/selector_spec.rb +513 -0
  300. data/spec/selenium_spec_chrome.rb +188 -0
  301. data/spec/selenium_spec_chrome_remote.rb +96 -0
  302. data/spec/selenium_spec_edge.rb +47 -0
  303. data/spec/selenium_spec_firefox.rb +208 -0
  304. data/spec/selenium_spec_firefox_remote.rb +80 -0
  305. data/spec/selenium_spec_ie.rb +150 -0
  306. data/spec/selenium_spec_safari.rb +148 -0
  307. data/spec/server_spec.rb +292 -0
  308. data/spec/session_spec.rb +91 -0
  309. data/spec/shared_selenium_node.rb +83 -0
  310. data/spec/shared_selenium_session.rb +476 -0
  311. data/spec/spec_helper.rb +100 -0
  312. data/spec/xpath_builder_spec.rb +93 -0
  313. metadata +753 -0
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'selenium-webdriver'
5
+ require 'shared_selenium_session'
6
+ require 'shared_selenium_node'
7
+ require 'rspec/shared_spec_matchers'
8
+
9
+ def selenium_host
10
+ ENV.fetch('SELENIUM_HOST', '0.0.0.0')
11
+ end
12
+
13
+ def selenium_port
14
+ ENV.fetch('SELENIUM_PORT', 4445)
15
+ end
16
+
17
+ def ensure_selenium_running!
18
+ timer = Capybara::Helpers.timer(expire_in: 20)
19
+ begin
20
+ TCPSocket.open(selenium_host, selenium_port)
21
+ rescue StandardError
22
+ if timer.expired?
23
+ raise 'Selenium is not running. ' \
24
+ "You can run a selenium server easily with: \n" \
25
+ ' $ docker-compose up -d selenium_firefox'
26
+ else
27
+ puts 'Waiting for Selenium docker instance...'
28
+ sleep 1
29
+ retry
30
+ end
31
+ end
32
+ end
33
+
34
+ Capybara.register_driver :selenium_firefox_remote do |app|
35
+ ensure_selenium_running!
36
+
37
+ url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
38
+ browser_options = ::Selenium::WebDriver::Firefox::Options.new
39
+
40
+ Capybara::Selenium::Driver.new app,
41
+ browser: :remote,
42
+ desired_capabilities: :firefox,
43
+ options: browser_options,
44
+ url: url
45
+ end
46
+
47
+ FIREFOX_REMOTE_DRIVER = :selenium_firefox_remote
48
+
49
+ module TestSessions
50
+ RemoteFirefox = Capybara::Session.new(FIREFOX_REMOTE_DRIVER, TestApp)
51
+ end
52
+
53
+ skipped_tests = %i[response_headers status_code trigger download]
54
+
55
+ Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
56
+ case example.metadata[:full_description]
57
+ when 'Capybara::Session selenium_firefox_remote node #click should allow multiple modifiers'
58
+ skip "Firefox doesn't generate an event for shift+control+click" if firefox_gte?(62, @session)
59
+ when 'Capybara::Session selenium_firefox_remote #accept_prompt should accept the prompt with a blank response when there is a default'
60
+ pending "Geckodriver doesn't set a blank response in FF < 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1486485" if firefox_lt?(63, @session)
61
+ when 'Capybara::Session selenium_firefox_remote #attach_file with multipart form should fire change once when uploading multiple files from empty'
62
+ pending "FF < 62 doesn't support setting all files at once" if firefox_lt?(62, @session)
63
+ when 'Capybara::Session selenium_firefox_remote #reset_session! removes ALL cookies'
64
+ pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
65
+ when /#accept_confirm should work with nested modals$/
66
+ # skip because this is timing based and hence flaky when set to pending
67
+ skip 'Broken in FF 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session)
68
+ end
69
+ end
70
+
71
+ RSpec.describe 'Capybara::Session with remote firefox' do
72
+ include Capybara::SpecHelper
73
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
74
+ include_examples examples, TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER
75
+ end
76
+
77
+ it 'is considered to be firefox' do
78
+ expect(session.driver.browser.browser).to eq :firefox
79
+ end
80
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'selenium-webdriver'
5
+ require 'shared_selenium_session'
6
+ require 'shared_selenium_node'
7
+ require 'rspec/shared_spec_matchers'
8
+
9
+ # if ENV['CI']
10
+ # if ::Selenium::WebDriver::Service.respond_to? :driver_path=
11
+ # ::Selenium::WebDriver::IE::Service
12
+ # else
13
+ # ::Selenium::WebDriver::IE
14
+ # end.driver_path = 'C:\Tools\WebDriver\IEDriverServer.exe'
15
+ # end
16
+
17
+ def selenium_host
18
+ ENV.fetch('SELENIUM_HOST', '192.168.56.102')
19
+ end
20
+
21
+ def selenium_port
22
+ ENV.fetch('SELENIUM_PORT', 4444)
23
+ end
24
+
25
+ def server_host
26
+ ENV.fetch('SERVER_HOST', '10.24.4.135')
27
+ end
28
+
29
+ Capybara.register_driver :selenium_ie do |app|
30
+ # ::Selenium::WebDriver.logger.level = "debug"
31
+ options = ::Selenium::WebDriver::IE::Options.new
32
+ # options.require_window_focus = true
33
+ # options.add_option("log", {"level": "trace"})
34
+
35
+ if ENV['REMOTE']
36
+ Capybara.server_host = server_host
37
+
38
+ url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
39
+ Capybara::Selenium::Driver.new(app,
40
+ browser: :remote,
41
+ options: options,
42
+ url: url)
43
+ else
44
+ Capybara::Selenium::Driver.new(
45
+ app,
46
+ browser: :ie,
47
+ options: options
48
+ )
49
+ end
50
+ end
51
+
52
+ module TestSessions
53
+ SeleniumIE = Capybara::Session.new(:selenium_ie, TestApp)
54
+ end
55
+
56
+ TestSessions::SeleniumIE.current_window.resize_to(800, 500)
57
+
58
+ skipped_tests = %i[response_headers status_code trigger modals hover form_attribute windows]
59
+
60
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::IE) if ENV['CI']
61
+
62
+ TestSessions::SeleniumIE.current_window.resize_to(1600, 1200)
63
+
64
+ Capybara::SpecHelper.run_specs TestSessions::SeleniumIE, 'selenium', capybara_skip: skipped_tests do |example|
65
+ case example.metadata[:full_description]
66
+ when /#refresh it reposts$/
67
+ skip 'IE insists on prompting without providing a way to suppress'
68
+ when /#click_link can download a file$/
69
+ skip 'Not sure how to configure IE for automatic downloading'
70
+ when /#fill_in with Date /
71
+ pending "IE 11 doesn't support date input types"
72
+ when /#click_link_or_button with :disabled option happily clicks on links which incorrectly have the disabled attribute$/
73
+ skip 'IE 11 obeys non-standard disabled attribute on anchor tag'
74
+ when /#right_click should allow modifiers$/
75
+ skip "Windows can't :meta click because :meta triggers start menu"
76
+ when /#click should allow modifiers$/
77
+ pending "Doesn't work with IE for some unknown reason$"
78
+ when /#double_click should allow modifiers$/
79
+ pending "Doesn't work with IE for some unknown reason$"
80
+ when /#click should allow multiple modifiers$/
81
+ skip "Windows can't :meta click because :meta triggers start menu"
82
+ when /#double_click should allow multiple modifiers$/
83
+ skip "Windows can't :alt double click due to being properties shortcut"
84
+ when /#has_css\? should support case insensitive :class and :id options$/
85
+ pending "IE doesn't support case insensitive CSS selectors"
86
+ when /#reset_session! removes ALL cookies$/
87
+ pending "IE driver doesn't provide a way to remove ALL cookies"
88
+ when /#click_button should send button in document order$/
89
+ pending "IE 11 doesn't support the 'form' attribute"
90
+ when /#click_button should follow permanent redirects that maintain method$/
91
+ pending "Window 7 and 8.1 don't support 308 http status code"
92
+ when /#scroll_to can scroll an element to the center of the viewport$/,
93
+ /#scroll_to can scroll an element to the center of the scrolling element$/
94
+ pending " IE doesn't support ScrollToOptions"
95
+ when /#attach_file with multipart form should fire change once for each set of files uploaded$/,
96
+ /#attach_file with multipart form should fire change once when uploading multiple files from empty$/,
97
+ /#attach_file with multipart form should not break when using HTML5 multiple file input uploading multiple files$/
98
+ pending "IE requires all files be uploaded from same directory. Selenium doesn't provide that." if ENV['REMOTE']
99
+ when %r{#attach_file with multipart form should send content type image/jpeg when uploading an image$}
100
+ pending 'IE gets text/plain type for some reason'
101
+ # when /#click should not retry clicking when wait is disabled$/
102
+ # Fixed in IEDriverServer 3.141.0.5
103
+ # pending "IE driver doesn't error when clicking on covered elements, it just clicks the wrong element"
104
+ when /#click should go to the same page if href is blank$/
105
+ pending 'IE treats blank href as a parent request (against HTML spec)'
106
+ when /#attach_file with a block/
107
+ skip 'Hangs IE testing for unknown reason'
108
+ when /drag_to.*HTML5/
109
+ pending "IE doesn't support a DataTransfer constuctor"
110
+ when /template elements should not be visible/
111
+ skip "IE doesn't support template elements"
112
+ when /Element#drop/
113
+ pending "IE doesn't support DataTransfer constructor"
114
+ end
115
+ end
116
+
117
+ RSpec.describe 'Capybara::Session with Internet Explorer', capybara_skip: skipped_tests do # rubocop:disable RSpec/MultipleDescribes
118
+ include Capybara::SpecHelper
119
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
120
+ include_examples examples, TestSessions::SeleniumIE, :selenium_ie
121
+ end
122
+ end
123
+
124
+ RSpec.describe Capybara::Selenium::Node do
125
+ it '#right_click should allow modifiers' do
126
+ # pending "Actions API doesn't appear to work for this"
127
+ session = TestSessions::SeleniumIE
128
+ session.visit('/with_js')
129
+ el = session.find(:css, '#click-test')
130
+ el.right_click(:control)
131
+ expect(session).to have_link('Has been control right clicked')
132
+ end
133
+
134
+ it '#click should allow multiple modifiers' do
135
+ # pending "Actions API doesn't appear to work for this"
136
+ session = TestSessions::SeleniumIE
137
+ session.visit('with_js')
138
+ # IE triggers system behavior with :meta so can't use those here
139
+ session.find(:css, '#click-test').click(:ctrl, :shift, :alt)
140
+ expect(session).to have_link('Has been alt control shift clicked')
141
+ end
142
+
143
+ it '#double_click should allow modifiers' do
144
+ # pending "Actions API doesn't appear to work for this"
145
+ session = TestSessions::SeleniumIE
146
+ session.visit('/with_js')
147
+ session.find(:css, '#click-test').double_click(:shift)
148
+ expect(session).to have_link('Has been shift double clicked')
149
+ end
150
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'selenium-webdriver'
5
+ require 'shared_selenium_session'
6
+ require 'shared_selenium_node'
7
+ require 'rspec/shared_spec_matchers'
8
+
9
+ SAFARI_DRIVER = :selenium_safari
10
+
11
+ if ::Selenium::WebDriver::Service.respond_to? :driver_path=
12
+ ::Selenium::WebDriver::Safari::Service
13
+ else
14
+ ::Selenium::WebDriver::Safari
15
+ end.driver_path = '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver'
16
+
17
+ browser_options = ::Selenium::WebDriver::Safari::Options.new
18
+ # browser_options.headless! if ENV['HEADLESS']
19
+ # browser_options.add_option(:w3c, !!ENV['W3C'])
20
+
21
+ Capybara.register_driver :selenium_safari do |app|
22
+ Capybara::Selenium::Driver.new(app, browser: :safari, options: browser_options, timeout: 30).tap do |driver|
23
+ # driver.browser.download_path = Capybara.save_path
24
+ end
25
+ end
26
+
27
+ Capybara.register_driver :selenium_safari_not_clear_storage do |app|
28
+ safari_options = {
29
+ browser: :safari,
30
+ options: browser_options
31
+ }
32
+ Capybara::Selenium::Driver.new(app, safari_options.merge(clear_local_storage: false, clear_session_storage: false))
33
+ end
34
+
35
+ module TestSessions
36
+ Safari = Capybara::Session.new(SAFARI_DRIVER, TestApp)
37
+ end
38
+
39
+ skipped_tests = %i[response_headers status_code trigger windows drag]
40
+
41
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Safari) if ENV['CI']
42
+
43
+ Capybara::SpecHelper.run_specs TestSessions::Safari, SAFARI_DRIVER.to_s, capybara_skip: skipped_tests do |example|
44
+ case example.metadata[:full_description]
45
+ when /click_link can download a file/
46
+ skip "safaridriver doesn't provide a way to set the download directory"
47
+ when /Capybara::Session selenium_safari Capybara::Window#maximize/
48
+ pending "Safari headless doesn't support maximize" if ENV['HEADLESS']
49
+ when /Capybara::Session selenium_safari #visit without a server/,
50
+ /Capybara::Session selenium_safari #visit with Capybara.app_host set should override server/,
51
+ /Capybara::Session selenium_safari #reset_session! When reuse_server == false raises any standard errors caught inside the server during a second session/
52
+ skip "Safari webdriver doesn't support multiple sessions"
53
+ when /Capybara::Session selenium_safari #click_link with alternative text given to a contained image/,
54
+ 'Capybara::Session selenium_safari #click_link_or_button with enable_aria_label should click on link'
55
+ pending 'safaridriver thinks these links are non-interactable for some unknown reason'
56
+ when /Capybara::Session selenium_safari #attach_file with a block can upload by clicking the file input/
57
+ skip "safaridriver doesn't allow clicking on file inputs"
58
+ when /Capybara::Session selenium_safari #within_frame works if the frame is closed/,
59
+ /Capybara::Session selenium_safari #switch_to_frame works if the frame is closed/
60
+ skip 'Safari has a race condition when clicking an element that causes the frame to close. It will sometimes raise a NoSuchFrameError'
61
+ when /Capybara::Session selenium_safari #reset_session! removes ALL cookies/
62
+ skip 'Safari webdriver can only remove cookies for the current domain'
63
+ when /Capybara::Session selenium_safari #refresh it reposts/
64
+ skip "Safari opens an alert that can't be closed"
65
+ when 'Capybara::Session selenium_safari node #double_click should allow to adjust the offset',
66
+ 'Capybara::Session selenium_safari node #double_click should double click an element'
67
+ pending "safardriver doesn't generate a double click event"
68
+ when 'Capybara::Session selenium_safari node #click should allow multiple modifiers',
69
+ /Capybara::Session selenium_safari node #(click|right_click|double_click) should allow modifiers/
70
+ pending "safaridriver doesn't take key state into account when clicking"
71
+ when 'Capybara::Session selenium_safari #fill_in on a pre-populated textfield with a reformatting onchange should trigger change when clearing field'
72
+ pending "safardriver clear doesn't generate change event"
73
+ when 'Capybara::Session selenium_safari #go_back should fetch a response from the driver from the previous page',
74
+ 'Capybara::Session selenium_safari #go_forward should fetch a response from the driver from the previous page'
75
+ skip 'safaridriver loses the ability to find elements in the document after `go_back`'
76
+ when /drag_to.*HTML5/
77
+ pending "Safari doesn't support"
78
+ end
79
+ end
80
+
81
+ RSpec.describe 'Capybara::Session with safari' do
82
+ include Capybara::SpecHelper
83
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
84
+ include_examples examples, TestSessions::Safari, SAFARI_DRIVER
85
+ end
86
+
87
+ context 'storage' do
88
+ describe '#reset!' do
89
+ it 'clears storage by default' do
90
+ session = TestSessions::Safari
91
+ session.visit('/with_js')
92
+ session.find(:css, '#set-storage').click
93
+ session.reset!
94
+ session.visit('/with_js')
95
+ expect(session.evaluate_script('Object.keys(localStorage)')).to be_empty
96
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
97
+ end
98
+
99
+ it 'does not clear storage when false' do
100
+ skip "Safari webdriver doesn't support multiple sessions"
101
+ session = Capybara::Session.new(:selenium_safari_not_clear_storage, TestApp)
102
+ session.visit('/with_js')
103
+ session.find(:css, '#set-storage').click
104
+ session.reset!
105
+ session.visit('/with_js')
106
+ expect(session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
107
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty
108
+ end
109
+ end
110
+ end
111
+
112
+ context 'timeout' do
113
+ it 'sets the http client read timeout' do
114
+ expect(TestSessions::Safari.driver.browser.send(:bridge).http.read_timeout).to eq 30
115
+ end
116
+ end
117
+
118
+ describe 'filling in Safari-specific date and time fields with keystrokes' do
119
+ let(:datetime) { Time.new(1983, 6, 19, 6, 30) }
120
+ let(:session) { TestSessions::Safari }
121
+
122
+ before do
123
+ session.visit('/form')
124
+ end
125
+
126
+ it 'should fill in a date input with a String' do
127
+ pending "Safari doesn't support date inputs"
128
+ session.fill_in('form_date', with: '06/19/1983')
129
+ session.click_button('awesome')
130
+ expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date
131
+ end
132
+
133
+ it 'should fill in a time input with a String' do
134
+ # Safari doesn't support time inputs - so this is just a text input
135
+ session.fill_in('form_time', with: '06:30A')
136
+ session.click_button('awesome')
137
+ results = extract_results(session)['time']
138
+ expect(Time.parse(results).strftime('%r')).to eq datetime.strftime('%r')
139
+ end
140
+
141
+ it 'should fill in a datetime input with a String' do
142
+ pending "Safari doesn't support datetime inputs"
143
+ session.fill_in('form_datetime', with: "06/19/1983\t06:30A")
144
+ session.click_button('awesome')
145
+ expect(Time.parse(extract_results(session)['datetime'])).to eq datetime
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,292 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Capybara::Server do
6
+ it 'should spool up a rack server' do
7
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
8
+ server = described_class.new(app).boot
9
+
10
+ res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
11
+
12
+ expect(res.body).to include('Hello Server')
13
+ end
14
+
15
+ it 'should do nothing when no server given' do
16
+ expect do
17
+ described_class.new(nil).boot
18
+ end.not_to raise_error
19
+ end
20
+
21
+ it 'should bind to the specified host' do
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['TRAVIS'] && (RUBY_ENGINE == 'jruby')) || Gem.win_platform?
24
+
25
+ begin
26
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
27
+
28
+ Capybara.server_host = '127.0.0.1'
29
+ server = described_class.new(app).boot
30
+ res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
31
+ expect(res).to eq('Hello Server!')
32
+
33
+ Capybara.server_host = '0.0.0.0'
34
+ server = described_class.new(app).boot
35
+ res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
36
+ expect(res).to eq('Hello Server!')
37
+ ensure
38
+ Capybara.server_host = nil
39
+ end
40
+ end
41
+
42
+ it 'should use specified port' do
43
+ Capybara.server_port = 22789
44
+
45
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
46
+ server = described_class.new(app).boot
47
+
48
+ res = Net::HTTP.start(server.host, 22789) { |http| http.get('/') }
49
+ expect(res.body).to include('Hello Server')
50
+
51
+ Capybara.server_port = nil
52
+ end
53
+
54
+ it 'should use given port' do
55
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
56
+ server = described_class.new(app, port: 22790).boot
57
+
58
+ res = Net::HTTP.start(server.host, 22790) { |http| http.get('/') }
59
+ expect(res.body).to include('Hello Server')
60
+
61
+ Capybara.server_port = nil
62
+ end
63
+
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 }
70
+
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
76
+
77
+ it 'should handle that getting available ports fails randomly' do
78
+ begin
79
+ # Use a port to force a EADDRINUSE error to be generated
80
+ server = TCPServer.new('0.0.0.0', 0)
81
+ server_port = server.addr[1]
82
+ d_server = instance_double('TCPServer', addr: [nil, server_port, nil, nil], close: nil)
83
+ call_count = 0
84
+ allow(TCPServer).to receive(:new).and_wrap_original do |m, *args|
85
+ begin
86
+ call_count.zero? ? d_server : m.call(*args)
87
+ ensure
88
+ call_count += 1
89
+ end
90
+ end
91
+
92
+ port = described_class.new(Object.new, host: '0.0.0.0').port
93
+ expect(port).not_to eq(server_port)
94
+ ensure
95
+ server&.close
96
+ end
97
+ end
98
+
99
+ it 'should return its #base_url' do
100
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
101
+ server = described_class.new(app).boot
102
+ uri = ::Addressable::URI.parse(server.base_url)
103
+ expect(uri.to_hash).to include(scheme: 'http', host: server.host, port: server.port)
104
+ end
105
+
106
+ it 'should support SSL' do
107
+ begin
108
+ key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem')
109
+ cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem')
110
+ Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" }
111
+ app = proc { |_env| [200, {}, ['Hello SSL Server!']] }
112
+ server = described_class.new(app).boot
113
+
114
+ expect do
115
+ Net::HTTP.start(server.host, server.port, max_retries: 0) { |http| http.get('/__identify__') }
116
+ end.to(raise_error do |e|
117
+ expect(e.is_a?(EOFError) || e.is_a?(Net::ReadTimeout)).to be true
118
+ end)
119
+
120
+ res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
121
+ https.get('/')
122
+ end
123
+
124
+ expect(res.body).to include('Hello SSL Server!')
125
+ uri = ::Addressable::URI.parse(server.base_url)
126
+ expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port)
127
+ ensure
128
+ Capybara.server = :default
129
+ end
130
+ end
131
+
132
+ context 'When Capybara.reuse_server is true' do
133
+ let!(:old_reuse_server) { Capybara.reuse_server }
134
+
135
+ before do
136
+ Capybara.reuse_server = true
137
+ end
138
+
139
+ after do
140
+ Capybara.reuse_server = old_reuse_server
141
+ end
142
+
143
+ it 'should use the existing server if it already running' do
144
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
145
+
146
+ servers = Array.new(2) { described_class.new(app).boot }
147
+
148
+ servers.each do |server|
149
+ res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
150
+ expect(res.body).to include('Hello Server')
151
+ end
152
+
153
+ expect(servers[0].port).to eq(servers[1].port)
154
+ end
155
+
156
+ it 'detects and waits for all reused server sessions pending requests' do
157
+ done = 0
158
+
159
+ app = proc do |env|
160
+ request = Rack::Request.new(env)
161
+ sleep request.params['wait_time'].to_f
162
+ done += 1
163
+ [200, {}, ['Hello Server!']]
164
+ end
165
+
166
+ server1 = described_class.new(app).boot
167
+ server2 = described_class.new(app).boot
168
+
169
+ expect do
170
+ start_request(server1, 1.0)
171
+ start_request(server2, 3.0)
172
+ server1.wait_for_pending_requests
173
+ end.to change { done }.from(0).to(2)
174
+ expect(server2.send(:pending_requests?)).to eq(false)
175
+ end
176
+ end
177
+
178
+ context 'When Capybara.reuse_server is false' do
179
+ before do
180
+ @old_reuse_server = Capybara.reuse_server
181
+ Capybara.reuse_server = false
182
+ end
183
+
184
+ after do
185
+ Capybara.reuse_server = @old_reuse_server # rubocop:disable RSpec/InstanceVariable
186
+ end
187
+
188
+ it 'should not reuse an already running server' do
189
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
190
+
191
+ servers = Array.new(2) { described_class.new(app).boot }
192
+
193
+ servers.each do |server|
194
+ res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
195
+ expect(res.body).to include('Hello Server')
196
+ end
197
+
198
+ expect(servers[0].port).not_to eq(servers[1].port)
199
+ end
200
+
201
+ it 'detects and waits for only one sessions pending requests' do
202
+ done = 0
203
+
204
+ app = proc do |env|
205
+ request = Rack::Request.new(env)
206
+ sleep request.params['wait_time'].to_f
207
+ done += 1
208
+ [200, {}, ['Hello Server!']]
209
+ end
210
+
211
+ server1 = described_class.new(app).boot
212
+ server2 = described_class.new(app).boot
213
+
214
+ expect do
215
+ start_request(server1, 1.0)
216
+ start_request(server2, 3.0)
217
+ server1.wait_for_pending_requests
218
+ end.to change { done }.from(0).to(1)
219
+ expect(server2.send(:pending_requests?)).to eq(true)
220
+ expect do
221
+ server2.wait_for_pending_requests
222
+ end.to change { done }.from(1).to(2)
223
+ end
224
+ end
225
+
226
+ it 'should raise server errors when the server errors before the timeout' do
227
+ begin
228
+ Capybara.register_server :kaboom do
229
+ sleep 0.1
230
+ raise 'kaboom'
231
+ end
232
+ Capybara.server = :kaboom
233
+
234
+ expect do
235
+ described_class.new(proc { |e| }).boot
236
+ end.to raise_error(RuntimeError, 'kaboom')
237
+ ensure
238
+ Capybara.server = :default
239
+ end
240
+ end
241
+
242
+ it 'should raise an error when there are pending requests' do
243
+ app = proc do |env|
244
+ request = Rack::Request.new(env)
245
+ sleep request.params['wait_time'].to_f
246
+ [200, {}, ['Hello Server!']]
247
+ end
248
+
249
+ server = described_class.new(app).boot
250
+
251
+ expect do
252
+ start_request(server, 59.0)
253
+ server.wait_for_pending_requests
254
+ end.not_to raise_error
255
+
256
+ expect do
257
+ start_request(server, 61.0)
258
+ server.wait_for_pending_requests
259
+ end.to raise_error('Requests did not finish in 60 seconds: ["/?wait_time=61.0"]')
260
+ end
261
+
262
+ it 'is not #responsive? when Net::HTTP raises a SystemCallError' do
263
+ app = -> { [200, {}, ['Hello, world']] }
264
+ server = described_class.new(app)
265
+ allow(Net::HTTP).to receive(:start).and_raise(SystemCallError.allocate)
266
+ expect(server.responsive?).to eq false
267
+ end
268
+
269
+ [EOFError, Net::ReadTimeout].each do |err|
270
+ it "should attempt an HTTPS connection if HTTP connection returns #{err}" do
271
+ app = -> { [200, {}, ['Hello, world']] }
272
+ ordered_errors = [Errno::ECONNREFUSED, err]
273
+ allow(Net::HTTP).to receive(:start).with(anything, anything, hash_excluding(:use_ssl)) do
274
+ raise ordered_errors.shift
275
+ end
276
+ response = Net::HTTPSuccess.allocate
277
+ allow(response).to receive(:body).and_return app.object_id.to_s
278
+ allow(Net::HTTP).to receive(:start).with(anything, anything, hash_including(use_ssl: true)).and_return(response).once
279
+ described_class.new(app).boot
280
+ expect(Net::HTTP).to have_received(:start).exactly(3).times
281
+ end
282
+ end
283
+
284
+ def start_request(server, wait_time)
285
+ # Start request, but don't wait for it to finish
286
+ socket = TCPSocket.new(server.host, server.port)
287
+ socket.write "GET /?wait_time=#{wait_time} HTTP/1.0\r\n\r\n"
288
+ sleep 0.1
289
+ socket.close
290
+ sleep 0.1
291
+ end
292
+ end