capybara 3.8.1 → 3.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (242) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +465 -0
  4. data/License.txt +1 -1
  5. data/README.md +58 -57
  6. data/lib/capybara/config.rb +10 -4
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/base.rb +2 -2
  9. data/lib/capybara/driver/node.rb +26 -5
  10. data/lib/capybara/dsl.rb +12 -4
  11. data/lib/capybara/helpers.rb +8 -4
  12. data/lib/capybara/minitest/spec.rb +162 -85
  13. data/lib/capybara/minitest.rb +248 -148
  14. data/lib/capybara/node/actions.rb +149 -96
  15. data/lib/capybara/node/base.rb +27 -10
  16. data/lib/capybara/node/document.rb +12 -0
  17. data/lib/capybara/node/document_matchers.rb +9 -5
  18. data/lib/capybara/node/element.rb +254 -109
  19. data/lib/capybara/node/finders.rb +83 -76
  20. data/lib/capybara/node/matchers.rb +279 -141
  21. data/lib/capybara/node/simple.rb +25 -6
  22. data/lib/capybara/queries/ancestor_query.rb +5 -7
  23. data/lib/capybara/queries/base_query.rb +11 -5
  24. data/lib/capybara/queries/current_path_query.rb +3 -3
  25. data/lib/capybara/queries/match_query.rb +1 -0
  26. data/lib/capybara/queries/selector_query.rb +467 -103
  27. data/lib/capybara/queries/sibling_query.rb +5 -4
  28. data/lib/capybara/queries/style_query.rb +6 -2
  29. data/lib/capybara/queries/text_query.rb +17 -3
  30. data/lib/capybara/queries/title_query.rb +2 -2
  31. data/lib/capybara/rack_test/browser.rb +22 -15
  32. data/lib/capybara/rack_test/driver.rb +10 -1
  33. data/lib/capybara/rack_test/errors.rb +6 -0
  34. data/lib/capybara/rack_test/form.rb +33 -28
  35. data/lib/capybara/rack_test/node.rb +74 -6
  36. data/lib/capybara/registration_container.rb +44 -0
  37. data/lib/capybara/registrations/drivers.rb +36 -0
  38. data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
  39. data/lib/capybara/registrations/servers.rb +44 -0
  40. data/lib/capybara/result.rb +55 -23
  41. data/lib/capybara/rspec/features.rb +4 -4
  42. data/lib/capybara/rspec/matcher_proxies.rb +36 -15
  43. data/lib/capybara/rspec/matchers/base.rb +111 -0
  44. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  45. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  46. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  47. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  48. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  49. data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
  50. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  51. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  52. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  53. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  54. data/lib/capybara/rspec/matchers/match_style.rb +38 -0
  55. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  56. data/lib/capybara/rspec/matchers.rb +117 -311
  57. data/lib/capybara/selector/builders/css_builder.rb +84 -0
  58. data/lib/capybara/selector/builders/xpath_builder.rb +69 -0
  59. data/lib/capybara/selector/css.rb +17 -15
  60. data/lib/capybara/selector/definition/button.rb +52 -0
  61. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  62. data/lib/capybara/selector/definition/css.rb +10 -0
  63. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  64. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  65. data/lib/capybara/selector/definition/element.rb +27 -0
  66. data/lib/capybara/selector/definition/field.rb +40 -0
  67. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  68. data/lib/capybara/selector/definition/file_field.rb +13 -0
  69. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  70. data/lib/capybara/selector/definition/frame.rb +17 -0
  71. data/lib/capybara/selector/definition/id.rb +6 -0
  72. data/lib/capybara/selector/definition/label.rb +62 -0
  73. data/lib/capybara/selector/definition/link.rb +54 -0
  74. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  75. data/lib/capybara/selector/definition/option.rb +27 -0
  76. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  77. data/lib/capybara/selector/definition/select.rb +81 -0
  78. data/lib/capybara/selector/definition/table.rb +109 -0
  79. data/lib/capybara/selector/definition/table_row.rb +21 -0
  80. data/lib/capybara/selector/definition/xpath.rb +5 -0
  81. data/lib/capybara/selector/definition.rb +277 -0
  82. data/lib/capybara/selector/filter.rb +1 -0
  83. data/lib/capybara/selector/filter_set.rb +26 -19
  84. data/lib/capybara/selector/filters/base.rb +24 -5
  85. data/lib/capybara/selector/filters/expression_filter.rb +3 -3
  86. data/lib/capybara/selector/filters/locator_filter.rb +29 -0
  87. data/lib/capybara/selector/filters/node_filter.rb +16 -2
  88. data/lib/capybara/selector/regexp_disassembler.rb +214 -0
  89. data/lib/capybara/selector/selector.rb +73 -367
  90. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  91. data/lib/capybara/selector.rb +221 -480
  92. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  93. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  94. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  95. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  96. data/lib/capybara/selenium/driver.rb +203 -86
  97. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +88 -14
  98. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
  99. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
  100. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
  101. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  102. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  103. data/lib/capybara/selenium/extensions/find.rb +110 -0
  104. data/lib/capybara/selenium/extensions/html5_drag.rb +191 -22
  105. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  106. data/lib/capybara/selenium/extensions/scroll.rb +78 -0
  107. data/lib/capybara/selenium/logger_suppressor.rb +34 -0
  108. data/lib/capybara/selenium/node.rb +298 -93
  109. data/lib/capybara/selenium/nodes/chrome_node.rb +100 -8
  110. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  111. data/lib/capybara/selenium/nodes/firefox_node.rb +131 -0
  112. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  113. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  114. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  115. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  116. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  117. data/lib/capybara/selenium/patches/logs.rb +45 -0
  118. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -3
  119. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  120. data/lib/capybara/server/animation_disabler.rb +4 -3
  121. data/lib/capybara/server/checker.rb +6 -2
  122. data/lib/capybara/server/middleware.rb +23 -13
  123. data/lib/capybara/server.rb +30 -7
  124. data/lib/capybara/session/config.rb +14 -10
  125. data/lib/capybara/session/matchers.rb +11 -7
  126. data/lib/capybara/session.rb +152 -111
  127. data/lib/capybara/spec/public/offset.js +6 -0
  128. data/lib/capybara/spec/public/test.js +101 -10
  129. data/lib/capybara/spec/session/all_spec.rb +96 -6
  130. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  131. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +29 -0
  132. data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
  133. data/lib/capybara/spec/session/assert_selector_spec.rb +0 -10
  134. data/lib/capybara/spec/session/assert_style_spec.rb +4 -4
  135. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  136. data/lib/capybara/spec/session/attach_file_spec.rb +63 -36
  137. data/lib/capybara/spec/session/check_spec.rb +10 -4
  138. data/lib/capybara/spec/session/choose_spec.rb +8 -2
  139. data/lib/capybara/spec/session/click_button_spec.rb +117 -61
  140. data/lib/capybara/spec/session/click_link_or_button_spec.rb +16 -0
  141. data/lib/capybara/spec/session/click_link_spec.rb +17 -6
  142. data/lib/capybara/spec/session/element/matches_selector_spec.rb +40 -39
  143. data/lib/capybara/spec/session/evaluate_script_spec.rb +13 -0
  144. data/lib/capybara/spec/session/execute_script_spec.rb +1 -0
  145. data/lib/capybara/spec/session/fill_in_spec.rb +47 -6
  146. data/lib/capybara/spec/session/find_field_spec.rb +1 -1
  147. data/lib/capybara/spec/session/find_spec.rb +74 -4
  148. data/lib/capybara/spec/session/first_spec.rb +1 -1
  149. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +13 -1
  150. data/lib/capybara/spec/session/frame/within_frame_spec.rb +12 -1
  151. data/lib/capybara/spec/session/has_all_selectors_spec.rb +1 -1
  152. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  153. data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
  154. data/lib/capybara/spec/session/has_button_spec.rb +16 -0
  155. data/lib/capybara/spec/session/has_css_spec.rb +122 -12
  156. data/lib/capybara/spec/session/has_current_path_spec.rb +6 -4
  157. data/lib/capybara/spec/session/has_field_spec.rb +55 -0
  158. data/lib/capybara/spec/session/has_select_spec.rb +34 -6
  159. data/lib/capybara/spec/session/has_selector_spec.rb +11 -4
  160. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  161. data/lib/capybara/spec/session/has_table_spec.rb +166 -0
  162. data/lib/capybara/spec/session/has_text_spec.rb +48 -1
  163. data/lib/capybara/spec/session/has_xpath_spec.rb +17 -0
  164. data/lib/capybara/spec/session/html_spec.rb +7 -0
  165. data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
  166. data/lib/capybara/spec/session/node_spec.rb +643 -18
  167. data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
  168. data/lib/capybara/spec/session/refresh_spec.rb +4 -0
  169. data/lib/capybara/spec/session/reset_session_spec.rb +23 -8
  170. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  171. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  172. data/lib/capybara/spec/session/scroll_spec.rb +117 -0
  173. data/lib/capybara/spec/session/select_spec.rb +10 -10
  174. data/lib/capybara/spec/session/selectors_spec.rb +36 -5
  175. data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
  176. data/lib/capybara/spec/session/unselect_spec.rb +1 -1
  177. data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
  178. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +4 -0
  179. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +4 -0
  180. data/lib/capybara/spec/session/window/window_spec.rb +59 -58
  181. data/lib/capybara/spec/session/window/windows_spec.rb +4 -0
  182. data/lib/capybara/spec/session/within_spec.rb +23 -0
  183. data/lib/capybara/spec/spec_helper.rb +16 -6
  184. data/lib/capybara/spec/test_app.rb +28 -23
  185. data/lib/capybara/spec/views/animated.erb +49 -0
  186. data/lib/capybara/spec/views/form.erb +48 -7
  187. data/lib/capybara/spec/views/frame_child.erb +3 -2
  188. data/lib/capybara/spec/views/frame_one.erb +1 -0
  189. data/lib/capybara/spec/views/obscured.erb +47 -0
  190. data/lib/capybara/spec/views/offset.erb +32 -0
  191. data/lib/capybara/spec/views/react.erb +45 -0
  192. data/lib/capybara/spec/views/scroll.erb +20 -0
  193. data/lib/capybara/spec/views/spatial.erb +31 -0
  194. data/lib/capybara/spec/views/tables.erb +67 -0
  195. data/lib/capybara/spec/views/with_animation.erb +29 -1
  196. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  197. data/lib/capybara/spec/views/with_hover.erb +1 -0
  198. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  199. data/lib/capybara/spec/views/with_html.erb +32 -6
  200. data/lib/capybara/spec/views/with_js.erb +3 -1
  201. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  202. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  203. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  204. data/lib/capybara/version.rb +1 -1
  205. data/lib/capybara/window.rb +11 -11
  206. data/lib/capybara.rb +118 -111
  207. data/spec/basic_node_spec.rb +14 -3
  208. data/spec/capybara_spec.rb +29 -29
  209. data/spec/css_builder_spec.rb +101 -0
  210. data/spec/dsl_spec.rb +46 -21
  211. data/spec/filter_set_spec.rb +5 -5
  212. data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
  213. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  214. data/spec/minitest_spec.rb +18 -4
  215. data/spec/minitest_spec_spec.rb +59 -44
  216. data/spec/rack_test_spec.rb +117 -89
  217. data/spec/regexp_dissassembler_spec.rb +250 -0
  218. data/spec/result_spec.rb +51 -49
  219. data/spec/rspec/features_spec.rb +3 -0
  220. data/spec/rspec/shared_spec_matchers.rb +112 -97
  221. data/spec/rspec_spec.rb +35 -17
  222. data/spec/sauce_spec_chrome.rb +43 -0
  223. data/spec/selector_spec.rb +244 -28
  224. data/spec/selenium_spec_chrome.rb +125 -54
  225. data/spec/selenium_spec_chrome_remote.rb +26 -12
  226. data/spec/selenium_spec_edge.rb +23 -8
  227. data/spec/selenium_spec_firefox.rb +208 -0
  228. data/spec/selenium_spec_firefox_remote.rb +15 -18
  229. data/spec/selenium_spec_ie.rb +82 -13
  230. data/spec/selenium_spec_safari.rb +148 -0
  231. data/spec/server_spec.rb +118 -77
  232. data/spec/session_spec.rb +19 -3
  233. data/spec/shared_selenium_node.rb +83 -0
  234. data/spec/shared_selenium_session.rb +110 -65
  235. data/spec/spec_helper.rb +57 -9
  236. data/spec/xpath_builder_spec.rb +93 -0
  237. metadata +257 -17
  238. data/lib/capybara/rspec/compound.rb +0 -94
  239. data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +0 -49
  240. data/lib/capybara/selenium/nodes/marionette_node.rb +0 -121
  241. data/lib/capybara/spec/session/has_style_spec.rb +0 -25
  242. data/spec/selenium_spec_marionette.rb +0 -172
@@ -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
@@ -38,11 +39,12 @@ Capybara.register_driver :selenium_chrome_remote do |app|
38
39
  ensure_selenium_running!
39
40
 
40
41
  url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
41
- caps = Selenium::WebDriver::Remote::Capabilities.chrome
42
+ browser_options = ::Selenium::WebDriver::Chrome::Options.new
42
43
 
43
44
  Capybara::Selenium::Driver.new app,
44
45
  browser: :remote,
45
- desired_capabilities: caps,
46
+ desired_capabilities: :chrome,
47
+ options: browser_options,
46
48
  url: url
47
49
  end
48
50
 
@@ -52,15 +54,7 @@ module TestSessions
52
54
  Chrome = Capybara::Session.new(CHROME_REMOTE_DRIVER, TestApp)
53
55
  end
54
56
 
55
- TestSessions::Chrome.driver.browser.file_detector = lambda do |args|
56
- # args => ["/path/to/file"]
57
- str = args.first.to_s
58
- str if File.exist?(str)
59
- end
60
-
61
57
  skipped_tests = %i[response_headers status_code trigger download]
62
- # skip window tests when headless for now - closing a window not supported by chromedriver/chrome
63
- skipped_tests << :windows if ENV['TRAVIS'] && (ENV['SKIP_WINDOW'] || ENV['HEADLESS'])
64
58
 
65
59
  Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
66
60
  case example.metadata[:full_description]
@@ -68,15 +62,35 @@ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_REMOTE_DRIVER.to_s,
68
62
  'Capybara::Session selenium_chrome_remote #attach_file with multipart form should fire change once for each set of files uploaded',
69
63
  'Capybara::Session selenium_chrome_remote #attach_file with multipart form should fire change once when uploading multiple files from empty'
70
64
  pending "Selenium with Remote Chrome doesn't support multiple file upload" unless selenium_gte?(3.14)
65
+ when /node #right_click delay should delay the mouse up/
66
+ skip "Legacy selenium doesn't support separate right button down/up" if ENV['W3C'] == 'false'
71
67
  end
72
68
  end
73
69
 
74
70
  RSpec.describe 'Capybara::Session with remote Chrome' do
75
71
  include Capybara::SpecHelper
76
- include_examples 'Capybara::Session', TestSessions::Chrome, CHROME_REMOTE_DRIVER
77
- include_examples Capybara::RSpecMatchers, TestSessions::Chrome, CHROME_REMOTE_DRIVER
72
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
73
+ include_examples examples, TestSessions::Chrome, CHROME_REMOTE_DRIVER
74
+ end
78
75
 
79
76
  it 'is considered to be chrome' do
80
77
  expect(session.driver.browser.browser).to eq :chrome
81
78
  end
79
+
80
+ describe 'log access' do
81
+ before { skip 'Only makes sense in W3C mode' if ENV['W3C'] == 'false' }
82
+
83
+ it 'does not error when getting log types' do
84
+ skip if Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0]) < Gem::Version.new('75.0.3770.90')
85
+ expect do
86
+ session.driver.browser.manage.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
+ session.driver.browser.manage.logs.get(:browser)
93
+ end.not_to raise_error
94
+ end
95
+ end
82
96
  end
@@ -3,30 +3,45 @@
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
 
9
+ # unless ENV['CI']
10
+ # Selenium::WebDriver::Edge::Service.driver_path = '/usr/local/bin/msedgedriver'
11
+ # end
12
+
13
+ if ::Selenium::WebDriver::Platform.mac?
14
+ Selenium::WebDriver::EdgeChrome.path = '/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev'
15
+ end
16
+
8
17
  Capybara.register_driver :selenium_edge do |app|
9
18
  # ::Selenium::WebDriver.logger.level = "debug"
10
- Capybara::Selenium::Driver.new(app, browser: :edge)
19
+ # If we don't create an options object the path set above won't be used
20
+ browser_options = ::Selenium::WebDriver::EdgeChrome::Options.new
21
+ Capybara::Selenium::Driver.new(app, browser: :edge_chrome, options: browser_options).tap do |driver|
22
+ driver.browser
23
+ driver.download_path = Capybara.save_path
24
+ end
11
25
  end
12
26
 
13
27
  module TestSessions
14
28
  SeleniumEdge = Capybara::Session.new(:selenium_edge, TestApp)
15
29
  end
16
30
 
17
- skipped_tests = %i[response_headers status_code trigger modals]
31
+ skipped_tests = %i[response_headers status_code trigger]
18
32
 
19
- $stdout.puts `#{Selenium::WebDriver::Edge.driver_path} --version` if ENV['CI']
33
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::EdgeChrome) if ENV['CI']
20
34
 
21
35
  Capybara::SpecHelper.run_specs TestSessions::SeleniumEdge, 'selenium', capybara_skip: skipped_tests do |example|
22
- case example.metadata[:description]
23
- when /#refresh it reposts$/
24
- skip 'Edge insists on prompting without providing a way to suppress'
36
+ case example.metadata[:full_description]
37
+ when 'Capybara::Session selenium #attach_file with a block can upload by clicking the file input'
38
+ pending "EdgeChrome doesn't allow clicking on file inputs"
25
39
  end
26
40
  end
27
41
 
28
42
  RSpec.describe 'Capybara::Session with Edge', capybara_skip: skipped_tests do
29
43
  include Capybara::SpecHelper
30
- include_examples 'Capybara::Session', TestSessions::SeleniumEdge, :selenium_edge
31
- include_examples Capybara::RSpecMatchers, TestSessions::SeleniumEdge, :selenium_edge
44
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
45
+ include_examples examples, TestSessions::SeleniumEdge, :selenium_edge
46
+ end
32
47
  end
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'selenium-webdriver'
5
+ require 'shared_selenium_session'
6
+ require 'shared_selenium_node'
7
+ require 'rspec/shared_spec_matchers'
8
+
9
+ browser_options = ::Selenium::WebDriver::Firefox::Options.new
10
+ browser_options.headless! if ENV['HEADLESS']
11
+ # browser_options.add_option("log", {"level": "trace"})
12
+
13
+ browser_options.profile = Selenium::WebDriver::Firefox::Profile.new.tap do |profile|
14
+ profile['browser.download.dir'] = Capybara.save_path
15
+ profile['browser.download.folderList'] = 2
16
+ profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv'
17
+ end
18
+
19
+ Capybara.register_driver :selenium_firefox do |app|
20
+ # ::Selenium::WebDriver.logger.level = "debug"
21
+ Capybara::Selenium::Driver.new(
22
+ app,
23
+ browser: :firefox,
24
+ options: browser_options,
25
+ timeout: 31
26
+ # Get a trace level log from geckodriver
27
+ # :driver_opts => { args: ['-vv'] }
28
+ )
29
+ end
30
+
31
+ Capybara.register_driver :selenium_firefox_not_clear_storage do |app|
32
+ Capybara::Selenium::Driver.new(
33
+ app,
34
+ browser: :firefox,
35
+ clear_local_storage: false,
36
+ clear_session_storage: false,
37
+ options: browser_options
38
+ )
39
+ end
40
+
41
+ module TestSessions
42
+ SeleniumFirefox = Capybara::Session.new(:selenium_firefox, TestApp)
43
+ end
44
+
45
+ skipped_tests = %i[response_headers status_code trigger]
46
+
47
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Firefox) if ENV['CI']
48
+
49
+ Capybara::SpecHelper.run_specs TestSessions::SeleniumFirefox, 'selenium', capybara_skip: skipped_tests do |example|
50
+ case example.metadata[:full_description]
51
+ when 'Capybara::Session selenium node #click should allow multiple modifiers'
52
+ pending "Firefox on OSX doesn't generate an event for shift+control+click" if firefox_gte?(62, @session) && Selenium::WebDriver::Platform.mac?
53
+ when /^Capybara::Session selenium node #double_click/
54
+ pending "selenium-webdriver/geckodriver doesn't generate double click event" if firefox_lt?(59, @session)
55
+ when 'Capybara::Session selenium #accept_prompt should accept the prompt with a blank response when there is a default'
56
+ 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)
57
+ when 'Capybara::Session selenium #attach_file with multipart form should fire change once when uploading multiple files from empty'
58
+ pending "FF < 62 doesn't support setting all files at once" if firefox_lt?(62, @session)
59
+ when 'Capybara::Session selenium #accept_confirm should work with nested modals'
60
+ skip 'Broken in 63 <= FF < 69 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session) && firefox_lt?(69, @session)
61
+ 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)
62
+ skip 'Broken again intermittently in FF 71 - jus skip it'
63
+ when 'Capybara::Session selenium #click_link can download a file'
64
+ skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
65
+ when 'Capybara::Session selenium #reset_session! removes ALL cookies'
66
+ pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
67
+ when /drag_to.*HTML5/
68
+ pending "Firefox < 62 doesn't support a DataTransfer constuctor" if firefox_lt?(62.0, @session)
69
+ when 'Capybara::Session selenium #accept_alert should handle the alert if the page changes',
70
+ 'Capybara::Session selenium #accept_alert with an asynchronous alert should accept the alert'
71
+ skip 'No clue what Firefox is doing here - works fine on MacOS locally'
72
+ end
73
+ end
74
+
75
+ RSpec.describe 'Capybara::Session with firefox' do # rubocop:disable RSpec/MultipleDescribes
76
+ include Capybara::SpecHelper
77
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
78
+ include_examples examples, TestSessions::SeleniumFirefox, :selenium_firefox
79
+ end
80
+
81
+ describe 'filling in Firefox-specific date and time fields with keystrokes' do
82
+ let(:datetime) { Time.new(1983, 6, 19, 6, 30) }
83
+ let(:session) { TestSessions::SeleniumFirefox }
84
+
85
+ before do
86
+ session.visit('/form')
87
+ end
88
+
89
+ it 'should fill in a date input with a String' do
90
+ session.fill_in('form_date', with: datetime.to_date.iso8601)
91
+ session.click_button('awesome')
92
+ expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date
93
+ end
94
+
95
+ it 'should fill in a time input with a String' do
96
+ session.fill_in('form_time', with: datetime.to_time.strftime('%T'))
97
+ session.click_button('awesome')
98
+ results = extract_results(session)['time']
99
+ expect(Time.parse(results).strftime('%r')).to eq datetime.strftime('%r')
100
+ end
101
+
102
+ it 'should fill in a datetime input with a String' do
103
+ # FF doesn't currently support datetime-local so this is really just a text input
104
+ session.fill_in('form_datetime', with: datetime.iso8601)
105
+ session.click_button('awesome')
106
+ expect(Time.parse(extract_results(session)['datetime'])).to eq datetime
107
+ end
108
+ end
109
+ end
110
+
111
+ RSpec.describe Capybara::Selenium::Driver do
112
+ let(:driver) { described_class.new(TestApp, browser: :firefox, options: browser_options) }
113
+
114
+ describe '#quit' do
115
+ it 'should reset browser when quit' do
116
+ expect(driver.browser).to be_truthy
117
+ driver.quit
118
+ # access instance variable directly so we don't create a new browser instance
119
+ expect(driver.instance_variable_get(:@browser)).to be_nil
120
+ end
121
+
122
+ context 'with errors' do
123
+ let!(:original_browser) { driver.browser }
124
+
125
+ after do
126
+ # Ensure browser is actually quit so we don't leave hanging processe
127
+ RSpec::Mocks.space.proxy_for(original_browser).reset
128
+ original_browser.quit
129
+ end
130
+
131
+ it 'warns UnknownError returned during quit because the browser is probably already gone' do
132
+ allow(driver).to receive(:warn)
133
+ allow(driver.browser).to(
134
+ receive(:quit)
135
+ .and_raise(Selenium::WebDriver::Error::UnknownError, 'random message')
136
+ )
137
+
138
+ expect { driver.quit }.not_to raise_error
139
+ expect(driver.instance_variable_get(:@browser)).to be_nil
140
+ expect(driver).to have_received(:warn).with(/random message/)
141
+ end
142
+
143
+ it 'ignores silenced UnknownError returned during quit because the browser is almost definitely already gone' do
144
+ allow(driver).to receive(:warn)
145
+ allow(driver.browser).to(
146
+ receive(:quit)
147
+ .and_raise(Selenium::WebDriver::Error::UnknownError, 'Error communicating with the remote browser')
148
+ )
149
+
150
+ expect { driver.quit }.not_to raise_error
151
+ expect(driver.instance_variable_get(:@browser)).to be_nil
152
+ expect(driver).not_to have_received(:warn)
153
+ end
154
+ end
155
+ end
156
+
157
+ context 'storage' do
158
+ describe '#reset!' do
159
+ it 'clears storage by default' do
160
+ session = TestSessions::SeleniumFirefox
161
+ session.visit('/with_js')
162
+ session.find(:css, '#set-storage').click
163
+ session.reset!
164
+ session.visit('/with_js')
165
+ expect(session.driver.browser.local_storage.keys).to be_empty
166
+ expect(session.driver.browser.session_storage.keys).to be_empty
167
+ end
168
+
169
+ it 'does not clear storage when false' do
170
+ session = Capybara::Session.new(:selenium_firefox_not_clear_storage, TestApp)
171
+ session.visit('/with_js')
172
+ session.find(:css, '#set-storage').click
173
+ session.reset!
174
+ session.visit('/with_js')
175
+ expect(session.driver.browser.local_storage.keys).not_to be_empty
176
+ expect(session.driver.browser.session_storage.keys).not_to be_empty
177
+ end
178
+ end
179
+ end
180
+
181
+ context 'timeout' do
182
+ it 'sets the http client read timeout' do
183
+ expect(TestSessions::SeleniumFirefox.driver.browser.send(:bridge).http.read_timeout).to eq 31
184
+ end
185
+ end
186
+ end
187
+
188
+ RSpec.describe Capybara::Selenium::Node do
189
+ describe '#click' do
190
+ it 'warns when attempting on a table row' do
191
+ session = TestSessions::SeleniumFirefox
192
+ session.visit('/tables')
193
+ tr = session.find(:css, '#agent_table tr:first-child')
194
+ allow(tr.base).to receive(:warn)
195
+ tr.click
196
+ expect(tr.base).to have_received(:warn).with(/Clicking the first cell in the row instead/)
197
+ end
198
+
199
+ it 'should allow multiple modifiers', requires: [:js] do
200
+ session = TestSessions::SeleniumFirefox
201
+ session.visit('with_js')
202
+ # Firefox v62+ doesn't generate an event for control+shift+click
203
+ session.find(:css, '#click-test').click(:alt, :ctrl, :meta)
204
+ # it also triggers a contextmenu event when control is held so don't check click type
205
+ expect(session).to have_link('Has been alt control meta')
206
+ end
207
+ end
208
+ 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
@@ -34,11 +35,12 @@ Capybara.register_driver :selenium_firefox_remote do |app|
34
35
  ensure_selenium_running!
35
36
 
36
37
  url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
37
- caps = Selenium::WebDriver::Remote::Capabilities.firefox
38
+ browser_options = ::Selenium::WebDriver::Firefox::Options.new
38
39
 
39
40
  Capybara::Selenium::Driver.new app,
40
41
  browser: :remote,
41
- desired_capabilities: caps,
42
+ desired_capabilities: :firefox,
43
+ options: browser_options,
42
44
  url: url
43
45
  end
44
46
 
@@ -48,34 +50,29 @@ module TestSessions
48
50
  RemoteFirefox = Capybara::Session.new(FIREFOX_REMOTE_DRIVER, TestApp)
49
51
  end
50
52
 
51
- TestSessions::RemoteFirefox.driver.browser.file_detector = lambda do |args|
52
- # args => ["/path/to/file"]
53
- str = args.first.to_s
54
- str if File.exist?(str)
55
- end
56
-
57
53
  skipped_tests = %i[response_headers status_code trigger download]
58
- # skip window tests when headless for now - closing a window not supported by chromedriver/chrome
59
- skipped_tests << :windows if ENV['TRAVIS'] && (ENV['SKIP_WINDOW'] || ENV['HEADLESS'])
60
54
 
61
55
  Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
62
56
  case example.metadata[:full_description]
63
57
  when 'Capybara::Session selenium_firefox_remote node #click should allow multiple modifiers'
64
- skip "Firefox doesn't generate an event for shift+control+click" if marionette_gte?(62, @session)
58
+ skip "Firefox doesn't generate an event for shift+control+click" if firefox_gte?(62, @session)
65
59
  when 'Capybara::Session selenium_firefox_remote #accept_prompt should accept the prompt with a blank response when there is a default'
66
- pending "Geckodriver doesn't set a blank response in FF < 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1486485" if marionette_lt?(63, @session)
67
- when 'Capybara::Session selenium_firefox_remote #attach_file with multipart form should fire change once for each set of files uploaded'
68
- pending 'Gekcodriver appends files so we have to first call clear for multiple files which creates an extra change ' \
69
- 'if files are already set'
60
+ pending "Geckodriver doesn't set a blank response in FF < 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1486485" if firefox_lt?(63, @session)
70
61
  when 'Capybara::Session selenium_firefox_remote #attach_file with multipart form should fire change once when uploading multiple files from empty'
71
- pending "FF < 62 doesn't support setting all files at once" if marionette_lt?(62, @session)
62
+ pending "FF < 62 doesn't support setting all files at once" if firefox_lt?(62, @session)
63
+ when 'Capybara::Session selenium_firefox_remote #reset_session! removes ALL cookies'
64
+ pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
65
+ when /#accept_confirm should work with nested modals$/
66
+ # skip because this is timing based and hence flaky when set to pending
67
+ skip 'Broken in FF 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session)
72
68
  end
73
69
  end
74
70
 
75
71
  RSpec.describe 'Capybara::Session with remote firefox' do
76
72
  include Capybara::SpecHelper
77
- include_examples 'Capybara::Session', TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER
78
- include_examples Capybara::RSpecMatchers, TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER
73
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
74
+ include_examples examples, TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER
75
+ end
79
76
 
80
77
  it 'is considered to be firefox' do
81
78
  expect(session.driver.browser.browser).to eq :firefox
@@ -3,18 +3,50 @@
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
 
9
+ # if ENV['CI']
10
+ # if ::Selenium::WebDriver::Service.respond_to? :driver_path=
11
+ # ::Selenium::WebDriver::IE::Service
12
+ # else
13
+ # ::Selenium::WebDriver::IE
14
+ # end.driver_path = 'C:\Tools\WebDriver\IEDriverServer.exe'
15
+ # end
16
+
17
+ def selenium_host
18
+ ENV.fetch('SELENIUM_HOST', '192.168.56.102')
19
+ end
20
+
21
+ def selenium_port
22
+ ENV.fetch('SELENIUM_PORT', 4444)
23
+ end
24
+
25
+ def server_host
26
+ ENV.fetch('SERVER_HOST', '10.24.4.135')
27
+ end
28
+
8
29
  Capybara.register_driver :selenium_ie do |app|
9
30
  # ::Selenium::WebDriver.logger.level = "debug"
10
31
  options = ::Selenium::WebDriver::IE::Options.new
11
- options.require_window_focus = true
12
- Capybara::Selenium::Driver.new(
13
- app,
14
- browser: :ie,
15
- desired_capabilities: ::Selenium::WebDriver::Remote::Capabilities.ie,
16
- options: options
17
- )
32
+ # options.require_window_focus = true
33
+ # options.add_option("log", {"level": "trace"})
34
+
35
+ if ENV['REMOTE']
36
+ Capybara.server_host = server_host
37
+
38
+ url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
39
+ Capybara::Selenium::Driver.new(app,
40
+ browser: :remote,
41
+ options: options,
42
+ url: url)
43
+ else
44
+ Capybara::Selenium::Driver.new(
45
+ app,
46
+ browser: :ie,
47
+ options: options
48
+ )
49
+ end
18
50
  end
19
51
 
20
52
  module TestSessions
@@ -25,7 +57,7 @@ TestSessions::SeleniumIE.current_window.resize_to(800, 500)
25
57
 
26
58
  skipped_tests = %i[response_headers status_code trigger modals hover form_attribute windows]
27
59
 
28
- $stdout.puts `#{Selenium::WebDriver::IE.driver_path} --version` if ENV['CI']
60
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::IE) if ENV['CI']
29
61
 
30
62
  TestSessions::SeleniumIE.current_window.resize_to(1600, 1200)
31
63
 
@@ -41,30 +73,66 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumIE, 'selenium', capybara_sk
41
73
  skip 'IE 11 obeys non-standard disabled attribute on anchor tag'
42
74
  when /#right_click should allow modifiers$/
43
75
  skip "Windows can't :meta click because :meta triggers start menu"
76
+ when /#click should allow modifiers$/
77
+ pending "Doesn't work with IE for some unknown reason$"
78
+ when /#double_click should allow modifiers$/
79
+ pending "Doesn't work with IE for some unknown reason$"
44
80
  when /#click should allow multiple modifiers$/
45
81
  skip "Windows can't :meta click because :meta triggers start menu"
46
82
  when /#double_click should allow multiple modifiers$/
47
83
  skip "Windows can't :alt double click due to being properties shortcut"
48
- when /via clicking the wrapping label if possible$/
49
- pending 'IEDriver has an issue with the click location of elements with multiple children if the first child is a text node and the page is scrolled'
84
+ when /#has_css\? should support case insensitive :class and :id options$/
85
+ pending "IE doesn't support case insensitive CSS selectors"
86
+ when /#reset_session! removes ALL cookies$/
87
+ pending "IE driver doesn't provide a way to remove ALL cookies"
88
+ when /#click_button should send button in document order$/
89
+ pending "IE 11 doesn't support the 'form' attribute"
90
+ when /#click_button should follow permanent redirects that maintain method$/
91
+ pending "Window 7 and 8.1 don't support 308 http status code"
92
+ when /#scroll_to can scroll an element to the center of the viewport$/,
93
+ /#scroll_to can scroll an element to the center of the scrolling element$/
94
+ pending " IE doesn't support ScrollToOptions"
95
+ when /#attach_file with multipart form should fire change once for each set of files uploaded$/,
96
+ /#attach_file with multipart form should fire change once when uploading multiple files from empty$/,
97
+ /#attach_file with multipart form should not break when using HTML5 multiple file input uploading multiple files$/
98
+ pending "IE requires all files be uploaded from same directory. Selenium doesn't provide that." if ENV['REMOTE']
99
+ when %r{#attach_file with multipart form should send content type image/jpeg when uploading an image$}
100
+ pending 'IE gets text/plain type for some reason'
101
+ # when /#click should not retry clicking when wait is disabled$/
102
+ # Fixed in IEDriverServer 3.141.0.5
103
+ # pending "IE driver doesn't error when clicking on covered elements, it just clicks the wrong element"
104
+ when /#click should go to the same page if href is blank$/
105
+ pending 'IE treats blank href as a parent request (against HTML spec)'
106
+ when /#attach_file with a block/
107
+ skip 'Hangs IE testing for unknown reason'
108
+ when /drag_to.*HTML5/
109
+ pending "IE doesn't support a DataTransfer constuctor"
110
+ when /template elements should not be visible/
111
+ skip "IE doesn't support template elements"
112
+ when /Element#drop/
113
+ pending "IE doesn't support DataTransfer constructor"
50
114
  end
51
115
  end
52
116
 
53
117
  RSpec.describe 'Capybara::Session with Internet Explorer', capybara_skip: skipped_tests do # rubocop:disable RSpec/MultipleDescribes
54
118
  include Capybara::SpecHelper
55
- include_examples 'Capybara::Session', TestSessions::SeleniumIE, :selenium_ie
56
- include_examples Capybara::RSpecMatchers, TestSessions::SeleniumIE, :selenium_ie
119
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
120
+ include_examples examples, TestSessions::SeleniumIE, :selenium_ie
121
+ end
57
122
  end
58
123
 
59
124
  RSpec.describe Capybara::Selenium::Node do
60
125
  it '#right_click should allow modifiers' do
126
+ # pending "Actions API doesn't appear to work for this"
61
127
  session = TestSessions::SeleniumIE
62
128
  session.visit('/with_js')
63
- session.find(:css, '#click-test').right_click(:control)
129
+ el = session.find(:css, '#click-test')
130
+ el.right_click(:control)
64
131
  expect(session).to have_link('Has been control right clicked')
65
132
  end
66
133
 
67
134
  it '#click should allow multiple modifiers' do
135
+ # pending "Actions API doesn't appear to work for this"
68
136
  session = TestSessions::SeleniumIE
69
137
  session.visit('with_js')
70
138
  # IE triggers system behavior with :meta so can't use those here
@@ -73,6 +141,7 @@ RSpec.describe Capybara::Selenium::Node do
73
141
  end
74
142
 
75
143
  it '#double_click should allow modifiers' do
144
+ # pending "Actions API doesn't appear to work for this"
76
145
  session = TestSessions::SeleniumIE
77
146
  session.visit('/with_js')
78
147
  session.find(:css, '#click-test').double_click(:shift)