capybara 3.0.0 → 3.36.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 (308) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +777 -10
  4. data/License.txt +1 -1
  5. data/README.md +75 -58
  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 +34 -9
  10. data/lib/capybara/dsl.rb +14 -6
  11. data/lib/capybara/helpers.rb +52 -7
  12. data/lib/capybara/minitest/spec.rb +173 -84
  13. data/lib/capybara/minitest.rb +250 -144
  14. data/lib/capybara/node/actions.rb +248 -124
  15. data/lib/capybara/node/base.rb +34 -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 +339 -113
  19. data/lib/capybara/node/finders.rb +95 -82
  20. data/lib/capybara/node/matchers.rb +338 -157
  21. data/lib/capybara/node/simple.rb +54 -15
  22. data/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/lib/capybara/queries/ancestor_query.rb +9 -10
  24. data/lib/capybara/queries/base_query.rb +25 -18
  25. data/lib/capybara/queries/current_path_query.rb +16 -6
  26. data/lib/capybara/queries/match_query.rb +11 -0
  27. data/lib/capybara/queries/selector_query.rb +600 -103
  28. data/lib/capybara/queries/sibling_query.rb +9 -7
  29. data/lib/capybara/queries/style_query.rb +45 -0
  30. data/lib/capybara/queries/text_query.rb +40 -22
  31. data/lib/capybara/queries/title_query.rb +2 -2
  32. data/lib/capybara/rack_test/browser.rb +47 -28
  33. data/lib/capybara/rack_test/driver.rb +12 -3
  34. data/lib/capybara/rack_test/errors.rb +6 -0
  35. data/lib/capybara/rack_test/form.rb +53 -50
  36. data/lib/capybara/rack_test/node.rb +114 -37
  37. data/lib/capybara/rails.rb +1 -1
  38. data/lib/capybara/registration_container.rb +44 -0
  39. data/lib/capybara/registrations/drivers.rb +42 -0
  40. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  41. data/lib/capybara/registrations/servers.rb +45 -0
  42. data/lib/capybara/result.rb +86 -52
  43. data/lib/capybara/rspec/features.rb +8 -10
  44. data/lib/capybara/rspec/matcher_proxies.rb +39 -18
  45. data/lib/capybara/rspec/matchers/base.rb +111 -0
  46. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  47. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  48. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  49. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  50. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  51. data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
  52. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  53. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  54. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  55. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  56. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  57. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  58. data/lib/capybara/rspec/matchers.rb +138 -316
  59. data/lib/capybara/rspec.rb +3 -2
  60. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  61. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  62. data/lib/capybara/selector/css.rb +89 -12
  63. data/lib/capybara/selector/definition/button.rb +68 -0
  64. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  65. data/lib/capybara/selector/definition/css.rb +10 -0
  66. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  67. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  68. data/lib/capybara/selector/definition/element.rb +28 -0
  69. data/lib/capybara/selector/definition/field.rb +40 -0
  70. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  71. data/lib/capybara/selector/definition/file_field.rb +13 -0
  72. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  73. data/lib/capybara/selector/definition/frame.rb +17 -0
  74. data/lib/capybara/selector/definition/id.rb +6 -0
  75. data/lib/capybara/selector/definition/label.rb +62 -0
  76. data/lib/capybara/selector/definition/link.rb +54 -0
  77. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  78. data/lib/capybara/selector/definition/option.rb +27 -0
  79. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  80. data/lib/capybara/selector/definition/select.rb +81 -0
  81. data/lib/capybara/selector/definition/table.rb +109 -0
  82. data/lib/capybara/selector/definition/table_row.rb +21 -0
  83. data/lib/capybara/selector/definition/xpath.rb +5 -0
  84. data/lib/capybara/selector/definition.rb +279 -0
  85. data/lib/capybara/selector/filter.rb +1 -0
  86. data/lib/capybara/selector/filter_set.rb +72 -27
  87. data/lib/capybara/selector/filters/base.rb +45 -2
  88. data/lib/capybara/selector/filters/expression_filter.rb +5 -6
  89. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  90. data/lib/capybara/selector/filters/node_filter.rb +18 -4
  91. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  92. data/lib/capybara/selector/selector.rb +85 -200
  93. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  94. data/lib/capybara/selector.rb +226 -537
  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 +296 -238
  100. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  101. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -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 +76 -0
  110. data/lib/capybara/selenium/logger_suppressor.rb +40 -0
  111. data/lib/capybara/selenium/node.rb +436 -166
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +104 -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/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 +45 -0
  121. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  122. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  123. data/lib/capybara/server/animation_disabler.rb +69 -0
  124. data/lib/capybara/server/checker.rb +44 -0
  125. data/lib/capybara/server/middleware.rb +71 -0
  126. data/lib/capybara/server.rb +58 -67
  127. data/lib/capybara/session/config.rb +38 -6
  128. data/lib/capybara/session/matchers.rb +26 -19
  129. data/lib/capybara/session.rb +258 -190
  130. data/lib/capybara/spec/public/jquery.js +5 -5
  131. data/lib/capybara/spec/public/offset.js +6 -0
  132. data/lib/capybara/spec/public/test.js +122 -8
  133. data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
  134. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
  135. data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
  136. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  137. data/lib/capybara/spec/session/all_spec.rb +135 -42
  138. data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
  139. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
  140. data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
  141. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  142. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  143. data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +62 -38
  144. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +12 -12
  145. data/lib/capybara/spec/session/attach_file_spec.rb +120 -72
  146. data/lib/capybara/spec/session/body_spec.rb +11 -13
  147. data/lib/capybara/spec/session/check_spec.rb +111 -51
  148. data/lib/capybara/spec/session/choose_spec.rb +62 -30
  149. data/lib/capybara/spec/session/click_button_spec.rb +227 -161
  150. data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
  151. data/lib/capybara/spec/session/click_link_spec.rb +78 -55
  152. data/lib/capybara/spec/session/current_scope_spec.rb +7 -7
  153. data/lib/capybara/spec/session/current_url_spec.rb +44 -37
  154. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
  155. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
  156. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  157. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  158. data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
  159. data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
  160. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
  161. data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
  162. data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
  163. data/lib/capybara/spec/session/fill_in_spec.rb +104 -44
  164. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  165. data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
  166. data/lib/capybara/spec/session/find_field_spec.rb +33 -31
  167. data/lib/capybara/spec/session/find_link_spec.rb +32 -14
  168. data/lib/capybara/spec/session/find_spec.rb +236 -141
  169. data/lib/capybara/spec/session/first_spec.rb +44 -43
  170. data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
  171. data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
  172. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
  173. data/lib/capybara/spec/session/frame/within_frame_spec.rb +44 -19
  174. data/lib/capybara/spec/session/go_back_spec.rb +1 -1
  175. data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
  176. data/lib/capybara/spec/session/has_all_selectors_spec.rb +18 -18
  177. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  178. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  179. data/lib/capybara/spec/session/has_button_spec.rb +92 -12
  180. data/lib/capybara/spec/session/has_css_spec.rb +271 -137
  181. data/lib/capybara/spec/session/has_current_path_spec.rb +48 -33
  182. data/lib/capybara/spec/session/has_field_spec.rb +137 -58
  183. data/lib/capybara/spec/session/has_link_spec.rb +30 -6
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +26 -24
  185. data/lib/capybara/spec/session/has_select_spec.rb +75 -47
  186. data/lib/capybara/spec/session/has_selector_spec.rb +102 -69
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +170 -4
  189. data/lib/capybara/spec/session/has_text_spec.rb +108 -52
  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 +35 -0
  195. data/lib/capybara/spec/session/node_spec.rb +871 -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 +52 -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 +117 -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 +40 -21
  212. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  213. data/lib/capybara/spec/session/visit_spec.rb +59 -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 +10 -7
  221. data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
  222. data/lib/capybara/spec/session/within_spec.rb +69 -44
  223. data/lib/capybara/spec/spec_helper.rb +41 -53
  224. data/lib/capybara/spec/test_app.rb +79 -40
  225. data/lib/capybara/spec/views/animated.erb +49 -0
  226. data/lib/capybara/spec/views/form.erb +134 -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 +43 -10
  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_other.erb +6 -0
  255. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  256. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  257. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  258. data/lib/capybara/spec/views/with_windows.erb +1 -1
  259. data/lib/capybara/spec/views/within_frames.erb +1 -1
  260. data/lib/capybara/version.rb +1 -1
  261. data/lib/capybara/window.rb +31 -25
  262. data/lib/capybara.rb +120 -100
  263. data/spec/basic_node_spec.rb +59 -34
  264. data/spec/capybara_spec.rb +54 -52
  265. data/spec/css_builder_spec.rb +101 -0
  266. data/spec/css_splitter_spec.rb +38 -0
  267. data/spec/dsl_spec.rb +80 -53
  268. data/spec/filter_set_spec.rb +24 -7
  269. data/spec/fixtures/certificate.pem +25 -0
  270. data/spec/fixtures/key.pem +27 -0
  271. data/spec/fixtures/selenium_driver_rspec_failure.rb +4 -4
  272. data/spec/fixtures/selenium_driver_rspec_success.rb +4 -4
  273. data/spec/minitest_spec.rb +38 -5
  274. data/spec/minitest_spec_spec.rb +88 -62
  275. data/spec/per_session_config_spec.rb +5 -5
  276. data/spec/rack_test_spec.rb +169 -115
  277. data/spec/regexp_dissassembler_spec.rb +250 -0
  278. data/spec/result_spec.rb +86 -33
  279. data/spec/rspec/features_spec.rb +26 -23
  280. data/spec/rspec/scenarios_spec.rb +8 -4
  281. data/spec/rspec/shared_spec_matchers.rb +393 -363
  282. data/spec/rspec/views_spec.rb +4 -3
  283. data/spec/rspec_matchers_spec.rb +10 -10
  284. data/spec/rspec_spec.rb +109 -85
  285. data/spec/sauce_spec_chrome.rb +43 -0
  286. data/spec/selector_spec.rb +391 -61
  287. data/spec/selenium_spec_chrome.rb +180 -41
  288. data/spec/selenium_spec_chrome_remote.rb +101 -0
  289. data/spec/selenium_spec_edge.rb +28 -8
  290. data/spec/selenium_spec_firefox.rb +211 -0
  291. data/spec/selenium_spec_firefox_remote.rb +80 -0
  292. data/spec/selenium_spec_ie.rb +127 -11
  293. data/spec/selenium_spec_safari.rb +156 -0
  294. data/spec/server_spec.rb +177 -78
  295. data/spec/session_spec.rb +52 -16
  296. data/spec/shared_selenium_node.rb +79 -0
  297. data/spec/shared_selenium_session.rb +455 -123
  298. data/spec/spec_helper.rb +91 -2
  299. data/spec/xpath_builder_spec.rb +93 -0
  300. metadata +343 -42
  301. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  302. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  303. data/.yard/yard_extensions.rb +0 -78
  304. data/lib/capybara/rspec/compound.rb +0 -90
  305. data/lib/capybara/spec/session/assert_selector.rb +0 -149
  306. data/lib/capybara/spec/session/source_spec.rb +0 -0
  307. data/lib/capybara/spec/views/with_title.erb +0 -5
  308. data/spec/selenium_spec_marionette.rb +0 -143
@@ -3,21 +3,72 @@
3
3
  require 'spec_helper'
4
4
  require 'selenium-webdriver'
5
5
  require 'shared_selenium_session'
6
+ require 'shared_selenium_node'
6
7
  require 'rspec/shared_spec_matchers'
7
8
 
8
- CHROME_DRIVER = ENV['HEADLESS'] ? :selenium_chrome_headless : :selenium_chrome
9
+ CHROME_DRIVER = :selenium_chrome
9
10
 
10
- # if ENV['HEADLESS'] && ENV['TRAVIS']
11
- # Selenium::WebDriver::Chrome.path='/usr/bin/google-chrome-beta'
12
- # end
11
+ Selenium::WebDriver::Chrome.path = '/usr/bin/google-chrome-beta' if ENV['CI'] && ENV['CHROME_BETA']
13
12
 
14
- Capybara.register_driver :selenium_chrome_clear_storage do |app|
15
- chrome_options = {
16
- browser: :chrome,
17
- options: ::Selenium::WebDriver::Chrome::Options.new
18
- }
19
- chrome_options[:options].args << 'headless' if ENV['HEADLESS']
20
- Capybara::Selenium::Driver.new(app, chrome_options.merge(clear_local_storage: true, clear_session_storage: true))
13
+ browser_options = ::Selenium::WebDriver::Chrome::Options.new
14
+ browser_options.headless! if ENV['HEADLESS']
15
+
16
+ # Chromedriver 77 requires setting this for headless mode on linux
17
+ # Different versions of Chrome/selenium-webdriver require setting differently - jus set them all
18
+ browser_options.add_preference('download.default_directory', Capybara.save_path)
19
+ browser_options.add_preference(:download, default_directory: Capybara.save_path)
20
+
21
+ Capybara.register_driver :selenium_chrome do |app|
22
+ version = Capybara::Selenium::Driver.load_selenium
23
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
24
+ driver_options = { browser: :chrome, timeout: 30 }.tap do |opts|
25
+ opts[options_key] = browser_options
26
+ end
27
+
28
+ Capybara::Selenium::Driver.new(app, **driver_options).tap do |driver|
29
+ # Set download dir for Chrome < 77
30
+ driver.browser.download_path = Capybara.save_path
31
+ end
32
+ end
33
+
34
+ Capybara.register_driver :selenium_chrome_not_clear_storage do |app|
35
+ version = Capybara::Selenium::Driver.load_selenium
36
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
37
+ chrome_options = { browser: :chrome, clear_local_storage: false, clear_session_storage: false }.tap do |opts|
38
+ opts[options_key] = browser_options
39
+ end
40
+
41
+ Capybara::Selenium::Driver.new(app, **chrome_options)
42
+ end
43
+
44
+ Capybara.register_driver :selenium_chrome_not_clear_session_storage do |app|
45
+ version = Capybara::Selenium::Driver.load_selenium
46
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
47
+ chrome_options = { browser: :chrome, clear_session_storage: false }.tap do |opts|
48
+ opts[options_key] = browser_options
49
+ end
50
+
51
+ Capybara::Selenium::Driver.new(app, **chrome_options)
52
+ end
53
+
54
+ Capybara.register_driver :selenium_chrome_not_clear_local_storage do |app|
55
+ version = Capybara::Selenium::Driver.load_selenium
56
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
57
+ chrome_options = { browser: :chrome, clear_local_storage: false }.tap do |opts|
58
+ opts[options_key] = browser_options
59
+ end
60
+ Capybara::Selenium::Driver.new(app, **chrome_options)
61
+ end
62
+
63
+ Capybara.register_driver :selenium_driver_subclass_with_chrome do |app|
64
+ version = Capybara::Selenium::Driver.load_selenium
65
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
66
+ subclass = Class.new(Capybara::Selenium::Driver)
67
+ chrome_options = { browser: :chrome, timeout: 30 }.tap do |opts|
68
+ opts[options_key] = browser_options
69
+ end
70
+
71
+ subclass.new(app, **chrome_options)
21
72
  end
22
73
 
23
74
  module TestSessions
@@ -25,43 +76,131 @@ module TestSessions
25
76
  end
26
77
 
27
78
  skipped_tests = %i[response_headers status_code trigger]
28
- # skip window tests when headless for now - closing a window not supported by chromedriver/chrome
29
- skipped_tests << :windows if ENV['TRAVIS'] && (ENV['SKIP_WINDOW'] || ENV['HEADLESS'])
30
79
 
31
- $stdout.puts `#{Selenium::WebDriver::Chrome.driver_path} --version` if ENV['CI']
80
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Chrome) if ENV['CI']
32
81
 
33
- Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybara_skip: skipped_tests
82
+ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybara_skip: skipped_tests do |example|
83
+ case example.metadata[:full_description]
84
+ when /#click_link can download a file$/
85
+ skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
86
+ when /Capybara::Session selenium_chrome Capybara::Window#maximize/
87
+ pending "Chrome headless doesn't support maximize" if ENV['HEADLESS']
88
+ end
89
+ end
34
90
 
35
- RSpec.describe "Capybara::Session with chrome" do
91
+ RSpec.describe 'Capybara::Session with chrome' do
36
92
  include Capybara::SpecHelper
37
- include_examples "Capybara::Session", TestSessions::Chrome, CHROME_DRIVER
38
- include_examples Capybara::RSpecMatchers, TestSessions::Chrome, CHROME_DRIVER
39
-
40
- context "storage" do
41
- describe "#reset!" do
42
- it "does not clear either storage by default" do
43
- @session = TestSessions::Chrome
44
- @session.visit('/with_js')
45
- @session.find(:css, '#set-storage').click
46
- @session.reset!
47
- @session.visit('/with_js')
48
- # expect(@session.driver.browser.local_storage.keys).not_to be_empty
49
- # expect(@session.driver.browser.session_storage.keys).not_to be_empty
50
- expect(@session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
51
- expect(@session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty
93
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
94
+ include_examples examples, TestSessions::Chrome, CHROME_DRIVER
95
+ end
96
+
97
+ context 'storage' do
98
+ describe '#reset!' do
99
+ it 'clears storage by default' do
100
+ session = TestSessions::Chrome
101
+ session.visit('/with_js')
102
+ session.find(:css, '#set-storage').click
103
+ session.reset!
104
+ session.visit('/with_js')
105
+ expect(session.evaluate_script('Object.keys(localStorage)')).to be_empty
106
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
52
107
  end
53
108
 
54
- it "clears storage when set" do
55
- @session = Capybara::Session.new(:selenium_chrome_clear_storage, TestApp)
56
- @session.visit('/with_js')
57
- @session.find(:css, '#set-storage').click
58
- @session.reset!
59
- @session.visit('/with_js')
60
- # expect(@session.driver.browser.local_storage.keys).to be_empty
61
- # expect(@session.driver.browser.session_storage.keys).to be_empty
62
- expect(@session.evaluate_script('Object.keys(localStorage)')).to be_empty
63
- expect(@session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
109
+ it 'does not clear storage when false' do
110
+ session = Capybara::Session.new(:selenium_chrome_not_clear_storage, TestApp)
111
+ session.visit('/with_js')
112
+ session.find(:css, '#set-storage').click
113
+ session.reset!
114
+ session.visit('/with_js')
115
+ expect(session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
116
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty
64
117
  end
118
+
119
+ it 'can not clear session storage' do
120
+ session = Capybara::Session.new(:selenium_chrome_not_clear_session_storage, TestApp)
121
+ session.visit('/with_js')
122
+ session.find(:css, '#set-storage').click
123
+ session.reset!
124
+ session.visit('/with_js')
125
+ expect(session.evaluate_script('Object.keys(localStorage)')).to be_empty
126
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty
127
+ end
128
+
129
+ it 'can not clear local storage' do
130
+ session = Capybara::Session.new(:selenium_chrome_not_clear_local_storage, TestApp)
131
+ session.visit('/with_js')
132
+ session.find(:css, '#set-storage').click
133
+ session.reset!
134
+ session.visit('/with_js')
135
+ expect(session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
136
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
137
+ end
138
+ end
139
+ end
140
+
141
+ context 'timeout' do
142
+ it 'sets the http client read timeout' do
143
+ expect(TestSessions::Chrome.driver.browser.send(:bridge).http.read_timeout).to eq 30
144
+ end
145
+ end
146
+
147
+ describe 'filling in Chrome-specific date and time fields with keystrokes' do
148
+ let(:datetime) { Time.new(1983, 6, 19, 6, 30) }
149
+ let(:session) { TestSessions::Chrome }
150
+
151
+ before do
152
+ session.visit('/form')
153
+ end
154
+
155
+ it 'should fill in a date input with a String' do
156
+ session.fill_in('form_date', with: '06/19/1983')
157
+ session.click_button('awesome')
158
+ expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date
159
+ end
160
+
161
+ it 'should fill in a time input with a String' do
162
+ session.fill_in('form_time', with: '06:30A')
163
+ session.click_button('awesome')
164
+ results = extract_results(session)['time']
165
+ expect(Time.parse(results).strftime('%r')).to eq datetime.strftime('%r')
166
+ end
167
+
168
+ it 'should fill in a datetime input with a String' do
169
+ session.fill_in('form_datetime', with: "06/19/1983\t06:30A")
170
+ session.click_button('awesome')
171
+ expect(Time.parse(extract_results(session)['datetime'])).to eq datetime
172
+ end
173
+ end
174
+
175
+ describe 'using subclass of selenium driver' do
176
+ it 'works' do
177
+ session = Capybara::Session.new(:selenium_driver_subclass_with_chrome, TestApp)
178
+ session.visit('/form')
179
+ expect(session).to have_current_path('/form')
180
+ end
181
+ end
182
+
183
+ describe 'log access' do
184
+ let(:logs) do
185
+ session.driver.browser.then do |chrome_driver|
186
+ chrome_driver.respond_to?(:logs) ? chrome_driver : chrome_driver.manage
187
+ end.logs
65
188
  end
189
+
190
+ it 'does not error getting log types' do
191
+ expect do
192
+ logs.available_types
193
+ end.not_to raise_error
194
+ end
195
+
196
+ it 'does not error when getting logs' do
197
+ expect do
198
+ logs.get(:browser)
199
+ end.not_to raise_error
200
+ end
201
+ end
202
+
203
+ def chromedriver_version
204
+ Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0])
66
205
  end
67
206
  end
@@ -0,0 +1,101 @@
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', 4444)
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_chrome'
26
+ else
27
+ puts 'Waiting for Selenium docker instance...'
28
+ sleep 1
29
+ retry
30
+ end
31
+ end
32
+ end
33
+
34
+ def selenium_gte?(version)
35
+ defined?(Selenium::WebDriver::VERSION) && (Selenium::WebDriver::VERSION.to_f >= version)
36
+ end
37
+
38
+ Capybara.register_driver :selenium_chrome_remote do |app|
39
+ ensure_selenium_running!
40
+
41
+ url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
42
+ browser_options = ::Selenium::WebDriver::Chrome::Options.new
43
+
44
+ Capybara::Selenium::Driver.new app,
45
+ browser: :remote,
46
+ desired_capabilities: :chrome,
47
+ options: browser_options,
48
+ url: url
49
+ end
50
+
51
+ CHROME_REMOTE_DRIVER = :selenium_chrome_remote
52
+
53
+ module TestSessions
54
+ Chrome = Capybara::Session.new(CHROME_REMOTE_DRIVER, TestApp)
55
+ end
56
+
57
+ skipped_tests = %i[response_headers status_code trigger download]
58
+
59
+ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
60
+ case example.metadata[:full_description]
61
+ when 'Capybara::Session selenium_chrome_remote #attach_file with multipart form should not break when using HTML5 multiple file input uploading multiple files',
62
+ 'Capybara::Session selenium_chrome_remote #attach_file with multipart form should fire change once for each set of files uploaded',
63
+ 'Capybara::Session selenium_chrome_remote #attach_file with multipart form should fire change once when uploading multiple files from empty'
64
+ pending "Selenium with Remote Chrome doesn't support multiple file upload" unless selenium_gte?(3.14)
65
+ end
66
+ end
67
+
68
+ RSpec.describe 'Capybara::Session with remote Chrome' do
69
+ include Capybara::SpecHelper
70
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
71
+ include_examples examples, TestSessions::Chrome, CHROME_REMOTE_DRIVER
72
+ end
73
+
74
+ it 'is considered to be chrome' do
75
+ expect(session.driver.browser.browser).to eq :chrome
76
+ end
77
+
78
+ describe 'log access' do
79
+ let(:logs) do
80
+ session.driver.browser.then do |chrome_driver|
81
+ chrome_driver.respond_to?(:logs) ? chrome_driver : chrome_driver.manage
82
+ end.logs
83
+ end
84
+
85
+ it 'does not error when getting log types' do
86
+ expect do
87
+ logs.available_types
88
+ end.not_to raise_error
89
+ end
90
+
91
+ it 'does not error when getting logs' do
92
+ expect do
93
+ logs.get(:browser)
94
+ end.not_to raise_error
95
+ end
96
+ end
97
+
98
+ def chromedriver_version
99
+ Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0])
100
+ end
101
+ end
@@ -1,27 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
- require "selenium-webdriver"
4
+ require 'selenium-webdriver'
5
5
  require 'shared_selenium_session'
6
+ require 'shared_selenium_node'
6
7
  require 'rspec/shared_spec_matchers'
7
8
 
9
+ # unless ENV['CI']
10
+ # Selenium::WebDriver::Edge::Service.driver_path = '/usr/local/bin/msedgedriver'
11
+ # end
12
+
13
+ if ::Selenium::WebDriver::Platform.mac?
14
+ Selenium::WebDriver::EdgeChrome.path = '/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev'
15
+ end
16
+
8
17
  Capybara.register_driver :selenium_edge do |app|
9
18
  # ::Selenium::WebDriver.logger.level = "debug"
10
- Capybara::Selenium::Driver.new(app, browser: :edge)
19
+ # If we don't create an options object the path set above won't be used
20
+ browser_options = ::Selenium::WebDriver::EdgeChrome::Options.new
21
+ Capybara::Selenium::Driver.new(app, browser: :edge_chrome, options: browser_options).tap do |driver|
22
+ driver.browser
23
+ driver.download_path = Capybara.save_path
24
+ end
11
25
  end
12
26
 
13
27
  module TestSessions
14
28
  SeleniumEdge = Capybara::Session.new(:selenium_edge, TestApp)
15
29
  end
16
30
 
17
- skipped_tests = %i[response_headers status_code trigger modals]
31
+ skipped_tests = %i[response_headers status_code trigger]
18
32
 
19
- $stdout.puts `#{Selenium::WebDriver::Edge.driver_path} --version` if ENV['CI']
33
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::EdgeChrome) if ENV['CI']
20
34
 
21
- Capybara::SpecHelper.run_specs TestSessions::SeleniumEdge, "selenium", capybara_skip: skipped_tests
35
+ Capybara::SpecHelper.run_specs TestSessions::SeleniumEdge, 'selenium', capybara_skip: skipped_tests do |example|
36
+ case example.metadata[:full_description]
37
+ when 'Capybara::Session selenium #attach_file with a block can upload by clicking the file input'
38
+ pending "EdgeChrome doesn't allow clicking on file inputs"
39
+ end
40
+ end
22
41
 
23
- RSpec.describe "Capybara::Session with Edge", capybara_skip: skipped_tests do
42
+ RSpec.describe 'Capybara::Session with Edge', capybara_skip: skipped_tests do
24
43
  include Capybara::SpecHelper
25
- include_examples "Capybara::Session", TestSessions::SeleniumEdge, :selenium_edge
26
- include_examples Capybara::RSpecMatchers, TestSessions::SeleniumEdge, :selenium_edge
44
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
45
+ include_examples examples, TestSessions::SeleniumEdge, :selenium_edge
46
+ end
27
47
  end
@@ -0,0 +1,211 @@
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
+ browser_options = ::Selenium::WebDriver::Firefox::Options.new
10
+ browser_options.headless! if ENV['HEADLESS']
11
+ # browser_options.add_option("log", {"level": "trace"})
12
+
13
+ browser_options.profile = Selenium::WebDriver::Firefox::Profile.new.tap do |profile|
14
+ profile['browser.download.dir'] = Capybara.save_path
15
+ profile['browser.download.folderList'] = 2
16
+ profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv'
17
+ profile['browser.startup.homepage'] = 'about:blank' # workaround bug in Selenium 4 alpha4-7
18
+ profile['accessibility.tabfocus'] = 7 # make tab move over links too
19
+ end
20
+
21
+ Capybara.register_driver :selenium_firefox do |app|
22
+ # ::Selenium::WebDriver.logger.level = "debug"
23
+ version = Capybara::Selenium::Driver.load_selenium
24
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
25
+ driver_options = { browser: :firefox, timeout: 31 }.tap do |opts|
26
+ opts[options_key] = browser_options
27
+ # Get a trace level log from geckodriver
28
+ # :driver_opts => { args: ['-vv'] }
29
+ end
30
+
31
+ Capybara::Selenium::Driver.new(app, **driver_options)
32
+ end
33
+
34
+ Capybara.register_driver :selenium_firefox_not_clear_storage do |app|
35
+ version = Capybara::Selenium::Driver.load_selenium
36
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
37
+ driver_options = { browser: :firefox, clear_local_storage: false, clear_session_storage: false }.tap do |opts|
38
+ opts[options_key] = browser_options
39
+ end
40
+
41
+ Capybara::Selenium::Driver.new(app, **driver_options)
42
+ end
43
+
44
+ module TestSessions
45
+ SeleniumFirefox = Capybara::Session.new(:selenium_firefox, TestApp)
46
+ end
47
+
48
+ skipped_tests = %i[response_headers status_code trigger]
49
+
50
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Firefox) if ENV['CI']
51
+
52
+ Capybara::SpecHelper.run_specs TestSessions::SeleniumFirefox, 'selenium', capybara_skip: skipped_tests do |example|
53
+ case example.metadata[:full_description]
54
+ when 'Capybara::Session selenium node #click should allow multiple modifiers'
55
+ pending "Firefox on OSX doesn't generate an event for shift+control+click" if firefox_gte?(62, @session) && Selenium::WebDriver::Platform.mac?
56
+ when /^Capybara::Session selenium node #double_click/
57
+ pending "selenium-webdriver/geckodriver doesn't generate double click event" if firefox_lt?(59, @session)
58
+ when 'Capybara::Session selenium #accept_prompt should accept the prompt with a blank response when there is a default'
59
+ 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)
60
+ when 'Capybara::Session selenium #attach_file with multipart form should fire change once when uploading multiple files from empty'
61
+ pending "FF < 62 doesn't support setting all files at once" if firefox_lt?(62, @session)
62
+ when 'Capybara::Session selenium #accept_confirm should work with nested modals'
63
+ skip 'Broken in 63 <= FF < 69 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session) && firefox_lt?(69, @session)
64
+ skip 'Hangs in 69 <= FF < 71 - Dont know what issue for this - previous issue was closed as fixed but it is not' if firefox_gte?(69, @session) && firefox_lt?(71, @session)
65
+ skip 'Broken again intermittently in FF 71 - jus skip it'
66
+ when 'Capybara::Session selenium #click_link can download a file'
67
+ skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
68
+ when 'Capybara::Session selenium #reset_session! removes ALL cookies'
69
+ pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
70
+ when /drag_to.*HTML5/
71
+ pending "Firefox < 62 doesn't support a DataTransfer constuctor" if firefox_lt?(62.0, @session)
72
+ when 'Capybara::Session selenium #accept_alert should handle the alert if the page changes',
73
+ 'Capybara::Session selenium #accept_alert with an asynchronous alert should accept the alert'
74
+ skip 'No clue what Firefox is doing here - works fine on MacOS locally'
75
+ end
76
+ end
77
+
78
+ RSpec.describe 'Capybara::Session with firefox' do # rubocop:disable RSpec/MultipleDescribes
79
+ include Capybara::SpecHelper
80
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
81
+ include_examples examples, TestSessions::SeleniumFirefox, :selenium_firefox
82
+ end
83
+
84
+ describe 'filling in Firefox-specific date and time fields with keystrokes' do
85
+ let(:datetime) { Time.new(1983, 6, 19, 6, 30) }
86
+ let(:session) { TestSessions::SeleniumFirefox }
87
+
88
+ before do
89
+ session.visit('/form')
90
+ end
91
+
92
+ it 'should fill in a date input with a String' do
93
+ session.fill_in('form_date', with: datetime.to_date.iso8601)
94
+ session.click_button('awesome')
95
+ expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date
96
+ end
97
+
98
+ it 'should fill in a time input with a String' do
99
+ session.fill_in('form_time', with: datetime.to_time.strftime('%T'))
100
+ session.click_button('awesome')
101
+ results = extract_results(session)['time']
102
+ expect(Time.parse(results).strftime('%r')).to eq datetime.strftime('%r')
103
+ end
104
+
105
+ it 'should fill in a datetime input with a String' do
106
+ pending "Need to figure out what string format this will actually accept"
107
+ session.fill_in('form_datetime', with: datetime.iso8601)
108
+ session.click_button('awesome')
109
+ expect(Time.parse(extract_results(session)['datetime'])).to eq datetime
110
+ end
111
+ end
112
+ end
113
+
114
+ RSpec.describe Capybara::Selenium::Driver do
115
+ let(:driver) { described_class.new(TestApp, browser: :firefox, options: browser_options) }
116
+
117
+ describe '#quit' do
118
+ it 'should reset browser when quit' do
119
+ expect(driver.browser).to be_truthy
120
+ driver.quit
121
+ # access instance variable directly so we don't create a new browser instance
122
+ expect(driver.instance_variable_get(:@browser)).to be_nil
123
+ end
124
+
125
+ context 'with errors' do
126
+ let!(:original_browser) { driver.browser }
127
+
128
+ after do
129
+ # Ensure browser is actually quit so we don't leave hanging processe
130
+ RSpec::Mocks.space.proxy_for(original_browser).reset
131
+ original_browser.quit
132
+ end
133
+
134
+ it 'warns UnknownError returned during quit because the browser is probably already gone' do
135
+ allow(driver).to receive(:warn)
136
+ allow(driver.browser).to(
137
+ receive(:quit)
138
+ .and_raise(Selenium::WebDriver::Error::UnknownError, 'random message')
139
+ )
140
+
141
+ expect { driver.quit }.not_to raise_error
142
+ expect(driver.instance_variable_get(:@browser)).to be_nil
143
+ expect(driver).to have_received(:warn).with(/random message/)
144
+ end
145
+
146
+ it 'ignores silenced UnknownError returned during quit because the browser is almost definitely already gone' do
147
+ allow(driver).to receive(:warn)
148
+ allow(driver.browser).to(
149
+ receive(:quit)
150
+ .and_raise(Selenium::WebDriver::Error::UnknownError, 'Error communicating with the remote browser')
151
+ )
152
+
153
+ expect { driver.quit }.not_to raise_error
154
+ expect(driver.instance_variable_get(:@browser)).to be_nil
155
+ expect(driver).not_to have_received(:warn)
156
+ end
157
+ end
158
+ end
159
+
160
+ context 'storage' do
161
+ describe '#reset!' do
162
+ it 'clears storage by default' do
163
+ session = TestSessions::SeleniumFirefox
164
+ session.visit('/with_js')
165
+ session.find(:css, '#set-storage').click
166
+ session.reset!
167
+ session.visit('/with_js')
168
+ expect(session.driver.browser.local_storage.keys).to be_empty
169
+ expect(session.driver.browser.session_storage.keys).to be_empty
170
+ end
171
+
172
+ it 'does not clear storage when false' do
173
+ session = Capybara::Session.new(:selenium_firefox_not_clear_storage, TestApp)
174
+ session.visit('/with_js')
175
+ session.find(:css, '#set-storage').click
176
+ session.reset!
177
+ session.visit('/with_js')
178
+ expect(session.driver.browser.local_storage.keys).not_to be_empty
179
+ expect(session.driver.browser.session_storage.keys).not_to be_empty
180
+ end
181
+ end
182
+ end
183
+
184
+ context 'timeout' do
185
+ it 'sets the http client read timeout' do
186
+ expect(TestSessions::SeleniumFirefox.driver.browser.send(:bridge).http.read_timeout).to eq 31
187
+ end
188
+ end
189
+ end
190
+
191
+ RSpec.describe Capybara::Selenium::Node do
192
+ describe '#click' do
193
+ it 'warns when attempting on a table row' do
194
+ session = TestSessions::SeleniumFirefox
195
+ session.visit('/tables')
196
+ tr = session.find(:css, '#agent_table tr:first-child')
197
+ allow(tr.base).to receive(:warn)
198
+ tr.click
199
+ expect(tr.base).to have_received(:warn).with(/Clicking the first cell in the row instead/)
200
+ end
201
+
202
+ it 'should allow multiple modifiers', requires: [:js] do
203
+ session = TestSessions::SeleniumFirefox
204
+ session.visit('with_js')
205
+ # Firefox v62+ doesn't generate an event for control+shift+click
206
+ session.find(:css, '#click-test').click(:alt, :ctrl, :meta)
207
+ # it also triggers a contextmenu event when control is held so don't check click type
208
+ expect(session).to have_link('Has been alt control meta')
209
+ end
210
+ end
211
+ end