capybara 3.16.1 → 3.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +321 -0
  4. data/README.md +51 -60
  5. data/lib/capybara.rb +71 -114
  6. data/lib/capybara/config.rb +8 -5
  7. data/lib/capybara/cucumber.rb +1 -1
  8. data/lib/capybara/driver/node.rb +15 -3
  9. data/lib/capybara/dsl.rb +10 -2
  10. data/lib/capybara/helpers.rb +5 -3
  11. data/lib/capybara/minitest.rb +242 -141
  12. data/lib/capybara/minitest/spec.rb +159 -90
  13. data/lib/capybara/node/actions.rb +85 -74
  14. data/lib/capybara/node/base.rb +4 -4
  15. data/lib/capybara/node/document.rb +2 -2
  16. data/lib/capybara/node/document_matchers.rb +3 -3
  17. data/lib/capybara/node/element.rb +216 -117
  18. data/lib/capybara/node/finders.rb +65 -65
  19. data/lib/capybara/node/matchers.rb +228 -126
  20. data/lib/capybara/node/simple.rb +9 -4
  21. data/lib/capybara/queries/ancestor_query.rb +5 -7
  22. data/lib/capybara/queries/base_query.rb +2 -1
  23. data/lib/capybara/queries/current_path_query.rb +1 -1
  24. data/lib/capybara/queries/selector_query.rb +296 -30
  25. data/lib/capybara/queries/sibling_query.rb +5 -4
  26. data/lib/capybara/queries/style_query.rb +2 -2
  27. data/lib/capybara/queries/text_query.rb +13 -1
  28. data/lib/capybara/queries/title_query.rb +1 -1
  29. data/lib/capybara/rack_test/browser.rb +7 -2
  30. data/lib/capybara/rack_test/driver.rb +1 -1
  31. data/lib/capybara/rack_test/form.rb +1 -1
  32. data/lib/capybara/rack_test/node.rb +43 -7
  33. data/lib/capybara/registration_container.rb +44 -0
  34. data/lib/capybara/registrations/drivers.rb +36 -0
  35. data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
  36. data/lib/capybara/registrations/servers.rb +44 -0
  37. data/lib/capybara/result.rb +36 -8
  38. data/lib/capybara/rspec/matcher_proxies.rb +6 -4
  39. data/lib/capybara/rspec/matchers.rb +100 -63
  40. data/lib/capybara/rspec/matchers/base.rb +23 -10
  41. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  42. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  43. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  44. data/lib/capybara/rspec/matchers/have_selector.rb +16 -8
  45. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  46. data/lib/capybara/rspec/matchers/have_text.rb +4 -4
  47. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  48. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  49. data/lib/capybara/rspec/matchers/match_style.rb +2 -2
  50. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  51. data/lib/capybara/selector.rb +219 -588
  52. data/lib/capybara/selector/builders/css_builder.rb +10 -6
  53. data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
  54. data/lib/capybara/selector/css.rb +4 -2
  55. data/lib/capybara/selector/definition.rb +277 -0
  56. data/lib/capybara/selector/definition/button.rb +52 -0
  57. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  58. data/lib/capybara/selector/definition/css.rb +10 -0
  59. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  60. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  61. data/lib/capybara/selector/definition/element.rb +27 -0
  62. data/lib/capybara/selector/definition/field.rb +40 -0
  63. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  64. data/lib/capybara/selector/definition/file_field.rb +13 -0
  65. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  66. data/lib/capybara/selector/definition/frame.rb +17 -0
  67. data/lib/capybara/selector/definition/id.rb +6 -0
  68. data/lib/capybara/selector/definition/label.rb +62 -0
  69. data/lib/capybara/selector/definition/link.rb +54 -0
  70. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  71. data/lib/capybara/selector/definition/option.rb +27 -0
  72. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  73. data/lib/capybara/selector/definition/select.rb +81 -0
  74. data/lib/capybara/selector/definition/table.rb +109 -0
  75. data/lib/capybara/selector/definition/table_row.rb +21 -0
  76. data/lib/capybara/selector/definition/xpath.rb +5 -0
  77. data/lib/capybara/selector/filter_set.rb +13 -9
  78. data/lib/capybara/selector/filters/base.rb +11 -2
  79. data/lib/capybara/selector/filters/locator_filter.rb +13 -3
  80. data/lib/capybara/selector/regexp_disassembler.rb +9 -2
  81. data/lib/capybara/selector/selector.rb +43 -448
  82. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  83. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  84. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  85. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  86. data/lib/capybara/selenium/driver.rb +125 -56
  87. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +73 -17
  88. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
  89. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +41 -2
  90. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +14 -1
  91. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +14 -5
  92. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  93. data/lib/capybara/selenium/extensions/find.rb +67 -45
  94. data/lib/capybara/selenium/extensions/html5_drag.rb +152 -36
  95. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  96. data/lib/capybara/selenium/logger_suppressor.rb +34 -0
  97. data/lib/capybara/selenium/node.rb +227 -56
  98. data/lib/capybara/selenium/nodes/chrome_node.rb +93 -8
  99. data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
  100. data/lib/capybara/selenium/nodes/firefox_node.rb +37 -59
  101. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  102. data/lib/capybara/selenium/nodes/safari_node.rb +27 -54
  103. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  104. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  105. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  106. data/lib/capybara/selenium/patches/logs.rb +45 -0
  107. data/lib/capybara/server.rb +19 -3
  108. data/lib/capybara/server/animation_disabler.rb +2 -2
  109. data/lib/capybara/server/checker.rb +6 -2
  110. data/lib/capybara/server/middleware.rb +23 -13
  111. data/lib/capybara/session.rb +124 -106
  112. data/lib/capybara/session/config.rb +12 -10
  113. data/lib/capybara/session/matchers.rb +6 -6
  114. data/lib/capybara/spec/public/offset.js +6 -0
  115. data/lib/capybara/spec/public/test.js +94 -5
  116. data/lib/capybara/spec/session/all_spec.rb +84 -6
  117. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  118. data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
  119. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  120. data/lib/capybara/spec/session/attach_file_spec.rb +14 -6
  121. data/lib/capybara/spec/session/check_spec.rb +10 -4
  122. data/lib/capybara/spec/session/choose_spec.rb +8 -2
  123. data/lib/capybara/spec/session/click_button_spec.rb +44 -1
  124. data/lib/capybara/spec/session/click_link_spec.rb +11 -0
  125. data/lib/capybara/spec/session/evaluate_script_spec.rb +12 -0
  126. data/lib/capybara/spec/session/fill_in_spec.rb +37 -2
  127. data/lib/capybara/spec/session/find_spec.rb +60 -6
  128. data/lib/capybara/spec/session/first_spec.rb +1 -1
  129. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
  130. data/lib/capybara/spec/session/frame/within_frame_spec.rb +12 -1
  131. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  132. data/lib/capybara/spec/session/has_button_spec.rb +16 -0
  133. data/lib/capybara/spec/session/has_css_spec.rb +35 -6
  134. data/lib/capybara/spec/session/has_current_path_spec.rb +6 -4
  135. data/lib/capybara/spec/session/has_field_spec.rb +34 -0
  136. data/lib/capybara/spec/session/has_select_spec.rb +32 -4
  137. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  138. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  139. data/lib/capybara/spec/session/has_table_spec.rb +51 -5
  140. data/lib/capybara/spec/session/has_text_spec.rb +47 -0
  141. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  142. data/lib/capybara/spec/session/node_spec.rb +574 -16
  143. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  144. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  145. data/lib/capybara/spec/session/scroll_spec.rb +1 -1
  146. data/lib/capybara/spec/session/select_spec.rb +5 -10
  147. data/lib/capybara/spec/session/selectors_spec.rb +24 -3
  148. data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
  149. data/lib/capybara/spec/session/unselect_spec.rb +1 -1
  150. data/lib/capybara/spec/session/window/window_spec.rb +10 -9
  151. data/lib/capybara/spec/spec_helper.rb +7 -2
  152. data/lib/capybara/spec/test_app.rb +26 -21
  153. data/lib/capybara/spec/views/animated.erb +49 -0
  154. data/lib/capybara/spec/views/form.erb +25 -4
  155. data/lib/capybara/spec/views/frame_child.erb +2 -1
  156. data/lib/capybara/spec/views/frame_one.erb +1 -0
  157. data/lib/capybara/spec/views/obscured.erb +9 -9
  158. data/lib/capybara/spec/views/offset.erb +32 -0
  159. data/lib/capybara/spec/views/react.erb +45 -0
  160. data/lib/capybara/spec/views/spatial.erb +31 -0
  161. data/lib/capybara/spec/views/with_animation.erb +29 -1
  162. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  163. data/lib/capybara/spec/views/with_html.erb +28 -2
  164. data/lib/capybara/spec/views/with_js.erb +2 -1
  165. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  166. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  167. data/lib/capybara/version.rb +1 -1
  168. data/lib/capybara/window.rb +10 -10
  169. data/spec/basic_node_spec.rb +6 -6
  170. data/spec/capybara_spec.rb +28 -28
  171. data/spec/dsl_spec.rb +16 -3
  172. data/spec/filter_set_spec.rb +5 -5
  173. data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
  174. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  175. data/spec/minitest_spec.rb +12 -2
  176. data/spec/minitest_spec_spec.rb +56 -45
  177. data/spec/rack_test_spec.rb +25 -12
  178. data/spec/regexp_dissassembler_spec.rb +53 -39
  179. data/spec/result_spec.rb +50 -54
  180. data/spec/rspec/features_spec.rb +1 -0
  181. data/spec/rspec/shared_spec_matchers.rb +78 -62
  182. data/spec/rspec_spec.rb +5 -5
  183. data/spec/sauce_spec_chrome.rb +1 -0
  184. data/spec/selector_spec.rb +26 -16
  185. data/spec/selenium_spec_chrome.rb +84 -5
  186. data/spec/selenium_spec_chrome_remote.rb +23 -8
  187. data/spec/selenium_spec_edge.rb +23 -8
  188. data/spec/selenium_spec_firefox.rb +16 -21
  189. data/spec/selenium_spec_firefox_remote.rb +4 -13
  190. data/spec/selenium_spec_ie.rb +23 -15
  191. data/spec/selenium_spec_safari.rb +17 -17
  192. data/spec/server_spec.rb +87 -42
  193. data/spec/session_spec.rb +11 -4
  194. data/spec/shared_selenium_node.rb +83 -0
  195. data/spec/shared_selenium_session.rb +62 -72
  196. data/spec/spec_helper.rb +43 -5
  197. metadata +114 -16
@@ -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
  browser_options = ::Selenium::WebDriver::Firefox::Options.new
@@ -43,36 +44,39 @@ end
43
44
 
44
45
  skipped_tests = %i[response_headers status_code trigger]
45
46
 
46
- $stdout.puts `#{Selenium::WebDriver::Firefox.driver_path} --version` if ENV['CI']
47
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Firefox) if ENV['CI']
47
48
 
48
49
  Capybara::SpecHelper.run_specs TestSessions::SeleniumFirefox, 'selenium', capybara_skip: skipped_tests do |example|
49
50
  case example.metadata[:full_description]
50
51
  when 'Capybara::Session selenium node #click should allow multiple modifiers'
51
- pending "Firefox doesn't generate an event for shift+control+click" if firefox_gte?(62, @session) && !Gem.win_platform?
52
+ pending "Firefox on OSX doesn't generate an event for shift+control+click" if firefox_gte?(62, @session) && Selenium::WebDriver::Platform.mac?
52
53
  when /^Capybara::Session selenium node #double_click/
53
54
  pending "selenium-webdriver/geckodriver doesn't generate double click event" if firefox_lt?(59, @session)
54
55
  when 'Capybara::Session selenium #accept_prompt should accept the prompt with a blank response when there is a default'
55
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)
56
- when 'Capybara::Session selenium #attach_file with multipart form should fire change once for each set of files uploaded'
57
- pending 'Gekcodriver appends files so we have to first call clear for multiple files which creates an extra change ' \
58
- 'if files are already set'
59
57
  when 'Capybara::Session selenium #attach_file with multipart form should fire change once when uploading multiple files from empty'
60
58
  pending "FF < 62 doesn't support setting all files at once" if firefox_lt?(62, @session)
61
59
  when 'Capybara::Session selenium #accept_confirm should work with nested modals'
62
- skip 'Broken in FF 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session)
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
63
  when 'Capybara::Session selenium #click_link can download a file'
64
64
  skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
65
65
  when 'Capybara::Session selenium #reset_session! removes ALL cookies'
66
66
  pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
67
- when 'Capybara::Session selenium #attach_file with a block can upload by clicking the file input'
68
- pending "Geckodriver doesn't allow clicking on file inputs"
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'
69
72
  end
70
73
  end
71
74
 
72
75
  RSpec.describe 'Capybara::Session with firefox' do # rubocop:disable RSpec/MultipleDescribes
73
76
  include Capybara::SpecHelper
74
- include_examples 'Capybara::Session', TestSessions::SeleniumFirefox, :selenium_firefox
75
- include_examples Capybara::RSpecMatchers, TestSessions::SeleniumFirefox, :selenium_firefox
77
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
78
+ include_examples examples, TestSessions::SeleniumFirefox, :selenium_firefox
79
+ end
76
80
 
77
81
  describe 'filling in Firefox-specific date and time fields with keystrokes' do
78
82
  let(:datetime) { Time.new(1983, 6, 19, 6, 30) }
@@ -105,7 +109,7 @@ RSpec.describe 'Capybara::Session with firefox' do # rubocop:disable RSpec/Multi
105
109
  end
106
110
 
107
111
  RSpec.describe Capybara::Selenium::Driver do
108
- let(:driver) { Capybara::Selenium::Driver.new(TestApp, browser: :firefox, options: browser_options) }
112
+ let(:driver) { described_class.new(TestApp, browser: :firefox, options: browser_options) }
109
113
 
110
114
  describe '#quit' do
111
115
  it 'should reset browser when quit' do
@@ -182,7 +186,7 @@ RSpec.describe Capybara::Selenium::Driver do
182
186
  end
183
187
 
184
188
  RSpec.describe Capybara::Selenium::Node do
185
- context '#click' do
189
+ describe '#click' do
186
190
  it 'warns when attempting on a table row' do
187
191
  session = TestSessions::SeleniumFirefox
188
192
  session.visit('/tables')
@@ -201,13 +205,4 @@ RSpec.describe Capybara::Selenium::Node do
201
205
  expect(session).to have_link('Has been alt control meta')
202
206
  end
203
207
  end
204
-
205
- context '#send_keys' do
206
- it 'should process space' do
207
- session = TestSessions::SeleniumFirefox
208
- session.visit('/form')
209
- session.find(:css, '#address1_city').send_keys('ocean', [:shift, :space, 'side'])
210
- expect(session.find(:css, '#address1_city').value).to eq 'ocean SIDE'
211
- end
212
- end
213
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
@@ -49,12 +50,6 @@ module TestSessions
49
50
  RemoteFirefox = Capybara::Session.new(FIREFOX_REMOTE_DRIVER, TestApp)
50
51
  end
51
52
 
52
- TestSessions::RemoteFirefox.driver.browser.file_detector = lambda do |args|
53
- # args => ["/path/to/file"]
54
- str = args.first.to_s
55
- str if File.exist?(str)
56
- end
57
-
58
53
  skipped_tests = %i[response_headers status_code trigger download]
59
54
 
60
55
  Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
@@ -63,9 +58,6 @@ Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVE
63
58
  skip "Firefox doesn't generate an event for shift+control+click" if firefox_gte?(62, @session)
64
59
  when 'Capybara::Session selenium_firefox_remote #accept_prompt should accept the prompt with a blank response when there is a default'
65
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)
66
- when 'Capybara::Session selenium_firefox_remote #attach_file with multipart form should fire change once for each set of files uploaded'
67
- pending 'Gekcodriver appends files so we have to first call clear for multiple files which creates an extra change ' \
68
- 'if files are already set'
69
61
  when 'Capybara::Session selenium_firefox_remote #attach_file with multipart form should fire change once when uploading multiple files from empty'
70
62
  pending "FF < 62 doesn't support setting all files at once" if firefox_lt?(62, @session)
71
63
  when 'Capybara::Session selenium_firefox_remote #reset_session! removes ALL cookies'
@@ -73,15 +65,14 @@ Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVE
73
65
  when /#accept_confirm should work with nested modals$/
74
66
  # skip because this is timing based and hence flaky when set to pending
75
67
  skip 'Broken in FF 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session)
76
- when 'Capybara::Session selenium_firefox_remote #attach_file with a block can upload by clicking the file input'
77
- pending "Geckodriver doesn't allow clicking on file inputs"
78
68
  end
79
69
  end
80
70
 
81
71
  RSpec.describe 'Capybara::Session with remote firefox' do
82
72
  include Capybara::SpecHelper
83
- include_examples 'Capybara::Session', TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER
84
- 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
85
76
 
86
77
  it 'is considered to be firefox' do
87
78
  expect(session.driver.browser.browser).to eq :firefox
@@ -3,9 +3,16 @@
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
- ::Selenium::WebDriver::IE.driver_path = 'C:\Tools\WebDriver\IEDriverServer.exe' if ENV['CI']
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
9
16
 
10
17
  def selenium_host
11
18
  ENV.fetch('SELENIUM_HOST', '192.168.56.102')
@@ -22,7 +29,7 @@ end
22
29
  Capybara.register_driver :selenium_ie do |app|
23
30
  # ::Selenium::WebDriver.logger.level = "debug"
24
31
  options = ::Selenium::WebDriver::IE::Options.new
25
- options.require_window_focus = true
32
+ # options.require_window_focus = true
26
33
  # options.add_option("log", {"level": "trace"})
27
34
 
28
35
  if ENV['REMOTE']
@@ -32,21 +39,13 @@ Capybara.register_driver :selenium_ie do |app|
32
39
  Capybara::Selenium::Driver.new(app,
33
40
  browser: :remote,
34
41
  options: options,
35
- url: url).tap do |driver|
36
- puts driver.browser.capabilities.inspect
37
- driver.browser.file_detector = lambda do |args|
38
- str = args.first.to_s
39
- str if File.exist?(str)
40
- end
41
- end
42
+ url: url)
42
43
  else
43
44
  Capybara::Selenium::Driver.new(
44
45
  app,
45
46
  browser: :ie,
46
47
  options: options
47
- ).tap do |driver|
48
- puts driver.browser.capabilities.inspect
49
- end
48
+ )
50
49
  end
51
50
  end
52
51
 
@@ -58,7 +57,7 @@ TestSessions::SeleniumIE.current_window.resize_to(800, 500)
58
57
 
59
58
  skipped_tests = %i[response_headers status_code trigger modals hover form_attribute windows]
60
59
 
61
- $stdout.puts `#{Selenium::WebDriver::IE.driver_path} --version` if ENV['CI']
60
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::IE) if ENV['CI']
62
61
 
63
62
  TestSessions::SeleniumIE.current_window.resize_to(1600, 1200)
64
63
 
@@ -104,13 +103,22 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumIE, 'selenium', capybara_sk
104
103
  # pending "IE driver doesn't error when clicking on covered elements, it just clicks the wrong element"
105
104
  when /#click should go to the same page if href is blank$/
106
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"
107
114
  end
108
115
  end
109
116
 
110
117
  RSpec.describe 'Capybara::Session with Internet Explorer', capybara_skip: skipped_tests do # rubocop:disable RSpec/MultipleDescribes
111
118
  include Capybara::SpecHelper
112
- include_examples 'Capybara::Session', TestSessions::SeleniumIE, :selenium_ie
113
- 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
114
122
  end
115
123
 
116
124
  RSpec.describe Capybara::Selenium::Node do
@@ -3,11 +3,16 @@
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
  SAFARI_DRIVER = :selenium_safari
9
10
 
10
- ::Selenium::WebDriver::Safari.driver_path = '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver'
11
+ if ::Selenium::WebDriver::Service.respond_to? :driver_path=
12
+ ::Selenium::WebDriver::Safari::Service
13
+ else
14
+ ::Selenium::WebDriver::Safari
15
+ end.driver_path = '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver'
11
16
 
12
17
  browser_options = ::Selenium::WebDriver::Safari::Options.new
13
18
  # browser_options.headless! if ENV['HEADLESS']
@@ -33,7 +38,7 @@ end
33
38
 
34
39
  skipped_tests = %i[response_headers status_code trigger windows drag]
35
40
 
36
- $stdout.puts `#{Selenium::WebDriver::Safari.driver_path} --version` if ENV['CI']
41
+ Capybara::SpecHelper.log_selenium_driver_version(Selenium::WebDriver::Safari) if ENV['CI']
37
42
 
38
43
  Capybara::SpecHelper.run_specs TestSessions::Safari, SAFARI_DRIVER.to_s, capybara_skip: skipped_tests do |example|
39
44
  case example.metadata[:full_description]
@@ -50,17 +55,9 @@ Capybara::SpecHelper.run_specs TestSessions::Safari, SAFARI_DRIVER.to_s, capybar
50
55
  pending 'safaridriver thinks these links are non-interactable for some unknown reason'
51
56
  when /Capybara::Session selenium_safari #attach_file with a block can upload by clicking the file input/
52
57
  skip "safaridriver doesn't allow clicking on file inputs"
53
- when /Capybara::Session selenium_safari #attach_file with a block can upload by clicking the label/
54
- skip 'hangs tests'
55
- when /Capybara::Session selenium_safari #check when checkbox hidden with Capybara.automatic_label_click == false with allow_label_click == true should check via the label if input is visible but blocked by another element/,
56
- 'Capybara::Session selenium_safari node #click should not retry clicking when wait is disabled',
57
- 'Capybara::Session selenium_safari node #click should allow to retry longer',
58
- 'Capybara::Session selenium_safari node #click should retry clicking'
59
- pending "safaridriver doesn't return a specific enough error to deal with this"
60
- when /Capybara::Session selenium_safari #within_frame should find multiple nested frames/,
61
- /Capybara::Session selenium_safari #within_frame works if the frame is closed/,
58
+ when /Capybara::Session selenium_safari #within_frame works if the frame is closed/,
62
59
  /Capybara::Session selenium_safari #switch_to_frame works if the frame is closed/
63
- skip 'switch_to_frame(:parent) appears to go to the root in Safari rather than parent'
60
+ skip 'Safari has a race condition when clicking an element that causes the frame to close. It will sometimes raise a NoSuchFrameError'
64
61
  when /Capybara::Session selenium_safari #reset_session! removes ALL cookies/
65
62
  skip 'Safari webdriver can only remove cookies for the current domain'
66
63
  when /Capybara::Session selenium_safari #refresh it reposts/
@@ -76,15 +73,16 @@ Capybara::SpecHelper.run_specs TestSessions::Safari, SAFARI_DRIVER.to_s, capybar
76
73
  when 'Capybara::Session selenium_safari #go_back should fetch a response from the driver from the previous page',
77
74
  'Capybara::Session selenium_safari #go_forward should fetch a response from the driver from the previous page'
78
75
  skip 'safaridriver loses the ability to find elements in the document after `go_back`'
79
- when 'Capybara::Session selenium_safari node #send_keys should hold modifiers at top level'
80
- skip 'Need to look into this'
76
+ when /drag_to.*HTML5/
77
+ pending "Safari doesn't support"
81
78
  end
82
79
  end
83
80
 
84
81
  RSpec.describe 'Capybara::Session with safari' do
85
82
  include Capybara::SpecHelper
86
- include_examples 'Capybara::Session', TestSessions::Safari, SAFARI_DRIVER
87
- include_examples Capybara::RSpecMatchers, TestSessions::Safari, SAFARI_DRIVER
83
+ ['Capybara::Session', 'Capybara::Node', Capybara::RSpecMatchers].each do |examples|
84
+ include_examples examples, TestSessions::Safari, SAFARI_DRIVER
85
+ end
88
86
 
89
87
  context 'storage' do
90
88
  describe '#reset!' do
@@ -122,17 +120,18 @@ RSpec.describe 'Capybara::Session with safari' do
122
120
  let(:session) { TestSessions::Safari }
123
121
 
124
122
  before do
125
- skip 'Too many other things broken currently'
126
123
  session.visit('/form')
127
124
  end
128
125
 
129
126
  it 'should fill in a date input with a String' do
127
+ pending "Safari doesn't support date inputs"
130
128
  session.fill_in('form_date', with: '06/19/1983')
131
129
  session.click_button('awesome')
132
130
  expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date
133
131
  end
134
132
 
135
133
  it 'should fill in a time input with a String' do
134
+ # Safari doesn't support time inputs - so this is just a text input
136
135
  session.fill_in('form_time', with: '06:30A')
137
136
  session.click_button('awesome')
138
137
  results = extract_results(session)['time']
@@ -140,6 +139,7 @@ RSpec.describe 'Capybara::Session with safari' do
140
139
  end
141
140
 
142
141
  it 'should fill in a datetime input with a String' do
142
+ pending "Safari doesn't support datetime inputs"
143
143
  session.fill_in('form_datetime', with: "06/19/1983\t06:30A")
144
144
  session.click_button('awesome')
145
145
  expect(Time.parse(extract_results(session)['datetime'])).to eq datetime
@@ -5,7 +5,7 @@ require 'spec_helper'
5
5
  RSpec.describe Capybara::Server do
6
6
  it 'should spool up a rack server' do
7
7
  app = proc { |_env| [200, {}, ['Hello Server!']] }
8
- server = Capybara::Server.new(app).boot
8
+ server = described_class.new(app).boot
9
9
 
10
10
  res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
11
11
 
@@ -14,7 +14,7 @@ RSpec.describe Capybara::Server do
14
14
 
15
15
  it 'should do nothing when no server given' do
16
16
  expect do
17
- Capybara::Server.new(nil).boot
17
+ described_class.new(nil).boot
18
18
  end.not_to raise_error
19
19
  end
20
20
 
@@ -26,12 +26,12 @@ RSpec.describe Capybara::Server do
26
26
  app = proc { |_env| [200, {}, ['Hello Server!']] }
27
27
 
28
28
  Capybara.server_host = '127.0.0.1'
29
- server = Capybara::Server.new(app).boot
29
+ server = described_class.new(app).boot
30
30
  res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
31
31
  expect(res).to eq('Hello Server!')
32
32
 
33
33
  Capybara.server_host = '0.0.0.0'
34
- server = Capybara::Server.new(app).boot
34
+ server = described_class.new(app).boot
35
35
  res = Net::HTTP.get(URI("http://127.0.0.1:#{server.port}"))
36
36
  expect(res).to eq('Hello Server!')
37
37
  ensure
@@ -43,7 +43,7 @@ RSpec.describe Capybara::Server do
43
43
  Capybara.server_port = 22789
44
44
 
45
45
  app = proc { |_env| [200, {}, ['Hello Server!']] }
46
- server = Capybara::Server.new(app).boot
46
+ server = described_class.new(app).boot
47
47
 
48
48
  res = Net::HTTP.start(server.host, 22789) { |http| http.get('/') }
49
49
  expect(res.body).to include('Hello Server')
@@ -53,7 +53,7 @@ RSpec.describe Capybara::Server do
53
53
 
54
54
  it 'should use given port' do
55
55
  app = proc { |_env| [200, {}, ['Hello Server!']] }
56
- server = Capybara::Server.new(app, port: 22790).boot
56
+ server = described_class.new(app, port: 22790).boot
57
57
 
58
58
  res = Net::HTTP.start(server.host, 22790) { |http| http.get('/') }
59
59
  expect(res.body).to include('Hello Server')
@@ -66,7 +66,7 @@ RSpec.describe Capybara::Server do
66
66
  apps = responses.map do |response|
67
67
  proc { |_env| [200, {}, [response]] }
68
68
  end
69
- servers = apps.map { |app| Capybara::Server.new(app).boot }
69
+ servers = apps.map { |app| described_class.new(app).boot }
70
70
 
71
71
  servers.each_with_index do |server, idx|
72
72
  result = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
@@ -74,26 +74,53 @@ RSpec.describe Capybara::Server do
74
74
  end
75
75
  end
76
76
 
77
- it 'should support SSL' do
78
- begin
79
- key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem')
80
- cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem')
81
- Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" }
82
- app = proc { |_env| [200, {}, ['Hello SSL Server!']] }
83
- server = Capybara::Server.new(app).boot
77
+ it 'should handle that getting available ports fails randomly' do
78
+ # Use a port to force a EADDRINUSE error to be generated
79
+ server = TCPServer.new('0.0.0.0', 0)
80
+ server_port = server.addr[1]
81
+ d_server = instance_double('TCPServer', addr: [nil, server_port, nil, nil], close: nil)
82
+ call_count = 0
83
+ allow(TCPServer).to receive(:new).and_wrap_original do |m, *args|
84
+ call_count.zero? ? d_server : m.call(*args)
85
+ ensure
86
+ call_count += 1
87
+ end
84
88
 
85
- expect do
86
- Net::HTTP.start(server.host, server.port) { |http| http.get('/__idntify__') }
87
- end.to raise_error(EOFError)
89
+ port = described_class.new(Object.new, host: '0.0.0.0').port
90
+ expect(port).not_to eq(server_port)
91
+ ensure
92
+ server&.close
93
+ end
88
94
 
89
- res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
90
- https.get('/')
91
- end
95
+ it 'should return its #base_url' do
96
+ app = proc { |_env| [200, {}, ['Hello Server!']] }
97
+ server = described_class.new(app).boot
98
+ uri = ::Addressable::URI.parse(server.base_url)
99
+ expect(uri.to_hash).to include(scheme: 'http', host: server.host, port: server.port)
100
+ end
92
101
 
93
- expect(res.body).to include('Hello SSL Server!')
94
- ensure
95
- Capybara.server = :default
102
+ it 'should support SSL' do
103
+ key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem')
104
+ cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem')
105
+ Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" }
106
+ app = proc { |_env| [200, {}, ['Hello SSL Server!']] }
107
+ server = described_class.new(app).boot
108
+
109
+ expect do
110
+ Net::HTTP.start(server.host, server.port, max_retries: 0) { |http| http.get('/__identify__') }
111
+ end.to(raise_error do |e|
112
+ expect(e.is_a?(EOFError) || e.is_a?(Net::ReadTimeout)).to be true
113
+ end)
114
+
115
+ res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
116
+ https.get('/')
96
117
  end
118
+
119
+ expect(res.body).to include('Hello SSL Server!')
120
+ uri = ::Addressable::URI.parse(server.base_url)
121
+ expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port)
122
+ ensure
123
+ Capybara.server = :default
97
124
  end
98
125
 
99
126
  context 'When Capybara.reuse_server is true' do
@@ -110,7 +137,7 @@ RSpec.describe Capybara::Server do
110
137
  it 'should use the existing server if it already running' do
111
138
  app = proc { |_env| [200, {}, ['Hello Server!']] }
112
139
 
113
- servers = Array.new(2) { Capybara::Server.new(app).boot }
140
+ servers = Array.new(2) { described_class.new(app).boot }
114
141
 
115
142
  servers.each do |server|
116
143
  res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
@@ -130,8 +157,8 @@ RSpec.describe Capybara::Server do
130
157
  [200, {}, ['Hello Server!']]
131
158
  end
132
159
 
133
- server1 = Capybara::Server.new(app).boot
134
- server2 = Capybara::Server.new(app).boot
160
+ server1 = described_class.new(app).boot
161
+ server2 = described_class.new(app).boot
135
162
 
136
163
  expect do
137
164
  start_request(server1, 1.0)
@@ -155,7 +182,7 @@ RSpec.describe Capybara::Server do
155
182
  it 'should not reuse an already running server' do
156
183
  app = proc { |_env| [200, {}, ['Hello Server!']] }
157
184
 
158
- servers = Array.new(2) { Capybara::Server.new(app).boot }
185
+ servers = Array.new(2) { described_class.new(app).boot }
159
186
 
160
187
  servers.each do |server|
161
188
  res = Net::HTTP.start(server.host, server.port) { |http| http.get('/') }
@@ -175,8 +202,8 @@ RSpec.describe Capybara::Server do
175
202
  [200, {}, ['Hello Server!']]
176
203
  end
177
204
 
178
- server1 = Capybara::Server.new(app).boot
179
- server2 = Capybara::Server.new(app).boot
205
+ server1 = described_class.new(app).boot
206
+ server2 = described_class.new(app).boot
180
207
 
181
208
  expect do
182
209
  start_request(server1, 1.0)
@@ -191,24 +218,42 @@ RSpec.describe Capybara::Server do
191
218
  end
192
219
 
193
220
  it 'should raise server errors when the server errors before the timeout' do
194
- begin
195
- Capybara.register_server :kaboom do
196
- sleep 0.1
197
- raise 'kaboom'
198
- end
199
- Capybara.server = :kaboom
221
+ Capybara.register_server :kaboom do
222
+ sleep 0.1
223
+ raise 'kaboom'
224
+ end
225
+ Capybara.server = :kaboom
200
226
 
201
- expect do
202
- Capybara::Server.new(proc { |e| }).boot
203
- end.to raise_error(RuntimeError, 'kaboom')
204
- ensure
205
- Capybara.server = :default
227
+ expect do
228
+ described_class.new(proc { |e| }).boot
229
+ end.to raise_error(RuntimeError, 'kaboom')
230
+ ensure
231
+ Capybara.server = :default
232
+ end
233
+
234
+ it 'should raise an error when there are pending requests' do
235
+ app = proc do |env|
236
+ request = Rack::Request.new(env)
237
+ sleep request.params['wait_time'].to_f
238
+ [200, {}, ['Hello Server!']]
206
239
  end
240
+
241
+ server = described_class.new(app).boot
242
+
243
+ expect do
244
+ start_request(server, 59.0)
245
+ server.wait_for_pending_requests
246
+ end.not_to raise_error
247
+
248
+ expect do
249
+ start_request(server, 61.0)
250
+ server.wait_for_pending_requests
251
+ end.to raise_error('Requests did not finish in 60 seconds: ["/?wait_time=61.0"]')
207
252
  end
208
253
 
209
254
  it 'is not #responsive? when Net::HTTP raises a SystemCallError' do
210
255
  app = -> { [200, {}, ['Hello, world']] }
211
- server = Capybara::Server.new(app)
256
+ server = described_class.new(app)
212
257
  allow(Net::HTTP).to receive(:start).and_raise(SystemCallError.allocate)
213
258
  expect(server.responsive?).to eq false
214
259
  end
@@ -223,7 +268,7 @@ RSpec.describe Capybara::Server do
223
268
  response = Net::HTTPSuccess.allocate
224
269
  allow(response).to receive(:body).and_return app.object_id.to_s
225
270
  allow(Net::HTTP).to receive(:start).with(anything, anything, hash_including(use_ssl: true)).and_return(response).once
226
- Capybara::Server.new(app).boot
271
+ described_class.new(app).boot
227
272
  expect(Net::HTTP).to have_received(:start).exactly(3).times
228
273
  end
229
274
  end