capybara 3.0.0 → 3.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/History.md +777 -10
  4. data/License.txt +1 -1
  5. data/README.md +75 -58
  6. data/lib/capybara/config.rb +29 -10
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/base.rb +22 -4
  9. data/lib/capybara/driver/node.rb +34 -9
  10. data/lib/capybara/dsl.rb +14 -6
  11. data/lib/capybara/helpers.rb +52 -7
  12. data/lib/capybara/minitest/spec.rb +173 -84
  13. data/lib/capybara/minitest.rb +250 -144
  14. data/lib/capybara/node/actions.rb +248 -124
  15. data/lib/capybara/node/base.rb +34 -20
  16. data/lib/capybara/node/document.rb +14 -2
  17. data/lib/capybara/node/document_matchers.rb +13 -15
  18. data/lib/capybara/node/element.rb +339 -113
  19. data/lib/capybara/node/finders.rb +95 -82
  20. data/lib/capybara/node/matchers.rb +338 -157
  21. data/lib/capybara/node/simple.rb +54 -15
  22. data/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/lib/capybara/queries/ancestor_query.rb +9 -10
  24. data/lib/capybara/queries/base_query.rb +25 -18
  25. data/lib/capybara/queries/current_path_query.rb +16 -6
  26. data/lib/capybara/queries/match_query.rb +11 -0
  27. data/lib/capybara/queries/selector_query.rb +600 -103
  28. data/lib/capybara/queries/sibling_query.rb +9 -7
  29. data/lib/capybara/queries/style_query.rb +45 -0
  30. data/lib/capybara/queries/text_query.rb +40 -22
  31. data/lib/capybara/queries/title_query.rb +2 -2
  32. data/lib/capybara/rack_test/browser.rb +47 -28
  33. data/lib/capybara/rack_test/driver.rb +12 -3
  34. data/lib/capybara/rack_test/errors.rb +6 -0
  35. data/lib/capybara/rack_test/form.rb +53 -50
  36. data/lib/capybara/rack_test/node.rb +114 -37
  37. data/lib/capybara/rails.rb +1 -1
  38. data/lib/capybara/registration_container.rb +44 -0
  39. data/lib/capybara/registrations/drivers.rb +42 -0
  40. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  41. data/lib/capybara/registrations/servers.rb +45 -0
  42. data/lib/capybara/result.rb +86 -52
  43. data/lib/capybara/rspec/features.rb +8 -10
  44. data/lib/capybara/rspec/matcher_proxies.rb +39 -18
  45. data/lib/capybara/rspec/matchers/base.rb +111 -0
  46. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  47. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  48. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  49. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  50. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  51. data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
  52. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  53. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  54. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  55. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  56. data/lib/capybara/rspec/matchers/match_style.rb +43 -0
  57. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  58. data/lib/capybara/rspec/matchers.rb +138 -316
  59. data/lib/capybara/rspec.rb +3 -2
  60. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  61. data/lib/capybara/selector/builders/xpath_builder.rb +71 -0
  62. data/lib/capybara/selector/css.rb +89 -12
  63. data/lib/capybara/selector/definition/button.rb +68 -0
  64. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  65. data/lib/capybara/selector/definition/css.rb +10 -0
  66. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  67. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  68. data/lib/capybara/selector/definition/element.rb +28 -0
  69. data/lib/capybara/selector/definition/field.rb +40 -0
  70. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  71. data/lib/capybara/selector/definition/file_field.rb +13 -0
  72. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  73. data/lib/capybara/selector/definition/frame.rb +17 -0
  74. data/lib/capybara/selector/definition/id.rb +6 -0
  75. data/lib/capybara/selector/definition/label.rb +62 -0
  76. data/lib/capybara/selector/definition/link.rb +54 -0
  77. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  78. data/lib/capybara/selector/definition/option.rb +27 -0
  79. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  80. data/lib/capybara/selector/definition/select.rb +81 -0
  81. data/lib/capybara/selector/definition/table.rb +109 -0
  82. data/lib/capybara/selector/definition/table_row.rb +21 -0
  83. data/lib/capybara/selector/definition/xpath.rb +5 -0
  84. data/lib/capybara/selector/definition.rb +279 -0
  85. data/lib/capybara/selector/filter.rb +1 -0
  86. data/lib/capybara/selector/filter_set.rb +72 -27
  87. data/lib/capybara/selector/filters/base.rb +45 -2
  88. data/lib/capybara/selector/filters/expression_filter.rb +5 -6
  89. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  90. data/lib/capybara/selector/filters/node_filter.rb +18 -4
  91. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  92. data/lib/capybara/selector/selector.rb +85 -200
  93. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  94. data/lib/capybara/selector.rb +226 -537
  95. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  96. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  97. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  98. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  99. data/lib/capybara/selenium/driver.rb +296 -238
  100. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +117 -0
  101. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
  102. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
  103. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  104. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  105. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  106. data/lib/capybara/selenium/extensions/find.rb +110 -0
  107. data/lib/capybara/selenium/extensions/html5_drag.rb +228 -0
  108. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  109. data/lib/capybara/selenium/extensions/scroll.rb +76 -0
  110. data/lib/capybara/selenium/logger_suppressor.rb +40 -0
  111. data/lib/capybara/selenium/node.rb +436 -166
  112. data/lib/capybara/selenium/nodes/chrome_node.rb +137 -0
  113. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  114. data/lib/capybara/selenium/nodes/firefox_node.rb +136 -0
  115. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  116. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  117. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  118. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  119. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  120. data/lib/capybara/selenium/patches/logs.rb +45 -0
  121. data/lib/capybara/selenium/patches/pause_duration_fix.rb +9 -0
  122. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  123. data/lib/capybara/server/animation_disabler.rb +69 -0
  124. data/lib/capybara/server/checker.rb +44 -0
  125. data/lib/capybara/server/middleware.rb +71 -0
  126. data/lib/capybara/server.rb +58 -67
  127. data/lib/capybara/session/config.rb +38 -6
  128. data/lib/capybara/session/matchers.rb +26 -19
  129. data/lib/capybara/session.rb +258 -190
  130. data/lib/capybara/spec/public/jquery.js +5 -5
  131. data/lib/capybara/spec/public/offset.js +6 -0
  132. data/lib/capybara/spec/public/test.js +122 -8
  133. data/lib/capybara/spec/session/accept_alert_spec.rb +11 -11
  134. data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -3
  135. data/lib/capybara/spec/session/accept_prompt_spec.rb +9 -10
  136. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  137. data/lib/capybara/spec/session/all_spec.rb +135 -42
  138. data/lib/capybara/spec/session/ancestor_spec.rb +24 -19
  139. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +67 -38
  140. data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +20 -18
  141. data/lib/capybara/spec/session/assert_selector_spec.rb +143 -0
  142. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  143. data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +62 -38
  144. data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +12 -12
  145. data/lib/capybara/spec/session/attach_file_spec.rb +120 -72
  146. data/lib/capybara/spec/session/body_spec.rb +11 -13
  147. data/lib/capybara/spec/session/check_spec.rb +111 -51
  148. data/lib/capybara/spec/session/choose_spec.rb +62 -30
  149. data/lib/capybara/spec/session/click_button_spec.rb +227 -161
  150. data/lib/capybara/spec/session/click_link_or_button_spec.rb +49 -30
  151. data/lib/capybara/spec/session/click_link_spec.rb +78 -55
  152. data/lib/capybara/spec/session/current_scope_spec.rb +7 -7
  153. data/lib/capybara/spec/session/current_url_spec.rb +44 -37
  154. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
  155. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +2 -2
  156. data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +11 -9
  157. data/lib/capybara/spec/session/element/match_css_spec.rb +18 -10
  158. data/lib/capybara/spec/session/element/match_xpath_spec.rb +8 -6
  159. data/lib/capybara/spec/session/element/matches_selector_spec.rb +70 -56
  160. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +7 -7
  161. data/lib/capybara/spec/session/evaluate_script_spec.rb +28 -8
  162. data/lib/capybara/spec/session/execute_script_spec.rb +8 -7
  163. data/lib/capybara/spec/session/fill_in_spec.rb +104 -44
  164. data/lib/capybara/spec/session/find_button_spec.rb +23 -23
  165. data/lib/capybara/spec/session/find_by_id_spec.rb +8 -8
  166. data/lib/capybara/spec/session/find_field_spec.rb +33 -31
  167. data/lib/capybara/spec/session/find_link_spec.rb +32 -14
  168. data/lib/capybara/spec/session/find_spec.rb +236 -141
  169. data/lib/capybara/spec/session/first_spec.rb +44 -43
  170. data/lib/capybara/spec/session/frame/frame_title_spec.rb +6 -6
  171. data/lib/capybara/spec/session/frame/frame_url_spec.rb +6 -6
  172. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +32 -20
  173. data/lib/capybara/spec/session/frame/within_frame_spec.rb +44 -19
  174. data/lib/capybara/spec/session/go_back_spec.rb +1 -1
  175. data/lib/capybara/spec/session/go_forward_spec.rb +1 -1
  176. data/lib/capybara/spec/session/has_all_selectors_spec.rb +18 -18
  177. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  178. data/lib/capybara/spec/session/has_any_selectors_spec.rb +29 -0
  179. data/lib/capybara/spec/session/has_button_spec.rb +92 -12
  180. data/lib/capybara/spec/session/has_css_spec.rb +271 -137
  181. data/lib/capybara/spec/session/has_current_path_spec.rb +48 -33
  182. data/lib/capybara/spec/session/has_field_spec.rb +137 -58
  183. data/lib/capybara/spec/session/has_link_spec.rb +30 -6
  184. data/lib/capybara/spec/session/has_none_selectors_spec.rb +26 -24
  185. data/lib/capybara/spec/session/has_select_spec.rb +75 -47
  186. data/lib/capybara/spec/session/has_selector_spec.rb +102 -69
  187. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  188. data/lib/capybara/spec/session/has_table_spec.rb +170 -4
  189. data/lib/capybara/spec/session/has_text_spec.rb +108 -52
  190. data/lib/capybara/spec/session/has_title_spec.rb +19 -14
  191. data/lib/capybara/spec/session/has_xpath_spec.rb +56 -38
  192. data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +1 -1
  193. data/lib/capybara/spec/session/html_spec.rb +13 -6
  194. data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
  195. data/lib/capybara/spec/session/node_spec.rb +871 -122
  196. data/lib/capybara/spec/session/node_wrapper_spec.rb +15 -12
  197. data/lib/capybara/spec/session/refresh_spec.rb +9 -7
  198. data/lib/capybara/spec/session/reset_session_spec.rb +52 -37
  199. data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +1 -1
  200. data/lib/capybara/spec/session/save_and_open_page_spec.rb +2 -2
  201. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +5 -4
  202. data/lib/capybara/spec/session/save_page_spec.rb +41 -38
  203. data/lib/capybara/spec/session/save_screenshot_spec.rb +13 -11
  204. data/lib/capybara/spec/session/screenshot_spec.rb +2 -2
  205. data/lib/capybara/spec/session/scroll_spec.rb +117 -0
  206. data/lib/capybara/spec/session/select_spec.rb +102 -76
  207. data/lib/capybara/spec/session/selectors_spec.rb +51 -18
  208. data/lib/capybara/spec/session/sibling_spec.rb +9 -9
  209. data/lib/capybara/spec/session/text_spec.rb +26 -24
  210. data/lib/capybara/spec/session/title_spec.rb +8 -6
  211. data/lib/capybara/spec/session/uncheck_spec.rb +40 -21
  212. data/lib/capybara/spec/session/unselect_spec.rb +37 -37
  213. data/lib/capybara/spec/session/visit_spec.rb +59 -53
  214. data/lib/capybara/spec/session/window/become_closed_spec.rb +22 -19
  215. data/lib/capybara/spec/session/window/current_window_spec.rb +4 -3
  216. data/lib/capybara/spec/session/window/open_new_window_spec.rb +4 -3
  217. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +25 -21
  218. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +10 -5
  219. data/lib/capybara/spec/session/window/window_spec.rb +88 -54
  220. data/lib/capybara/spec/session/window/windows_spec.rb +10 -7
  221. data/lib/capybara/spec/session/window/within_window_spec.rb +17 -16
  222. data/lib/capybara/spec/session/within_spec.rb +69 -44
  223. data/lib/capybara/spec/spec_helper.rb +41 -53
  224. data/lib/capybara/spec/test_app.rb +79 -40
  225. data/lib/capybara/spec/views/animated.erb +49 -0
  226. data/lib/capybara/spec/views/form.erb +134 -42
  227. data/lib/capybara/spec/views/frame_child.erb +4 -3
  228. data/lib/capybara/spec/views/frame_one.erb +2 -1
  229. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  230. data/lib/capybara/spec/views/frame_two.erb +1 -1
  231. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  232. data/lib/capybara/spec/views/layout.erb +10 -0
  233. data/lib/capybara/spec/views/obscured.erb +47 -0
  234. data/lib/capybara/spec/views/offset.erb +33 -0
  235. data/lib/capybara/spec/views/path.erb +2 -2
  236. data/lib/capybara/spec/views/popup_one.erb +1 -1
  237. data/lib/capybara/spec/views/popup_two.erb +1 -1
  238. data/lib/capybara/spec/views/react.erb +45 -0
  239. data/lib/capybara/spec/views/scroll.erb +21 -0
  240. data/lib/capybara/spec/views/spatial.erb +31 -0
  241. data/lib/capybara/spec/views/tables.erb +68 -1
  242. data/lib/capybara/spec/views/with_animation.erb +81 -0
  243. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  244. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  245. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  246. data/lib/capybara/spec/views/with_hover.erb +3 -2
  247. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  248. data/lib/capybara/spec/views/with_html.erb +43 -10
  249. data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
  250. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  251. data/lib/capybara/spec/views/with_js.erb +30 -5
  252. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  253. data/lib/capybara/spec/views/with_namespace.erb +21 -0
  254. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  255. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  256. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  257. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  258. data/lib/capybara/spec/views/with_windows.erb +1 -1
  259. data/lib/capybara/spec/views/within_frames.erb +1 -1
  260. data/lib/capybara/version.rb +1 -1
  261. data/lib/capybara/window.rb +31 -25
  262. data/lib/capybara.rb +120 -100
  263. data/spec/basic_node_spec.rb +59 -34
  264. data/spec/capybara_spec.rb +54 -52
  265. data/spec/css_builder_spec.rb +101 -0
  266. data/spec/css_splitter_spec.rb +38 -0
  267. data/spec/dsl_spec.rb +80 -53
  268. data/spec/filter_set_spec.rb +24 -7
  269. data/spec/fixtures/certificate.pem +25 -0
  270. data/spec/fixtures/key.pem +27 -0
  271. data/spec/fixtures/selenium_driver_rspec_failure.rb +4 -4
  272. data/spec/fixtures/selenium_driver_rspec_success.rb +4 -4
  273. data/spec/minitest_spec.rb +38 -5
  274. data/spec/minitest_spec_spec.rb +88 -62
  275. data/spec/per_session_config_spec.rb +5 -5
  276. data/spec/rack_test_spec.rb +169 -115
  277. data/spec/regexp_dissassembler_spec.rb +250 -0
  278. data/spec/result_spec.rb +86 -33
  279. data/spec/rspec/features_spec.rb +26 -23
  280. data/spec/rspec/scenarios_spec.rb +8 -4
  281. data/spec/rspec/shared_spec_matchers.rb +393 -363
  282. data/spec/rspec/views_spec.rb +4 -3
  283. data/spec/rspec_matchers_spec.rb +10 -10
  284. data/spec/rspec_spec.rb +109 -85
  285. data/spec/sauce_spec_chrome.rb +43 -0
  286. data/spec/selector_spec.rb +391 -61
  287. data/spec/selenium_spec_chrome.rb +180 -41
  288. data/spec/selenium_spec_chrome_remote.rb +101 -0
  289. data/spec/selenium_spec_edge.rb +28 -8
  290. data/spec/selenium_spec_firefox.rb +211 -0
  291. data/spec/selenium_spec_firefox_remote.rb +80 -0
  292. data/spec/selenium_spec_ie.rb +127 -11
  293. data/spec/selenium_spec_safari.rb +156 -0
  294. data/spec/server_spec.rb +177 -78
  295. data/spec/session_spec.rb +52 -16
  296. data/spec/shared_selenium_node.rb +79 -0
  297. data/spec/shared_selenium_session.rb +455 -123
  298. data/spec/spec_helper.rb +91 -2
  299. data/spec/xpath_builder_spec.rb +93 -0
  300. metadata +343 -42
  301. data/.yard/templates_custom/default/class/html/selectors.erb +0 -38
  302. data/.yard/templates_custom/default/class/html/setup.rb +0 -17
  303. data/.yard/yard_extensions.rb +0 -78
  304. data/lib/capybara/rspec/compound.rb +0 -90
  305. data/lib/capybara/spec/session/assert_selector.rb +0 -149
  306. data/lib/capybara/spec/session/source_spec.rb +0 -0
  307. data/lib/capybara/spec/views/with_title.erb +0 -5
  308. data/spec/selenium_spec_marionette.rb +0 -143
@@ -1,229 +1,561 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
- require "selenium-webdriver"
4
+ require 'selenium-webdriver'
5
5
 
6
- RSpec.shared_examples "Capybara::Session" do |session, mode|
6
+ RSpec.shared_examples 'Capybara::Session' do |session, mode|
7
7
  let(:session) { session }
8
8
 
9
9
  context 'with selenium driver' do
10
- before do
11
- @session = session
12
- end
13
-
14
10
  describe '#driver' do
15
- it "should be a selenium driver" do
16
- expect(@session.driver).to be_an_instance_of(Capybara::Selenium::Driver)
11
+ it 'should be a selenium driver' do
12
+ expect(session.driver).to be_an_instance_of(Capybara::Selenium::Driver)
17
13
  end
18
14
  end
19
15
 
20
16
  describe '#mode' do
21
- it "should remember the mode" do
22
- expect(@session.mode).to eq(mode)
17
+ it 'should remember the mode' do
18
+ expect(session.mode).to eq(mode)
23
19
  end
24
20
  end
25
21
 
26
- describe "#reset!" do
27
- it "freshly reset session should not be touched" do
28
- @session.instance_variable_set(:@touched, true)
29
- @session.reset!
30
- expect(@session.instance_variable_get(:@touched)).to eq false
22
+ describe '#reset!' do
23
+ it 'freshly reset session should not be touched' do
24
+ session.instance_variable_set(:@touched, true)
25
+ session.reset!
26
+ expect(session.instance_variable_get(:@touched)).to eq false
31
27
  end
32
28
  end
33
29
 
34
- describe "exit codes" do
30
+ describe 'exit codes' do
31
+ let(:env) { { 'SELENIUM_BROWSER' => session.driver.options[:browser].to_s } }
32
+ let!(:orig_dir) { Dir.getwd }
33
+
35
34
  before do
36
- @current_dir = Dir.getwd
37
35
  Dir.chdir(File.join(File.dirname(__FILE__), '..'))
38
- @env = { 'SELENIUM_BROWSER' => @session.driver.options[:browser].to_s }
39
36
  end
40
37
 
41
38
  after do
42
- Dir.chdir(@current_dir)
39
+ Dir.chdir(orig_dir)
43
40
  end
44
41
 
45
- it "should have return code 1 when running selenium_driver_rspec_failure.rb" do
46
- skip if ENV['HEADLESS']
47
- system(@env, 'rspec spec/fixtures/selenium_driver_rspec_failure.rb', out: File::NULL, err: File::NULL)
42
+ it 'should have return code 1 when running selenium_driver_rspec_failure.rb' do
43
+ skip 'only setup for local non-headless' if headless_or_remote?
44
+ skip 'Not setup for edge' if edge?(session)
45
+
46
+ system(env, 'rspec spec/fixtures/selenium_driver_rspec_failure.rb', out: File::NULL, err: File::NULL)
48
47
  expect($CHILD_STATUS.exitstatus).to eq(1)
49
48
  end
50
49
 
51
- it "should have return code 0 when running selenium_driver_rspec_success.rb" do
52
- skip if ENV['HEADLESS']
53
- system(@env, 'rspec spec/fixtures/selenium_driver_rspec_success.rb', out: File::NULL, err: File::NULL)
50
+ it 'should have return code 0 when running selenium_driver_rspec_success.rb' do
51
+ skip 'only setup for local non-headless' if headless_or_remote?
52
+ skip 'Not setup for edge' if edge?(session)
53
+
54
+ system(env, 'rspec spec/fixtures/selenium_driver_rspec_success.rb', out: File::NULL, err: File::NULL)
54
55
  expect($CHILD_STATUS.exitstatus).to eq(0)
55
56
  end
56
57
  end
57
58
 
58
- describe "#accept_alert", requires: [:modals] do
59
- it "supports a blockless mode" do
60
- @session.visit('/with_js')
61
- @session.click_link('Open alert')
62
- @session.accept_alert
63
- expect { @session.driver.browser.switch_to.alert }.to raise_error(@session.driver.send(:modal_error))
59
+ describe '#accept_alert', requires: [:modals] do
60
+ it 'supports a blockless mode' do
61
+ session.visit('/with_js')
62
+ session.click_link('Open alert')
63
+ session.accept_alert
64
+ expect { session.driver.browser.switch_to.alert }.to raise_error(session.driver.send(:modal_error))
64
65
  end
65
66
 
66
- it "can be called before visiting" do
67
- @session.accept_alert "Initial alert" do
68
- @session.visit('/initial_alert')
67
+ it 'can be called before visiting' do
68
+ session.accept_alert 'Initial alert' do
69
+ session.visit('/initial_alert')
69
70
  end
70
- expect(@session).to have_text('Initial alert page')
71
+ expect(session).to have_text('Initial alert page')
71
72
  end
72
73
  end
73
74
 
74
- context '#fill_in_with empty string and no options' do
75
+ describe '#fill_in_with empty string and no options' do
75
76
  it 'should trigger change when clearing a field' do
76
- @session.visit('/with_js')
77
- @session.fill_in('with_change_event', with: '')
77
+ session.visit('/with_js')
78
+ session.fill_in('with_change_event', with: '')
78
79
  # click outside the field to trigger the change event
79
- @session.find(:css, 'body').click
80
- expect(@session).to have_selector(:css, '.change_event_triggered', match: :one)
80
+ session.find(:css, 'body').click
81
+ expect(session).to have_selector(:css, '.change_event_triggered', match: :one)
81
82
  end
82
83
  end
83
84
 
84
- context "#fill_in with { :clear => :backspace } fill_option", requires: [:js] do
85
+ describe '#fill_in with { :clear => :backspace } fill_option', requires: [:js] do
86
+ before do
87
+ # Firefox has an issue with change events if the main window doesn't think it's focused
88
+ session.execute_script('window.focus()')
89
+ end
90
+
85
91
  it 'should fill in a field, replacing an existing value' do
86
- @session.visit('/form')
87
- @session.fill_in('form_first_name',
88
- with: 'Harry',
89
- fill_options: { clear: :backspace })
90
- expect(@session.find(:fillable_field, 'form_first_name').value).to eq('Harry')
92
+ session.visit('/form')
93
+ session.fill_in('form_first_name',
94
+ with: 'Harry',
95
+ fill_options: { clear: :backspace })
96
+ expect(session.find(:fillable_field, 'form_first_name').value).to eq('Harry')
97
+ end
98
+
99
+ it 'should fill in a field, replacing an existing value, even with caret position' do
100
+ session.visit('/form')
101
+ session.find(:css, '#form_first_name').execute_script <<-JS
102
+ this.focus();
103
+ this.setSelectionRange(0, 0);
104
+ JS
105
+
106
+ session.fill_in('form_first_name',
107
+ with: 'Harry',
108
+ fill_options: { clear: :backspace })
109
+ expect(session.find(:fillable_field, 'form_first_name').value).to eq('Harry')
110
+ end
111
+
112
+ it 'should fill in if the option is set via global option' do
113
+ Capybara.default_set_options = { clear: :backspace }
114
+ session.visit('/form')
115
+ session.fill_in('form_first_name', with: 'Thomas')
116
+ expect(session.find(:fillable_field, 'form_first_name').value).to eq('Thomas')
91
117
  end
92
118
 
93
119
  it 'should only trigger onchange once' do
94
- @session.visit('/with_js')
95
- @session.fill_in('with_change_event',
96
- with: 'some value',
97
- fill_options: { clear: :backspace })
120
+ session.visit('/with_js')
121
+ sleep 2 if safari?(session) # Safari needs a delay (to load event handlers maybe ???)
122
+ session.fill_in('with_change_event',
123
+ with: 'some value',
124
+ fill_options: { clear: :backspace })
98
125
  # click outside the field to trigger the change event
99
- @session.find(:css, 'body').click
100
- expect(@session.find(:css, '.change_event_triggered', match: :one)).to have_text 'some value'
126
+ session.find(:css, '#with_focus_event').click
127
+ expect(session.find(:css, '.change_event_triggered', match: :one, wait: 5)).to have_text 'some value'
101
128
  end
102
129
 
103
130
  it 'should trigger change when clearing field' do
104
- @session.visit('/with_js')
105
- @session.fill_in('with_change_event',
106
- with: '',
107
- fill_options: { clear: :backspace })
131
+ session.visit('/with_js')
132
+ session.fill_in('with_change_event',
133
+ with: '',
134
+ fill_options: { clear: :backspace })
108
135
  # click outside the field to trigger the change event
109
- @session.find(:css, 'body').click
110
- expect(@session).to have_selector(:css, '.change_event_triggered', match: :one)
136
+ session.find(:css, '#with_focus_event').click
137
+ expect(session).to have_selector(:css, '.change_event_triggered', match: :one, wait: 5)
111
138
  end
112
139
 
113
140
  it 'should trigger input event field_value.length times' do
114
- @session.visit('/with_js')
115
- @session.fill_in('with_change_event',
116
- with: '',
117
- fill_options: { clear: :backspace })
141
+ session.visit('/with_js')
142
+ session.fill_in('with_change_event',
143
+ with: '',
144
+ fill_options: { clear: :backspace })
118
145
  # click outside the field to trigger the change event
119
- @session.find(:css, 'body').click
120
- expect(@session).to have_xpath('//p[@class="input_event_triggered"]', count: 13)
146
+ # session.find(:css, 'body').click
147
+ session.find(:css, 'h1', text: 'FooBar').click
148
+ expect(session).to have_xpath('//p[@class="input_event_triggered"]', count: 13)
121
149
  end
122
150
  end
123
151
 
124
- context "#fill_in with { clear: :none } fill_options" do
152
+ describe '#fill_in with { clear: :none } fill_options' do
125
153
  it 'should append to content in a field' do
126
- @session.visit('/form')
127
- @session.fill_in('form_first_name',
128
- with: 'Harry',
129
- fill_options: { clear: :none })
130
- expect(@session.find(:fillable_field, 'form_first_name').value).to eq('JohnHarry')
154
+ pending 'Safari overwrites by default - need to figure out a workaround' if safari?(session)
155
+
156
+ session.visit('/form')
157
+ session.fill_in('form_first_name',
158
+ with: 'Harry',
159
+ fill_options: { clear: :none })
160
+ expect(session.find(:fillable_field, 'form_first_name').value).to eq('JohnHarry')
161
+ end
162
+
163
+ it 'works with rapid fill' do
164
+ pending 'Safari overwrites by default - need to figure out a workaround' if safari?(session)
165
+
166
+ long_string = (0...60).map { |i| ((i % 26) + 65).chr }.join
167
+ session.visit('/form')
168
+ session.fill_in('form_first_name', with: long_string, fill_options: { clear: :none })
169
+ expect(session.find(:fillable_field, 'form_first_name').value).to eq("John#{long_string}")
131
170
  end
132
171
  end
133
172
 
134
- context "#fill_in with { clear: Array } fill_options" do
173
+ describe '#fill_in with Date' do
174
+ before do
175
+ session.visit('/form')
176
+ session.find(:css, '#form_date').execute_script <<-JS
177
+ window.capybara_formDateFiredEvents = [];
178
+ var fd = this;
179
+ ['focus', 'input', 'change'].forEach(function(eventType) {
180
+ fd.addEventListener(eventType, function() { window.capybara_formDateFiredEvents.push(eventType); });
181
+ });
182
+ JS
183
+ # work around weird FF issue where it would create an extra focus issue in some cases
184
+ session.find(:css, 'h1', text: 'Form').click
185
+ # session.find(:css, 'body').click
186
+ end
187
+
188
+ it 'should generate standard events on changing value' do
189
+ pending "IE 11 doesn't support date input type" if ie?(session)
190
+ session.fill_in('form_date', with: Date.today)
191
+ expect(session.evaluate_script('window.capybara_formDateFiredEvents')).to eq %w[focus input change]
192
+ end
193
+
194
+ it 'should not generate input and change events if the value is not changed' do
195
+ pending "IE 11 doesn't support date input type" if ie?(session)
196
+ session.fill_in('form_date', with: Date.today)
197
+ session.fill_in('form_date', with: Date.today)
198
+ # Chrome adds an extra focus for some reason - ok for now
199
+ expect(session.evaluate_script('window.capybara_formDateFiredEvents')).to eq(%w[focus input change])
200
+ end
201
+ end
202
+
203
+ describe '#fill_in with { clear: Array } fill_options' do
135
204
  it 'should pass the array through to the element' do
136
- pending "selenium-webdriver/geckodriver doesn't support complex sets of characters" if marionette?(@session)
137
205
  # this is mainly for use with [[:control, 'a'], :backspace] - however since that is platform dependant I'm testing with something less useful
138
- @session.visit('/form')
139
- @session.fill_in('form_first_name',
140
- with: 'Harry',
141
- fill_options: { clear: [[:shift, 'abc'], :backspace] })
142
- expect(@session.find(:fillable_field, 'form_first_name').value).to eq('JohnABHarry')
206
+ session.visit('/form')
207
+ session.fill_in('form_first_name',
208
+ with: 'Harry',
209
+ fill_options: { clear: [[:shift, 'abc'], :backspace] })
210
+ expect(session.find(:fillable_field, 'form_first_name').value).to eq('JohnABHarry')
143
211
  end
144
212
  end
145
213
 
146
- describe "#path" do
147
- it "returns xpath" do
214
+ describe '#fill_in with Emoji' do
215
+ it 'sends emojis' do
216
+ session.visit('/form')
217
+ session.fill_in('form_first_name', with: 'a😀cd😴 🛌🏽🇵🇹 e🤾🏽‍♀️f')
218
+ expect(session.find(:fillable_field, 'form_first_name').value).to eq('a😀cd😴 🛌🏽🇵🇹 e🤾🏽‍♀️f')
219
+ end
220
+ end
221
+
222
+ describe '#send_keys' do
223
+ it 'defaults to sending keys to the active_element' do
224
+ session.visit('/form')
225
+
226
+ expect(session.active_element).to match_selector(:css, 'body')
227
+
228
+ session.send_keys(:tab)
229
+
230
+ expect(session.active_element).to match_selector(:css, '[tabindex="1"]')
231
+ end
232
+ end
233
+
234
+ describe '#path' do
235
+ it 'returns xpath' do
148
236
  # this is here because it is testing for an XPath that is specific to the algorithm used in the selenium driver
149
- @session.visit('/path')
150
- element = @session.find(:link, 'Second Link')
151
- expect(element.path).to eq('/html/body/div[2]/a[1]')
237
+ session.visit('/path')
238
+ element = session.find(:link, 'Second Link')
239
+ expect(element.path).to eq('/HTML/BODY[1]/DIV[2]/A[1]')
240
+ end
241
+
242
+ it 'handles namespaces in xhtml' do
243
+ pending "IE 11 doesn't handle all XPath querys (namespace-uri, etc)" if ie?(session)
244
+ session.visit '/with_namespace'
245
+ rect = session.find(:css, 'div svg rect:first-of-type')
246
+ expect(rect.path).to eq("/HTML/BODY[1]/DIV[1]/*[local-name()='svg' and namespace-uri()='http://www.w3.org/2000/svg'][1]/*[local-name()='rect' and namespace-uri()='http://www.w3.org/2000/svg'][1]")
247
+ expect(session.find(:xpath, rect.path)).to eq rect
248
+ end
249
+
250
+ it 'handles default namespaces in html5' do
251
+ pending "IE 11 doesn't handle all XPath querys (namespace-uri, etc)" if ie?(session)
252
+ session.visit '/with_html5_svg'
253
+ rect = session.find(:css, 'div svg rect:first-of-type')
254
+ expect(rect.path).to eq("/HTML/BODY[1]/DIV[1]/*[local-name()='svg' and namespace-uri()='http://www.w3.org/2000/svg'][1]/*[local-name()='rect' and namespace-uri()='http://www.w3.org/2000/svg'][1]")
255
+ expect(session.find(:xpath, rect.path)).to eq rect
256
+ end
257
+
258
+ it 'handles case sensitive element names' do
259
+ pending "IE 11 doesn't handle all XPath querys (namespace-uri, etc)" if ie?(session)
260
+ session.visit '/with_namespace'
261
+ els = session.all(:css, 'div *', visible: :all)
262
+ expect { els.map(&:path) }.not_to raise_error
263
+ lg = session.find(:css, 'div linearGradient', visible: :all)
264
+ expect(session.find(:xpath, lg.path, visible: :all)).to eq lg
152
265
  end
153
266
  end
154
267
 
155
- describe "all with disappearing elements" do
156
- it "ignores stale elements in results" do
157
- @session.visit('/path')
158
- elements = @session.all(:link) { |_node| raise Selenium::WebDriver::Error::StaleElementReferenceError }
268
+ describe 'all with disappearing elements' do
269
+ it 'ignores stale elements in results' do
270
+ session.visit('/path')
271
+ elements = session.all(:link) { |_node| raise Selenium::WebDriver::Error::StaleElementReferenceError }
159
272
  expect(elements.size).to eq 0
160
273
  end
161
274
  end
162
275
 
163
- describe "#evaluate_script" do
164
- it "can return an element" do
165
- @session.visit('/form')
166
- element = @session.evaluate_script("document.getElementById('form_title')")
167
- expect(element).to eq @session.find(:id, 'form_title')
276
+ describe '#evaluate_script' do
277
+ it 'can return an element' do
278
+ session.visit('/form')
279
+ element = session.evaluate_script("document.getElementById('form_title')")
280
+ expect(element).to eq session.find(:id, 'form_title')
168
281
  end
169
282
 
170
- it "can return arrays of nested elements" do
171
- @session.visit('/form')
172
- elements = @session.evaluate_script('document.querySelectorAll("#form_city option")')
173
- elements.each do |el|
174
- expect(el).to be_instance_of Capybara::Node::Element
175
- end
176
- expect(elements).to eq @session.find(:css, '#form_city').all(:css, 'option').to_a
283
+ it 'can return arrays of nested elements' do
284
+ session.visit('/form')
285
+ elements = session.evaluate_script('document.querySelectorAll("#form_city option")')
286
+ expect(elements).to all(be_instance_of Capybara::Node::Element)
287
+ expect(elements).to eq session.find(:css, '#form_city').all(:css, 'option').to_a
177
288
  end
178
289
 
179
- it "can return hashes with elements" do
180
- @session.visit('/form')
181
- result = @session.evaluate_script("{ a: document.getElementById('form_title'), b: {c: document.querySelectorAll('#form_city option')}}")
290
+ it 'can return hashes with elements' do
291
+ session.visit('/form')
292
+ result = session.evaluate_script("{ a: document.getElementById('form_title'), b: {c: document.querySelectorAll('#form_city option')}}")
182
293
  expect(result).to eq(
183
- 'a' => @session.find(:id, 'form_title'),
294
+ 'a' => session.find(:id, 'form_title'),
184
295
  'b' => {
185
- 'c' => @session.find(:css, '#form_city').all(:css, 'option').to_a
296
+ 'c' => session.find(:css, '#form_city').all(:css, 'option').to_a
186
297
  }
187
298
  )
188
299
  end
189
300
 
190
- describe "#evaluate_async_script" do
191
- it "will timeout if the script takes too long" do
192
- @session.visit('/with_js')
301
+ describe '#evaluate_async_script' do
302
+ it 'will timeout if the script takes too long' do
303
+ skip 'safaridriver returns the wrong error type' if safari?(session)
304
+ session.visit('/with_js')
193
305
  expect do
194
- @session.using_wait_time(1) do
195
- @session.evaluate_async_script("var cb = arguments[0]; setTimeout(function(){ cb(null) }, 3000)")
306
+ session.using_wait_time(1) do
307
+ session.evaluate_async_script('var cb = arguments[0]; setTimeout(function(){ cb(null) }, 3000)')
196
308
  end
197
309
  end.to raise_error Selenium::WebDriver::Error::ScriptTimeoutError
198
310
  end
199
311
  end
200
312
  end
201
313
 
202
- describe "Element#inspect" do
203
- it "outputs obsolete elements" do
204
- @session.visit('/form')
205
- el = @session.find(:button, 'Click me!').click
206
- expect(@session).to have_no_button('Click me!')
207
- expect(el).not_to receive(:synchronize)
208
- expect(el.inspect).to eq "Obsolete #<Capybara::Node::Element>"
314
+ describe 'Element#inspect' do
315
+ it 'outputs obsolete elements' do
316
+ session.visit('/form')
317
+ el = session.find(:button, 'Click me!').click
318
+ expect(session).to have_no_button('Click me!')
319
+ allow(el).to receive(:synchronize)
320
+ expect(el.inspect).to eq 'Obsolete #<Capybara::Node::Element>'
321
+ expect(el).not_to have_received(:synchronize)
209
322
  end
210
323
  end
211
324
 
212
- describe "Element#click" do
213
- it "should handle fixed headers/footers" do
214
- @session.visit('/with_fixed_header_footer')
215
- # @session.click_link('Go to root')
216
- @session.find(:link, 'Go to root').click
217
- expect(@session).to have_current_path('/')
325
+ describe 'Element#click' do
326
+ it 'should handle fixed headers/footers' do
327
+ session.visit('/with_fixed_header_footer')
328
+ session.using_wait_time(2) do
329
+ session.find(:link, 'Go to root').click
330
+ end
331
+ expect(session).to have_current_path('/')
218
332
  end
219
333
  end
220
334
 
221
- context "Windows" do
335
+ describe 'Capybara#Node#attach_file' do
336
+ it 'can attach a directory' do
337
+ pending "Geckodriver doesn't support uploading a directory" if firefox?(session)
338
+ pending "Selenium remote doesn't support transferring a directory" if remote?(session)
339
+ pending "Headless Chrome doesn't support directory upload - https://bugs.chromium.org/p/chromedriver/issues/detail?id=2521&q=directory%20upload&colspec=ID%20Status%20Pri%20Owner%20Summary" if chrome?(session) && ENV['HEADLESS']
340
+ pending "IE doesn't support uploading a directory" if ie?(session)
341
+ pending 'Chrome/chromedriver 73 breaks this' if chrome?(session) && chrome_gte?(73, session) && chrome_lt?(75, session)
342
+ pending "Safari doesn't support uploading a directory" if safari?(session)
343
+ # pending "Edge/msedgedriver doesn't support directory upload" if edge?(session) && edge_gte?(75, session)
344
+
345
+ session.visit('/form')
346
+ test_file_dir = File.expand_path('./fixtures', File.dirname(__FILE__))
347
+ session.attach_file('Directory Upload', test_file_dir)
348
+ session.click_button('Upload Multiple')
349
+ expect(session.body).to include('5 | ') # number of files
350
+ end
351
+
352
+ it 'can attach a relative file' do
353
+ pending 'Geckdoriver on windows requires alternate file separator which path expansion replaces' if Gem.win_platform? && firefox?(session)
354
+
355
+ session.visit('/form')
356
+ session.attach_file('Single Document', 'spec/fixtures/capybara.csv')
357
+ session.click_button('Upload Single')
358
+ expect(session.body).to include('Content-type: text/csv')
359
+ end
360
+ end
361
+
362
+ context 'Windows' do
222
363
  it "can't close the primary window" do
223
364
  expect do
224
- @session.current_window.close
365
+ session.current_window.close
225
366
  end.to raise_error(ArgumentError, 'Not allowed to close the primary window')
226
367
  end
227
368
  end
369
+
370
+ # rubocop:disable RSpec/InstanceVariable
371
+ describe 'Capybara#disable_animation' do
372
+ context 'when set to `true`' do
373
+ before(:context) do # rubocop:disable RSpec/BeforeAfterAll
374
+ skip "Safari doesn't support multiple sessions" if safari?(session)
375
+ # NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false,
376
+ # it doesn't affect any of these tests because the settings are applied per-session
377
+ Capybara.disable_animation = true
378
+ @animation_session = Capybara::Session.new(session.mode, TestApp.new)
379
+ end
380
+
381
+ it 'should add CSS to the <head> element' do
382
+ @animation_session.visit('with_animation')
383
+
384
+ expect(@animation_session).to have_selector(:css, 'head > style', text: 'transition: none', visible: :hidden)
385
+ end
386
+
387
+ it 'should disable CSS transitions' do
388
+ @animation_session.visit('with_animation')
389
+ @animation_session.click_link('transition me away')
390
+ expect(@animation_session).to have_no_link('transition me away', wait: 0.5)
391
+ end
392
+
393
+ it 'should disable CSS animations (set to 0s)' do
394
+ @animation_session.visit('with_animation')
395
+ sleep 1
396
+ @animation_session.click_link('animate me away')
397
+ expect(@animation_session).to have_no_link('animate me away', wait: 0.5)
398
+ end
399
+
400
+ it 'should disable CSS animations on pseudo elements (set to 0s)' do
401
+ @animation_session.visit('with_animation')
402
+ sleep 1
403
+ @animation_session.find_link('animate me away').right_click
404
+ expect(@animation_session).to have_content('Animation Ended', wait: 0.1)
405
+ end
406
+
407
+ it 'should scroll the page instantly', requires: [:js] do
408
+ @animation_session.visit('with_animation')
409
+ scroll_y = @animation_session.evaluate_script(<<~JS)
410
+ (function(){
411
+ window.scrollTo(0,500);
412
+ return window.scrollY;
413
+ })()
414
+ JS
415
+ expect(scroll_y).to eq 500
416
+ end
417
+
418
+ it 'should scroll the page instantly without jquery animation', requires: [:js] do
419
+ @animation_session.visit('with_jquery_animation')
420
+ @animation_session.click_link('scroll top 500')
421
+ scroll_y = @animation_session.evaluate_script('window.scrollY')
422
+ expect(scroll_y).to eq 500
423
+ end
424
+ end
425
+
426
+ context 'when set to `false`' do
427
+ before(:context) do # rubocop:disable RSpec/BeforeAfterAll
428
+ skip "Safari doesn't support multiple sessions" if safari?(session)
429
+ # NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false,
430
+ # it doesn't affect any of these tests because the settings are applied per-session
431
+ Capybara.disable_animation = false
432
+ @animation_session = Capybara::Session.new(session.mode, TestApp.new)
433
+ end
434
+
435
+ it 'should scroll the page with a smooth animation', requires: [:js] do
436
+ @animation_session.visit('with_animation')
437
+ scroll_y = @animation_session.evaluate_script(<<~JS)
438
+ (function(){
439
+ window.scrollTo(0,500);
440
+ return window.scrollY;
441
+ })()
442
+ JS
443
+ # measured over 0.5 seconds: 0, 75, 282, 478, 500
444
+ expect(scroll_y).to be < 500
445
+ end
446
+
447
+ it 'should scroll the page with jquery animation', requires: [:js] do
448
+ @animation_session.visit('with_jquery_animation')
449
+ @animation_session.click_link('scroll top 500')
450
+ scroll_y = @animation_session.evaluate_script('window.scrollY')
451
+ expect(scroll_y).to be < 500
452
+ end
453
+ end
454
+
455
+ context 'if we pass in css that matches elements' do
456
+ before(:context) do # rubocop:disable RSpec/BeforeAfterAll
457
+ skip "safaridriver doesn't support multiple sessions" if safari?(session)
458
+ # NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false,
459
+ # it doesn't affect any of these tests because the settings are applied per-session
460
+ Capybara.disable_animation = '#with_animation a'
461
+ @animation_session_with_matching_css = Capybara::Session.new(session.mode, TestApp.new)
462
+ end
463
+
464
+ it 'should disable CSS transitions' do
465
+ @animation_session_with_matching_css.visit('with_animation')
466
+ sleep 1
467
+ @animation_session_with_matching_css.click_link('transition me away')
468
+ expect(@animation_session_with_matching_css).to have_no_link('transition me away', wait: 0.5)
469
+ end
470
+
471
+ it 'should disable CSS animations' do
472
+ @animation_session_with_matching_css.visit('with_animation')
473
+ sleep 1
474
+ @animation_session_with_matching_css.click_link('animate me away')
475
+ expect(@animation_session_with_matching_css).to have_no_link('animate me away', wait: 0.5)
476
+ end
477
+ end
478
+
479
+ context 'if we pass in css that does not match elements' do
480
+ before(:context) do # rubocop:disable RSpec/BeforeAfterAll
481
+ skip "Safari doesn't support multiple sessions" if safari?(session)
482
+ # NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false,
483
+ # it doesn't affect any of these tests because the settings are applied per-session
484
+ Capybara.disable_animation = '.this-class-matches-nothing'
485
+ @animation_session_without_matching_css = Capybara::Session.new(session.mode, TestApp.new)
486
+ end
487
+
488
+ it 'should not disable CSS transitions' do
489
+ @animation_session_without_matching_css.visit('with_animation')
490
+ sleep 1
491
+ @animation_session_without_matching_css.click_link('transition me away')
492
+ sleep 0.5 # Wait long enough for click to have been processed
493
+ expect(@animation_session_without_matching_css).to have_link('transition me away', wait: false)
494
+ expect(@animation_session_without_matching_css).to have_no_link('transition me away', wait: 5)
495
+ end
496
+
497
+ it 'should not disable CSS animations' do
498
+ @animation_session_without_matching_css.visit('with_animation')
499
+ sleep 1
500
+ @animation_session_without_matching_css.click_link('animate me away')
501
+ sleep 0.5 # Wait long enough for click to have been processed
502
+ expect(@animation_session_without_matching_css).to have_link('animate me away', wait: false)
503
+ expect(@animation_session_without_matching_css).to have_no_link('animate me away', wait: 5)
504
+ end
505
+ end
506
+ end
507
+ # rubocop:enable RSpec/InstanceVariable
508
+
509
+ describe ':element selector' do
510
+ it 'can find html5 svg elements' do
511
+ session.visit('with_html5_svg')
512
+ expect(session).to have_selector(:element, :svg)
513
+ expect(session).to have_selector(:element, :rect, visible: :visible)
514
+ expect(session).to have_selector(:element, :circle)
515
+ expect(session).to have_selector(:element, :linearGradient, visible: :all)
516
+ end
517
+
518
+ it 'can query attributes with strange characters' do
519
+ session.visit('/form')
520
+ expect(session).to have_selector(:element, '{custom}': true)
521
+ expect(session).to have_selector(:element, '{custom}': 'abcdef')
522
+ end
523
+ end
524
+
525
+ describe 'with react' do
526
+ context 'controlled components' do
527
+ it 'can set and clear a text field' do
528
+ skip "This test doesn't support older browsers" if ie?(session)
529
+
530
+ session.visit 'react'
531
+
532
+ session.fill_in('Name:', with: 'abc')
533
+ session.accept_prompt 'A name was submitted: abc' do
534
+ session.click_button('Submit')
535
+ end
536
+
537
+ session.fill_in('Name:', with: '')
538
+ session.accept_prompt(/A name was submitted: $/) do
539
+ session.click_button('Submit')
540
+ end
541
+ end
542
+
543
+ it 'works with rapid fill' do
544
+ skip "This test doesn't support older browsers" if ie?(session)
545
+
546
+ session.visit 'react'
547
+ long_string = (0...60).map { |i| ((i % 26) + 65).chr }.join
548
+
549
+ session.fill_in('Name:', with: long_string)
550
+ session.accept_prompt "A name was submitted: #{long_string}" do
551
+ session.click_button('Submit')
552
+ end
553
+ end
554
+ end
555
+ end
556
+ end
557
+
558
+ def headless_or_remote?
559
+ !ENV['HEADLESS'].nil? || session.driver.options[:browser] == :remote
228
560
  end
229
561
  end