capybara 3.3.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 (308) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +803 -13
  4. data/License.txt +1 -1
  5. data/README.md +257 -84
  6. data/lib/capybara/config.rb +25 -9
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/base.rb +17 -3
  9. data/lib/capybara/driver/node.rb +31 -6
  10. data/lib/capybara/dsl.rb +9 -7
  11. data/lib/capybara/helpers.rb +31 -7
  12. data/lib/capybara/minitest/spec.rb +180 -88
  13. data/lib/capybara/minitest.rb +262 -149
  14. data/lib/capybara/node/actions.rb +202 -116
  15. data/lib/capybara/node/base.rb +34 -19
  16. data/lib/capybara/node/document.rb +14 -2
  17. data/lib/capybara/node/document_matchers.rb +10 -12
  18. data/lib/capybara/node/element.rb +269 -115
  19. data/lib/capybara/node/finders.rb +99 -77
  20. data/lib/capybara/node/matchers.rb +327 -151
  21. data/lib/capybara/node/simple.rb +48 -13
  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 +8 -9
  25. data/lib/capybara/queries/base_query.rb +23 -16
  26. data/lib/capybara/queries/current_path_query.rb +16 -6
  27. data/lib/capybara/queries/match_query.rb +1 -0
  28. data/lib/capybara/queries/selector_query.rb +587 -130
  29. data/lib/capybara/queries/sibling_query.rb +8 -6
  30. data/lib/capybara/queries/style_query.rb +6 -2
  31. data/lib/capybara/queries/text_query.rb +28 -14
  32. data/lib/capybara/queries/title_query.rb +2 -2
  33. data/lib/capybara/rack_test/browser.rb +92 -25
  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 +68 -41
  37. data/lib/capybara/rack_test/node.rb +106 -39
  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 +75 -52
  44. data/lib/capybara/rspec/features.rb +7 -7
  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 +141 -339
  60. data/lib/capybara/rspec.rb +2 -0
  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 +27 -25
  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 +73 -25
  88. data/lib/capybara/selector/filters/base.rb +24 -5
  89. data/lib/capybara/selector/filters/expression_filter.rb +3 -3
  90. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  91. data/lib/capybara/selector/filters/node_filter.rb +16 -2
  92. data/lib/capybara/selector/regexp_disassembler.rb +211 -0
  93. data/lib/capybara/selector/selector.rb +85 -348
  94. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  95. data/lib/capybara/selector.rb +474 -447
  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 +255 -143
  101. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +93 -11
  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 +436 -134
  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 +56 -19
  123. data/lib/capybara/server/checker.rb +9 -3
  124. data/lib/capybara/server/middleware.rb +28 -12
  125. data/lib/capybara/server.rb +33 -10
  126. data/lib/capybara/session/config.rb +34 -10
  127. data/lib/capybara/session/matchers.rb +23 -16
  128. data/lib/capybara/session.rb +230 -170
  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 +121 -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 +127 -40
  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_spec.rb +21 -18
  140. data/lib/capybara/spec/session/assert_selector_spec.rb +52 -58
  141. data/lib/capybara/spec/session/assert_style_spec.rb +7 -7
  142. data/lib/capybara/spec/session/assert_text_spec.rb +74 -50
  143. data/lib/capybara/spec/session/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 +6 -6
  146. data/lib/capybara/spec/session/check_spec.rb +102 -47
  147. data/lib/capybara/spec/session/choose_spec.rb +58 -32
  148. data/lib/capybara/spec/session/click_button_spec.rb +219 -163
  149. data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -23
  150. data/lib/capybara/spec/session/click_link_spec.rb +77 -54
  151. data/lib/capybara/spec/session/current_scope_spec.rb +8 -8
  152. data/lib/capybara/spec/session/current_url_spec.rb +38 -29
  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_spec.rb +8 -8
  156. data/lib/capybara/spec/session/element/match_css_spec.rb +16 -10
  157. data/lib/capybara/spec/session/element/match_xpath_spec.rb +6 -6
  158. data/lib/capybara/spec/session/element/matches_selector_spec.rb +68 -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 +101 -46
  163. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  164. data/lib/capybara/spec/session/find_by_id_spec.rb +7 -7
  165. data/lib/capybara/spec/session/find_field_spec.rb +32 -30
  166. data/lib/capybara/spec/session/find_link_spec.rb +31 -21
  167. data/lib/capybara/spec/session/find_spec.rb +244 -141
  168. data/lib/capybara/spec/session/first_spec.rb +43 -43
  169. data/lib/capybara/spec/session/frame/frame_title_spec.rb +5 -5
  170. data/lib/capybara/spec/session/frame/frame_url_spec.rb +5 -5
  171. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +30 -18
  172. data/lib/capybara/spec/session/frame/within_frame_spec.rb +45 -18
  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 +94 -13
  179. data/lib/capybara/spec/session/has_css_spec.rb +272 -132
  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 +44 -4
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +31 -31
  185. data/lib/capybara/spec/session/has_select_spec.rb +84 -50
  186. data/lib/capybara/spec/session/has_selector_spec.rb +111 -71
  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_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 +894 -142
  196. data/lib/capybara/spec/session/node_wrapper_spec.rb +10 -7
  197. data/lib/capybara/spec/session/refresh_spec.rb +9 -7
  198. data/lib/capybara/spec/session/reset_session_spec.rb +63 -35
  199. data/lib/capybara/spec/session/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 +2 -2
  202. data/lib/capybara/spec/session/save_page_spec.rb +37 -37
  203. data/lib/capybara/spec/session/save_screenshot_spec.rb +10 -10
  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 +85 -85
  207. data/lib/capybara/spec/session/selectors_spec.rb +49 -18
  208. data/lib/capybara/spec/session/sibling_spec.rb +9 -9
  209. data/lib/capybara/spec/session/text_spec.rb +25 -24
  210. data/lib/capybara/spec/session/title_spec.rb +7 -6
  211. data/lib/capybara/spec/session/uncheck_spec.rb +33 -21
  212. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  213. data/lib/capybara/spec/session/visit_spec.rb +68 -49
  214. data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
  215. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -1
  216. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +20 -16
  217. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +6 -2
  218. data/lib/capybara/spec/session/window/window_spec.rb +62 -63
  219. data/lib/capybara/spec/session/window/windows_spec.rb +5 -1
  220. data/lib/capybara/spec/session/window/within_window_spec.rb +14 -14
  221. data/lib/capybara/spec/session/within_spec.rb +79 -42
  222. data/lib/capybara/spec/spec_helper.rb +41 -53
  223. data/lib/capybara/spec/test_app.rb +132 -43
  224. data/lib/capybara/spec/views/animated.erb +49 -0
  225. data/lib/capybara/spec/views/form.erb +139 -42
  226. data/lib/capybara/spec/views/frame_child.erb +4 -3
  227. data/lib/capybara/spec/views/frame_one.erb +2 -1
  228. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  229. data/lib/capybara/spec/views/frame_two.erb +1 -1
  230. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  231. data/lib/capybara/spec/views/layout.erb +10 -0
  232. data/lib/capybara/spec/views/obscured.erb +47 -0
  233. data/lib/capybara/spec/views/offset.erb +33 -0
  234. data/lib/capybara/spec/views/path.erb +2 -2
  235. data/lib/capybara/spec/views/popup_one.erb +1 -1
  236. data/lib/capybara/spec/views/popup_two.erb +1 -1
  237. data/lib/capybara/spec/views/react.erb +45 -0
  238. data/lib/capybara/spec/views/scroll.erb +21 -0
  239. data/lib/capybara/spec/views/spatial.erb +31 -0
  240. data/lib/capybara/spec/views/tables.erb +67 -0
  241. data/lib/capybara/spec/views/with_animation.erb +39 -4
  242. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  243. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  244. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  245. data/lib/capybara/spec/views/with_hover.erb +3 -2
  246. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  247. data/lib/capybara/spec/views/with_html.erb +37 -9
  248. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  249. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  250. data/lib/capybara/spec/views/with_js.erb +26 -5
  251. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  252. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  253. data/lib/capybara/spec/views/with_scope.erb +2 -2
  254. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  255. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  256. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  257. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  258. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  259. data/lib/capybara/spec/views/with_windows.erb +1 -1
  260. data/lib/capybara/spec/views/within_frames.erb +1 -1
  261. data/lib/capybara/version.rb +1 -1
  262. data/lib/capybara/window.rb +19 -25
  263. data/lib/capybara.rb +126 -111
  264. data/spec/basic_node_spec.rb +59 -34
  265. data/spec/capybara_spec.rb +56 -44
  266. data/spec/counter_spec.rb +35 -0
  267. data/spec/css_builder_spec.rb +101 -0
  268. data/spec/css_splitter_spec.rb +8 -8
  269. data/spec/dsl_spec.rb +79 -52
  270. data/spec/filter_set_spec.rb +9 -9
  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 +45 -7
  274. data/spec/minitest_spec_spec.rb +87 -64
  275. data/spec/per_session_config_spec.rb +6 -6
  276. data/spec/rack_test_spec.rb +172 -116
  277. data/spec/regexp_dissassembler_spec.rb +250 -0
  278. data/spec/result_spec.rb +80 -72
  279. data/spec/rspec/features_spec.rb +21 -16
  280. data/spec/rspec/scenarios_spec.rb +10 -6
  281. data/spec/rspec/shared_spec_matchers.rb +407 -365
  282. data/spec/rspec/views_spec.rb +3 -3
  283. data/spec/rspec_matchers_spec.rb +35 -10
  284. data/spec/rspec_spec.rb +63 -41
  285. data/spec/sauce_spec_chrome.rb +43 -0
  286. data/spec/selector_spec.rb +334 -89
  287. data/spec/selenium_spec_chrome.rb +176 -62
  288. data/spec/selenium_spec_chrome_remote.rb +54 -14
  289. data/spec/selenium_spec_edge.rb +41 -8
  290. data/spec/selenium_spec_firefox.rb +228 -0
  291. data/spec/selenium_spec_firefox_remote.rb +94 -0
  292. data/spec/selenium_spec_ie.rb +129 -11
  293. data/spec/selenium_spec_safari.rb +162 -0
  294. data/spec/server_spec.rb +171 -97
  295. data/spec/session_spec.rb +34 -18
  296. data/spec/shared_selenium_node.rb +79 -0
  297. data/spec/shared_selenium_session.rb +344 -80
  298. data/spec/spec_helper.rb +124 -2
  299. data/spec/whitespace_normalizer_spec.rb +54 -0
  300. data/spec/xpath_builder_spec.rb +93 -0
  301. metadata +326 -28
  302. data/lib/capybara/rspec/compound.rb +0 -94
  303. data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +0 -31
  304. data/lib/capybara/selenium/nodes/marionette_node.rb +0 -31
  305. data/lib/capybara/spec/session/has_style_spec.rb +0 -25
  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 -167
@@ -3,49 +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)
12
+
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)
13
25
 
14
26
  Capybara.register_driver :selenium_chrome do |app|
15
- driver = Capybara::Selenium::Driver.new(app, browser: :chrome)
16
- # TODO: Fix this when selenium with `download_path =` support is released
17
- bridge = driver.browser.send(:bridge)
18
- params = { cmd: 'Page.setDownloadBehavior', params: { behavior: 'allow', downloadPath: Capybara.save_path } }
19
- command = +'/session/:session_id/chromium/send_command'
20
- command[':session_id'] = bridge.session_id
21
- bridge.http.call(:post, command, params)
22
-
23
- driver
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)
24
47
  end
25
48
 
26
- Capybara.register_driver :selenium_chrome_headless do |app|
27
- browser_options = ::Selenium::WebDriver::Chrome::Options.new
28
- browser_options.args << '--headless'
29
- browser_options.args << '--disable-gpu' if Gem.win_platform?
30
- driver = Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
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
31
55
 
32
- # TODO: Fix this when selenium with `download_path =` support is released
33
- bridge = driver.browser.send(:bridge)
34
- params = { cmd: 'Page.setDownloadBehavior', params: { behavior: 'allow', downloadPath: Capybara.save_path } }
35
- command = +'/session/:session_id/chromium/send_command'
36
- command[':session_id'] = bridge.session_id
37
- bridge.http.call(:post, command, params)
56
+ Capybara::Selenium::Driver.new(app, **chrome_options)
57
+ end
38
58
 
39
- driver
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)
40
66
  end
41
67
 
42
- Capybara.register_driver :selenium_chrome_clear_storage do |app|
43
- chrome_options = {
44
- browser: :chrome,
45
- options: ::Selenium::WebDriver::Chrome::Options.new
46
- }
47
- chrome_options[:options].args << 'headless' if ENV['HEADLESS']
48
- Capybara::Selenium::Driver.new(app, chrome_options.merge(clear_local_storage: true, clear_session_storage: true))
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)
49
77
  end
50
78
 
51
79
  module TestSessions
@@ -53,43 +81,129 @@ module TestSessions
53
81
  end
54
82
 
55
83
  skipped_tests = %i[response_headers status_code trigger]
56
- # skip window tests when headless for now - closing a window not supported by chromedriver/chrome
57
- skipped_tests << :windows if ENV['TRAVIS'] && (ENV['SKIP_WINDOW'] || ENV['HEADLESS'])
58
84
 
59
- $stdout.puts `#{Selenium::WebDriver::Chrome.driver_path} --version` if ENV['CI']
85
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Chrome) if ENV['CI']
60
86
 
61
- 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
62
97
 
63
- RSpec.describe "Capybara::Session with chrome" do
98
+ RSpec.describe 'Capybara::Session with chrome' do
64
99
  include Capybara::SpecHelper
65
- include_examples "Capybara::Session", TestSessions::Chrome, CHROME_DRIVER
66
- include_examples Capybara::RSpecMatchers, TestSessions::Chrome, CHROME_DRIVER
67
-
68
- context "storage" do
69
- describe "#reset!" do
70
- it "does not clear either storage by default" do
71
- @session = TestSessions::Chrome
72
- @session.visit('/with_js')
73
- @session.find(:css, '#set-storage').click
74
- @session.reset!
75
- @session.visit('/with_js')
76
- # expect(@session.driver.browser.local_storage.keys).not_to be_empty
77
- # expect(@session.driver.browser.session_storage.keys).not_to be_empty
78
- expect(@session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
79
- 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
114
+ end
115
+
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
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
80
134
  end
81
135
 
82
- it "clears storage when set" do
83
- @session = Capybara::Session.new(:selenium_chrome_clear_storage, TestApp)
84
- @session.visit('/with_js')
85
- @session.find(:css, '#set-storage').click
86
- @session.reset!
87
- @session.visit('/with_js')
88
- # expect(@session.driver.browser.local_storage.keys).to be_empty
89
- # expect(@session.driver.browser.session_storage.keys).to be_empty
90
- expect(@session.evaluate_script('Object.keys(localStorage)')).to be_empty
91
- expect(@session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
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
92
144
  end
93
145
  end
94
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
207
+ end
208
+ end
95
209
  end
@@ -3,6 +3,7 @@
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
9
  def selenium_host
@@ -14,22 +15,35 @@ def selenium_port
14
15
  end
15
16
 
16
17
  def ensure_selenium_running!
17
- TCPSocket.open(selenium_host, selenium_port)
18
- rescue
19
- raise 'Selenium is not running. ' \
20
- "You can run a selenium server easily with: \n" \
21
- ' $ docker-compose up -d selenium'
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))
22
36
  end
23
37
 
24
38
  Capybara.register_driver :selenium_chrome_remote do |app|
25
39
  ensure_selenium_running!
26
40
 
27
41
  url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
28
- caps = Selenium::WebDriver::Remote::Capabilities.chrome
42
+ browser_options = Selenium::WebDriver::Chrome::Options.new
29
43
 
30
44
  Capybara::Selenium::Driver.new app,
31
45
  browser: :remote,
32
- desired_capabilities: caps,
46
+ options: browser_options,
33
47
  url: url
34
48
  end
35
49
 
@@ -40,17 +54,43 @@ module TestSessions
40
54
  end
41
55
 
42
56
  skipped_tests = %i[response_headers status_code trigger download]
43
- # skip window tests when headless for now - closing a window not supported by chromedriver/chrome
44
- skipped_tests << :windows if ENV['TRAVIS'] && (ENV['SKIP_WINDOW'] || ENV['HEADLESS'])
45
57
 
46
- Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests
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
47
66
 
48
- RSpec.describe "Capybara::Session with chrome" do
67
+ RSpec.describe 'Capybara::Session with remote Chrome' do
49
68
  include Capybara::SpecHelper
50
- include_examples "Capybara::Session", TestSessions::Chrome, CHROME_REMOTE_DRIVER
51
- include_examples Capybara::RSpecMatchers, TestSessions::Chrome, CHROME_REMOTE_DRIVER
69
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
70
+ include_examples examples, TestSessions::Chrome, CHROME_REMOTE_DRIVER
71
+ end
52
72
 
53
73
  it 'is considered to be chrome' do
54
- expect(session.driver.send(:chrome?)).to be_truthy
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
55
95
  end
56
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