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
@@ -3,21 +3,77 @@
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.fetch('CI', nil) && ENV.fetch('CHROME_BETA', nil)
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
+ Selenium::WebDriver.logger.ignore(:selenium_manager)
14
+
15
+ browser_options = if ENV['HEADLESS']
16
+ Selenium::WebDriver::Options.chrome(args: ['--headless=new'])
17
+ else
18
+ Selenium::WebDriver::Options.chrome
19
+ end
20
+
21
+ # Chromedriver 77 requires setting this for headless mode on linux
22
+ # Different versions of Chrome/selenium-webdriver require setting differently - jus set them all
23
+ browser_options.add_preference('download.default_directory', Capybara.save_path)
24
+ browser_options.add_preference(:download, default_directory: Capybara.save_path)
25
+
26
+ Capybara.register_driver :selenium_chrome do |app|
27
+ version = Capybara::Selenium::Driver.load_selenium
28
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
29
+ driver_options = { browser: :chrome, timeout: 30 }.tap do |opts|
30
+ opts[options_key] = browser_options
31
+ end
32
+
33
+ Capybara::Selenium::Driver.new(app, **driver_options).tap do |driver|
34
+ # Set download dir for Chrome < 77
35
+ driver.browser.download_path = Capybara.save_path
36
+ end
37
+ end
38
+
39
+ Capybara.register_driver :selenium_chrome_not_clear_storage do |app|
40
+ version = Capybara::Selenium::Driver.load_selenium
41
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
42
+ chrome_options = { browser: :chrome, clear_local_storage: false, clear_session_storage: false }.tap do |opts|
43
+ opts[options_key] = browser_options
44
+ end
45
+
46
+ Capybara::Selenium::Driver.new(app, **chrome_options)
47
+ end
48
+
49
+ Capybara.register_driver :selenium_chrome_not_clear_session_storage do |app|
50
+ version = Capybara::Selenium::Driver.load_selenium
51
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
52
+ chrome_options = { browser: :chrome, clear_session_storage: false }.tap do |opts|
53
+ opts[options_key] = browser_options
54
+ end
55
+
56
+ Capybara::Selenium::Driver.new(app, **chrome_options)
57
+ end
58
+
59
+ Capybara.register_driver :selenium_chrome_not_clear_local_storage do |app|
60
+ version = Capybara::Selenium::Driver.load_selenium
61
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
62
+ chrome_options = { browser: :chrome, clear_local_storage: false }.tap do |opts|
63
+ opts[options_key] = browser_options
64
+ end
65
+ Capybara::Selenium::Driver.new(app, **chrome_options)
66
+ end
67
+
68
+ Capybara.register_driver :selenium_driver_subclass_with_chrome do |app|
69
+ version = Capybara::Selenium::Driver.load_selenium
70
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
71
+ subclass = Class.new(Capybara::Selenium::Driver)
72
+ chrome_options = { browser: :chrome, timeout: 30 }.tap do |opts|
73
+ opts[options_key] = browser_options
74
+ end
75
+
76
+ subclass.new(app, **chrome_options)
21
77
  end
22
78
 
23
79
  module TestSessions
@@ -25,43 +81,129 @@ module TestSessions
25
81
  end
26
82
 
27
83
  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
84
 
31
- $stdout.puts `#{Selenium::WebDriver::Chrome.driver_path} --version` if ENV['CI']
85
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Chrome) if ENV['CI']
32
86
 
33
- Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybara_skip: skipped_tests
87
+ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybara_skip: skipped_tests do |example|
88
+ case example.metadata[:full_description]
89
+ when /#click_link can download a file$/
90
+ skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
91
+ when /Capybara::Session selenium_chrome node #shadow_root should get visible text/
92
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
93
+ when /Capybara::Session selenium_chrome node #shadow_root/
94
+ skip 'Not supported with this chromedriver version' if chromedriver_lt?('96.0', @session)
95
+ end
96
+ end
34
97
 
35
- RSpec.describe "Capybara::Session with chrome" do
98
+ RSpec.describe 'Capybara::Session with chrome' do
36
99
  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
100
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
101
+ include_examples examples, TestSessions::Chrome, CHROME_DRIVER
102
+ end
103
+
104
+ context 'storage' do
105
+ describe '#reset!' do
106
+ it 'clears storage by default' do
107
+ session = TestSessions::Chrome
108
+ session.visit('/with_js')
109
+ session.find(:css, '#set-storage').click
110
+ session.reset!
111
+ session.visit('/with_js')
112
+ expect(session.evaluate_script('Object.keys(localStorage)')).to be_empty
113
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
52
114
  end
53
115
 
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
116
+ it 'does not clear storage when false' do
117
+ session = Capybara::Session.new(:selenium_chrome_not_clear_storage, TestApp)
118
+ session.visit('/with_js')
119
+ session.find(:css, '#set-storage').click
120
+ session.reset!
121
+ session.visit('/with_js')
122
+ expect(session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
123
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty
64
124
  end
125
+
126
+ it 'can not clear session storage' do
127
+ session = Capybara::Session.new(:selenium_chrome_not_clear_session_storage, TestApp)
128
+ session.visit('/with_js')
129
+ session.find(:css, '#set-storage').click
130
+ session.reset!
131
+ session.visit('/with_js')
132
+ expect(session.evaluate_script('Object.keys(localStorage)')).to be_empty
133
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty
134
+ end
135
+
136
+ it 'can not clear local storage' do
137
+ session = Capybara::Session.new(:selenium_chrome_not_clear_local_storage, TestApp)
138
+ session.visit('/with_js')
139
+ session.find(:css, '#set-storage').click
140
+ session.reset!
141
+ session.visit('/with_js')
142
+ expect(session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
143
+ expect(session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
144
+ end
145
+ end
146
+ end
147
+
148
+ context 'timeout' do
149
+ it 'sets the http client read timeout' do
150
+ expect(TestSessions::Chrome.driver.browser.send(:bridge).http.read_timeout).to eq 30
151
+ end
152
+ end
153
+
154
+ describe 'filling in Chrome-specific date and time fields with keystrokes' do
155
+ let(:datetime) { Time.new(1983, 6, 19, 6, 30) }
156
+ let(:session) { TestSessions::Chrome }
157
+
158
+ before do
159
+ session.visit('/form')
160
+ end
161
+
162
+ it 'should fill in a date input with a String' do
163
+ session.fill_in('form_date', with: '06/19/1983')
164
+ session.click_button('awesome')
165
+ expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date
166
+ end
167
+
168
+ it 'should fill in a time input with a String' do
169
+ session.fill_in('form_time', with: '06:30A')
170
+ session.click_button('awesome')
171
+ results = extract_results(session)['time']
172
+ expect(Time.parse(results).strftime('%r')).to eq datetime.strftime('%r')
173
+ end
174
+
175
+ it 'should fill in a datetime input with a String' do
176
+ session.fill_in('form_datetime', with: "06/19/1983\t06:30A")
177
+ session.click_button('awesome')
178
+ expect(Time.parse(extract_results(session)['datetime'])).to eq datetime
179
+ end
180
+ end
181
+
182
+ describe 'using subclass of selenium driver' do
183
+ it 'works' do
184
+ session = Capybara::Session.new(:selenium_driver_subclass_with_chrome, TestApp)
185
+ session.visit('/form')
186
+ expect(session).to have_current_path('/form')
187
+ end
188
+ end
189
+
190
+ describe 'log access' do
191
+ let(:logs) do
192
+ session.driver.browser.then do |chrome_driver|
193
+ chrome_driver.respond_to?(:logs) ? chrome_driver : chrome_driver.manage
194
+ end.logs
195
+ end
196
+
197
+ it 'does not error getting log types' do
198
+ expect do
199
+ logs.available_types
200
+ end.not_to raise_error
201
+ end
202
+
203
+ it 'does not error when getting logs' do
204
+ expect do
205
+ logs.get(:browser)
206
+ end.not_to raise_error
65
207
  end
66
208
  end
67
209
  end
@@ -0,0 +1,96 @@
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) && (Gem::Version.new(Selenium::WebDriver::VERSION) >= Gem::Version.new(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
+ options: browser_options,
47
+ url: url
48
+ end
49
+
50
+ CHROME_REMOTE_DRIVER = :selenium_chrome_remote
51
+
52
+ module TestSessions
53
+ Chrome = Capybara::Session.new(CHROME_REMOTE_DRIVER, TestApp)
54
+ end
55
+
56
+ skipped_tests = %i[response_headers status_code trigger download]
57
+
58
+ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
59
+ case example.metadata[:full_description]
60
+ when /Capybara::Session selenium_chrome_remote node #shadow_root should get visible text/
61
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
62
+ when /Capybara::Session selenium_chrome_remote node #shadow_root/
63
+ skip 'Not supported with this chromedriver version' if chromedriver_lt?('96.0', @session)
64
+ end
65
+ end
66
+
67
+ RSpec.describe 'Capybara::Session with remote Chrome' do
68
+ include Capybara::SpecHelper
69
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
70
+ include_examples examples, TestSessions::Chrome, CHROME_REMOTE_DRIVER
71
+ end
72
+
73
+ it 'is considered to be chrome' do
74
+ expect(session.driver.browser.browser).to eq :chrome
75
+ end
76
+
77
+ describe 'log access' do
78
+ let(:logs) do
79
+ session.driver.browser.then do |chrome_driver|
80
+ chrome_driver.respond_to?(:logs) ? chrome_driver : chrome_driver.manage
81
+ end.logs
82
+ end
83
+
84
+ it 'does not error when getting log types' do
85
+ expect do
86
+ logs.available_types
87
+ end.not_to raise_error
88
+ end
89
+
90
+ it 'does not error when getting logs' do
91
+ expect do
92
+ logs.get(:browser)
93
+ end.not_to raise_error
94
+ end
95
+ end
96
+ end
@@ -1,27 +1,60 @@
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
+ Selenium::WebDriver.logger.ignore(:selenium_manager)
14
+
15
+ if Selenium::WebDriver::Platform.mac?
16
+ Selenium::WebDriver::Edge.path = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge'
17
+ end
18
+
8
19
  Capybara.register_driver :selenium_edge do |app|
9
20
  # ::Selenium::WebDriver.logger.level = "debug"
10
- Capybara::Selenium::Driver.new(app, browser: :edge)
21
+ # If we don't create an options object the path set above won't be used
22
+
23
+ # browser_options = Selenium::WebDriver::Edge::Options.new
24
+ # browser_options.add_argument('--headless') if ENV['HEADLESS']
25
+
26
+ browser_options = if ENV['HEADLESS']
27
+ Selenium::WebDriver::Options.edge(args: ['--headless=new'])
28
+ else
29
+ Selenium::WebDriver::Options.edge
30
+ end
31
+
32
+ Capybara::Selenium::Driver.new(app, browser: :edge, options: browser_options).tap do |driver|
33
+ driver.browser
34
+ driver.download_path = Capybara.save_path
35
+ end
11
36
  end
12
37
 
13
38
  module TestSessions
14
39
  SeleniumEdge = Capybara::Session.new(:selenium_edge, TestApp)
15
40
  end
16
41
 
17
- skipped_tests = %i[response_headers status_code trigger modals]
42
+ skipped_tests = %i[response_headers status_code trigger]
18
43
 
19
- $stdout.puts `#{Selenium::WebDriver::Edge.driver_path} --version` if ENV['CI']
44
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Edge) if ENV['CI']
20
45
 
21
- Capybara::SpecHelper.run_specs TestSessions::SeleniumEdge, "selenium", capybara_skip: skipped_tests
46
+ Capybara::SpecHelper.run_specs TestSessions::SeleniumEdge, 'selenium', capybara_skip: skipped_tests do |example|
47
+ case example.metadata[:full_description]
48
+ when 'Capybara::Session selenium #attach_file with a block can upload by clicking the file input'
49
+ pending "Edge doesn't allow clicking on file inputs"
50
+ when /Capybara::Session selenium node #shadow_root should get visible text/
51
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
52
+ end
53
+ end
22
54
 
23
- RSpec.describe "Capybara::Session with Edge", capybara_skip: skipped_tests do
55
+ RSpec.describe 'Capybara::Session with Edge', capybara_skip: skipped_tests do
24
56
  include Capybara::SpecHelper
25
- include_examples "Capybara::Session", TestSessions::SeleniumEdge, :selenium_edge
26
- include_examples Capybara::RSpecMatchers, TestSessions::SeleniumEdge, :selenium_edge
57
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
58
+ include_examples examples, TestSessions::SeleniumEdge, :selenium_edge
59
+ end
27
60
  end
@@ -0,0 +1,228 @@
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
+ Selenium::WebDriver.logger.ignore(:selenium_manager)
10
+
11
+ browser_options = Selenium::WebDriver::Firefox::Options.new
12
+ browser_options.add_argument '-headless' if ENV['HEADLESS']
13
+ # browser_options.add_option("log", {"level": "trace"})
14
+
15
+ browser_options.profile = Selenium::WebDriver::Firefox::Profile.new.tap do |profile|
16
+ profile['browser.download.dir'] = Capybara.save_path
17
+ profile['browser.download.folderList'] = 2
18
+ profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv'
19
+ profile['browser.startup.homepage'] = 'about:blank' # workaround bug in Selenium 4 alpha4-7
20
+ profile['accessibility.tabfocus'] = 7 # make tab move over links too
21
+ end
22
+
23
+ Capybara.register_driver :selenium_firefox do |app|
24
+ # ::Selenium::WebDriver.logger.level = "debug"
25
+ version = Capybara::Selenium::Driver.load_selenium
26
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
27
+ driver_options = { browser: :firefox, timeout: 31 }.tap do |opts|
28
+ opts[options_key] = browser_options
29
+ # Get a trace level log from geckodriver
30
+ # :driver_opts => { args: ['-vv'] }
31
+ end
32
+
33
+ Capybara::Selenium::Driver.new(app, **driver_options)
34
+ end
35
+
36
+ Capybara.register_driver :selenium_firefox_not_clear_storage do |app|
37
+ version = Capybara::Selenium::Driver.load_selenium
38
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
39
+ driver_options = { browser: :firefox, clear_local_storage: false, clear_session_storage: false }.tap do |opts|
40
+ opts[options_key] = browser_options
41
+ end
42
+
43
+ Capybara::Selenium::Driver.new(app, **driver_options)
44
+ end
45
+
46
+ module TestSessions
47
+ SeleniumFirefox = Capybara::Session.new(:selenium_firefox, TestApp)
48
+ end
49
+
50
+ skipped_tests = %i[response_headers status_code trigger]
51
+
52
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Firefox) if ENV['CI']
53
+
54
+ Capybara::SpecHelper.run_specs TestSessions::SeleniumFirefox, 'selenium', capybara_skip: skipped_tests do |example|
55
+ case example.metadata[:full_description]
56
+ when 'Capybara::Session selenium node #click should allow multiple modifiers'
57
+ pending "Firefox on OSX doesn't generate an event for shift+control+click" if firefox_gte?(62, @session) && Selenium::WebDriver::Platform.mac?
58
+ when /^Capybara::Session selenium node #double_click/
59
+ pending "selenium-webdriver/geckodriver doesn't generate double click event" if firefox_lt?(59, @session)
60
+ when 'Capybara::Session selenium #accept_prompt should accept the prompt with a blank response when there is a default'
61
+ 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)
62
+ when 'Capybara::Session selenium #attach_file with multipart form should fire change once when uploading multiple files from empty'
63
+ pending "FF < 62 doesn't support setting all files at once" if firefox_lt?(62, @session)
64
+ when 'Capybara::Session selenium #accept_confirm should work with nested modals'
65
+ skip 'Broken in 63 <= FF < 69 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session) && firefox_lt?(69, @session)
66
+ 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)
67
+ skip 'Broken again intermittently in FF 71 - jus skip it' if firefox_lt?(109, @session) # don't really know when it was fixed
68
+ when 'Capybara::Session selenium #click_link can download a file'
69
+ skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
70
+ when 'Capybara::Session selenium #reset_session! removes ALL cookies'
71
+ pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
72
+ when /drag_to.*HTML5/
73
+ pending "Firefox < 62 doesn't support a DataTransfer constructor" if firefox_lt?(62.0, @session)
74
+ when 'Capybara::Session selenium #accept_alert should handle the alert if the page changes',
75
+ 'Capybara::Session selenium #accept_alert with an asynchronous alert should accept the alert'
76
+ skip 'No clue what Firefox is doing here - works fine on MacOS locally' if firefox_lt?(109, @session) # don't really know when it was fixed
77
+ when 'Capybara::Session selenium node #shadow_root should find elements inside the shadow dom using CSS',
78
+ 'Capybara::Session selenium node #shadow_root should find nested shadow roots',
79
+ 'Capybara::Session selenium node #shadow_root should click on elements',
80
+ 'Capybara::Session selenium node #shadow_root should use convenience methods once moved to a descendant of the shadow root',
81
+ 'Capybara::Session selenium node #shadow_root should produce error messages when failing',
82
+ 'Capybara::Session with firefox with selenium driver #evaluate_script returns a shadow root'
83
+ pending "Firefox doesn't yet have full W3C shadow root support" if firefox_lt?(113, @session)
84
+ when 'Capybara::Session selenium #fill_in should handle carriage returns with line feeds in a textarea correctly'
85
+ pending 'Not sure what firefox is doing here'
86
+ when /Capybara::Session selenium node #shadow_root should get visible text/
87
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
88
+ when /Capybara::Session selenium node #shadow_root/
89
+ skip 'Not supported with this geckodriver version' if geckodriver_lt?('0.31.0', @session)
90
+ when /Capybara::Session selenium node #set should submit single text input forms if ended with \\n/
91
+ pending 'Firefox/geckodriver doesn\'t submit with values ending in \n'
92
+ end
93
+ end
94
+
95
+ RSpec.describe 'Capybara::Session with firefox' do # rubocop:disable RSpec/MultipleDescribes
96
+ include Capybara::SpecHelper
97
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
98
+ include_examples examples, TestSessions::SeleniumFirefox, :selenium_firefox
99
+ end
100
+
101
+ describe 'filling in Firefox-specific date and time fields with keystrokes' do
102
+ let(:datetime) { Time.new(1983, 6, 19, 6, 30) }
103
+ let(:session) { TestSessions::SeleniumFirefox }
104
+
105
+ before do
106
+ session.visit('/form')
107
+ end
108
+
109
+ it 'should fill in a date input with a String' do
110
+ session.fill_in('form_date', with: datetime.to_date.iso8601)
111
+ session.click_button('awesome')
112
+ expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date
113
+ end
114
+
115
+ it 'should fill in a time input with a String' do
116
+ session.fill_in('form_time', with: datetime.to_time.strftime('%T'))
117
+ session.click_button('awesome')
118
+ results = extract_results(session)['time']
119
+ expect(Time.parse(results).strftime('%r')).to eq datetime.strftime('%r')
120
+ end
121
+
122
+ it 'should fill in a datetime input with a String' do
123
+ pending 'Need to figure out what string format this will actually accept'
124
+ session.fill_in('form_datetime', with: datetime.iso8601)
125
+ session.click_button('awesome')
126
+ expect(Time.parse(extract_results(session)['datetime'])).to eq datetime
127
+ end
128
+ end
129
+ end
130
+
131
+ RSpec.describe Capybara::Selenium::Driver do
132
+ let(:driver) { described_class.new(TestApp, browser: :firefox, options: browser_options) }
133
+
134
+ describe '#quit' do
135
+ it 'should reset browser when quit' do
136
+ expect(driver.browser).to be_truthy
137
+ driver.quit
138
+ # access instance variable directly so we don't create a new browser instance
139
+ expect(driver.instance_variable_get(:@browser)).to be_nil
140
+ end
141
+
142
+ context 'with errors' do
143
+ let!(:original_browser) { driver.browser }
144
+
145
+ after do
146
+ # Ensure browser is actually quit so we don't leave hanging processe
147
+ RSpec::Mocks.space.proxy_for(original_browser).reset
148
+ original_browser.quit
149
+ end
150
+
151
+ it 'warns UnknownError returned during quit because the browser is probably already gone' do
152
+ allow(driver).to receive(:warn)
153
+ allow(driver.browser).to(
154
+ receive(:quit)
155
+ .and_raise(Selenium::WebDriver::Error::UnknownError, 'random message')
156
+ )
157
+
158
+ expect { driver.quit }.not_to raise_error
159
+ expect(driver.instance_variable_get(:@browser)).to be_nil
160
+ expect(driver).to have_received(:warn).with(/random message/)
161
+ end
162
+
163
+ it 'ignores silenced UnknownError returned during quit because the browser is almost definitely already gone' do
164
+ allow(driver).to receive(:warn)
165
+ allow(driver.browser).to(
166
+ receive(:quit)
167
+ .and_raise(Selenium::WebDriver::Error::UnknownError, 'Error communicating with the remote browser')
168
+ )
169
+
170
+ expect { driver.quit }.not_to raise_error
171
+ expect(driver.instance_variable_get(:@browser)).to be_nil
172
+ expect(driver).not_to have_received(:warn)
173
+ end
174
+ end
175
+ end
176
+
177
+ context 'storage' do
178
+ describe '#reset!' do
179
+ it 'clears storage by default' do
180
+ session = TestSessions::SeleniumFirefox
181
+ session.visit('/with_js')
182
+ session.find(:css, '#set-storage').click
183
+ session.reset!
184
+ session.visit('/with_js')
185
+ expect(session.driver.browser.local_storage.keys).to be_empty
186
+ expect(session.driver.browser.session_storage.keys).to be_empty
187
+ end
188
+
189
+ it 'does not clear storage when false' do
190
+ session = Capybara::Session.new(:selenium_firefox_not_clear_storage, TestApp)
191
+ session.visit('/with_js')
192
+ session.find(:css, '#set-storage').click
193
+ session.reset!
194
+ session.visit('/with_js')
195
+ expect(session.driver.browser.local_storage.keys).not_to be_empty
196
+ expect(session.driver.browser.session_storage.keys).not_to be_empty
197
+ end
198
+ end
199
+ end
200
+
201
+ context 'timeout' do
202
+ it 'sets the http client read timeout' do
203
+ expect(TestSessions::SeleniumFirefox.driver.browser.send(:bridge).http.read_timeout).to eq 31
204
+ end
205
+ end
206
+ end
207
+
208
+ RSpec.describe Capybara::Selenium::Node do
209
+ describe '#click' do
210
+ it 'warns when attempting on a table row' do
211
+ session = TestSessions::SeleniumFirefox
212
+ session.visit('/tables')
213
+ tr = session.find(:css, '#agent_table tr:first-child')
214
+ allow(tr.base).to receive(:warn)
215
+ tr.click
216
+ expect(tr.base).to have_received(:warn).with(/Clicking the first cell in the row instead/)
217
+ end
218
+
219
+ it 'should allow multiple modifiers', requires: [:js] do
220
+ session = TestSessions::SeleniumFirefox
221
+ session.visit('with_js')
222
+ # Firefox v62+ doesn't generate an event for control+shift+click
223
+ session.find(:css, '#click-test').click(:alt, :ctrl, :meta)
224
+ # it also triggers a contextmenu event when control is held so don't check click type
225
+ expect(session).to have_link('Has been alt control meta')
226
+ end
227
+ end
228
+ end