capybara 3.35.3 → 3.39.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +110 -4
  3. data/README.md +28 -12
  4. data/lib/capybara/config.rb +16 -4
  5. data/lib/capybara/driver/base.rb +4 -0
  6. data/lib/capybara/driver/node.rb +5 -1
  7. data/lib/capybara/dsl.rb +4 -10
  8. data/lib/capybara/helpers.rb +8 -13
  9. data/lib/capybara/minitest/spec.rb +2 -2
  10. data/lib/capybara/node/actions.rb +14 -9
  11. data/lib/capybara/node/base.rb +2 -1
  12. data/lib/capybara/node/document.rb +2 -2
  13. data/lib/capybara/node/element.rb +13 -2
  14. data/lib/capybara/node/finders.rb +11 -2
  15. data/lib/capybara/node/simple.rb +5 -1
  16. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  17. data/lib/capybara/queries/active_element_query.rb +18 -0
  18. data/lib/capybara/queries/ancestor_query.rb +2 -1
  19. data/lib/capybara/queries/base_query.rb +2 -2
  20. data/lib/capybara/queries/current_path_query.rb +1 -1
  21. data/lib/capybara/queries/selector_query.rb +38 -10
  22. data/lib/capybara/queries/sibling_query.rb +2 -1
  23. data/lib/capybara/queries/text_query.rb +1 -1
  24. data/lib/capybara/rack_test/browser.rb +63 -8
  25. data/lib/capybara/rack_test/driver.rb +4 -4
  26. data/lib/capybara/rack_test/form.rb +29 -7
  27. data/lib/capybara/rack_test/node.rb +28 -22
  28. data/lib/capybara/registration_container.rb +0 -3
  29. data/lib/capybara/registrations/drivers.rb +6 -6
  30. data/lib/capybara/registrations/servers.rb +30 -10
  31. data/lib/capybara/rspec/matcher_proxies.rb +6 -6
  32. data/lib/capybara/rspec/matchers/base.rb +8 -6
  33. data/lib/capybara/rspec/matchers/compound.rb +1 -1
  34. data/lib/capybara/rspec/matchers/have_selector.rb +5 -5
  35. data/lib/capybara/rspec/matchers.rb +14 -14
  36. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  37. data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
  38. data/lib/capybara/selector/css.rb +1 -1
  39. data/lib/capybara/selector/definition/button.rb +9 -4
  40. data/lib/capybara/selector/definition/checkbox.rb +1 -1
  41. data/lib/capybara/selector/definition/file_field.rb +1 -1
  42. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  43. data/lib/capybara/selector/definition/link.rb +2 -1
  44. data/lib/capybara/selector/definition/radio_button.rb +1 -1
  45. data/lib/capybara/selector/definition.rb +4 -2
  46. data/lib/capybara/selector/filter_set.rb +4 -7
  47. data/lib/capybara/selector/regexp_disassembler.rb +2 -5
  48. data/lib/capybara/selector/selector.rb +5 -1
  49. data/lib/capybara/selector.rb +1 -0
  50. data/lib/capybara/selenium/driver.rb +30 -13
  51. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
  52. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -5
  53. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +1 -1
  54. data/lib/capybara/selenium/extensions/html5_drag.rb +5 -4
  55. data/lib/capybara/selenium/logger_suppressor.rb +4 -0
  56. data/lib/capybara/selenium/node.rb +81 -32
  57. data/lib/capybara/selenium/nodes/chrome_node.rb +6 -2
  58. data/lib/capybara/selenium/nodes/edge_node.rb +25 -3
  59. data/lib/capybara/selenium/nodes/firefox_node.rb +3 -3
  60. data/lib/capybara/selenium/nodes/safari_node.rb +4 -4
  61. data/lib/capybara/selenium/patches/action_pauser.rb +3 -3
  62. data/lib/capybara/selenium/patches/atoms.rb +1 -1
  63. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -1
  64. data/lib/capybara/server/animation_disabler.rb +40 -23
  65. data/lib/capybara/server/middleware.rb +1 -1
  66. data/lib/capybara/session/config.rb +4 -2
  67. data/lib/capybara/session.rb +31 -32
  68. data/lib/capybara/spec/public/test.js +4 -0
  69. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  70. data/lib/capybara/spec/session/all_spec.rb +10 -14
  71. data/lib/capybara/spec/session/assert_text_spec.rb +17 -17
  72. data/lib/capybara/spec/session/attach_file_spec.rb +6 -0
  73. data/lib/capybara/spec/session/check_spec.rb +10 -0
  74. data/lib/capybara/spec/session/choose_spec.rb +6 -0
  75. data/lib/capybara/spec/session/click_link_spec.rb +11 -0
  76. data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
  77. data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
  78. data/lib/capybara/spec/session/find_link_spec.rb +10 -0
  79. data/lib/capybara/spec/session/find_spec.rb +7 -1
  80. data/lib/capybara/spec/session/first_spec.rb +1 -1
  81. data/lib/capybara/spec/session/frame/within_frame_spec.rb +2 -0
  82. data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
  83. data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -2
  84. data/lib/capybara/spec/session/has_any_selectors_spec.rb +6 -2
  85. data/lib/capybara/spec/session/has_button_spec.rb +30 -0
  86. data/lib/capybara/spec/session/has_current_path_spec.rb +3 -3
  87. data/lib/capybara/spec/session/has_field_spec.rb +25 -1
  88. data/lib/capybara/spec/session/has_link_spec.rb +40 -0
  89. data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
  90. data/lib/capybara/spec/session/has_select_spec.rb +10 -4
  91. data/lib/capybara/spec/session/has_selector_spec.rb +15 -0
  92. data/lib/capybara/spec/session/has_text_spec.rb +6 -14
  93. data/lib/capybara/spec/session/matches_style_spec.rb +2 -0
  94. data/lib/capybara/spec/session/node_spec.rb +82 -1
  95. data/lib/capybara/spec/session/reset_session_spec.rb +13 -0
  96. data/lib/capybara/spec/session/scroll_spec.rb +7 -5
  97. data/lib/capybara/spec/session/visit_spec.rb +20 -0
  98. data/lib/capybara/spec/session/window/window_spec.rb +1 -1
  99. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  100. data/lib/capybara/spec/session/within_spec.rb +13 -0
  101. data/lib/capybara/spec/spec_helper.rb +12 -5
  102. data/lib/capybara/spec/test_app.rb +91 -14
  103. data/lib/capybara/spec/views/animated.erb +1 -1
  104. data/lib/capybara/spec/views/form.erb +28 -3
  105. data/lib/capybara/spec/views/frame_child.erb +1 -1
  106. data/lib/capybara/spec/views/frame_one.erb +1 -1
  107. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  108. data/lib/capybara/spec/views/frame_two.erb +1 -1
  109. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  110. data/lib/capybara/spec/views/layout.erb +10 -0
  111. data/lib/capybara/spec/views/obscured.erb +1 -1
  112. data/lib/capybara/spec/views/offset.erb +2 -1
  113. data/lib/capybara/spec/views/path.erb +2 -2
  114. data/lib/capybara/spec/views/popup_one.erb +1 -1
  115. data/lib/capybara/spec/views/popup_two.erb +1 -1
  116. data/lib/capybara/spec/views/react.erb +2 -2
  117. data/lib/capybara/spec/views/scroll.erb +2 -1
  118. data/lib/capybara/spec/views/spatial.erb +1 -1
  119. data/lib/capybara/spec/views/with_animation.erb +2 -3
  120. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  121. data/lib/capybara/spec/views/with_dragula.erb +2 -2
  122. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  123. data/lib/capybara/spec/views/with_hover.erb +2 -2
  124. data/lib/capybara/spec/views/with_html.erb +3 -3
  125. data/lib/capybara/spec/views/with_jquery_animation.erb +1 -1
  126. data/lib/capybara/spec/views/with_js.erb +2 -3
  127. data/lib/capybara/spec/views/with_jstree.erb +1 -1
  128. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  129. data/lib/capybara/spec/views/with_scope.erb +2 -2
  130. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  131. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  132. data/lib/capybara/spec/views/with_sortable_js.erb +2 -2
  133. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  134. data/lib/capybara/spec/views/with_windows.erb +1 -1
  135. data/lib/capybara/spec/views/within_frames.erb +1 -1
  136. data/lib/capybara/version.rb +1 -1
  137. data/lib/capybara/window.rb +1 -1
  138. data/lib/capybara.rb +23 -24
  139. data/spec/basic_node_spec.rb +16 -3
  140. data/spec/capybara_spec.rb +12 -0
  141. data/spec/counter_spec.rb +35 -0
  142. data/spec/css_builder_spec.rb +1 -1
  143. data/spec/css_splitter_spec.rb +1 -1
  144. data/spec/dsl_spec.rb +5 -3
  145. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
  146. data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
  147. data/spec/minitest_spec.rb +4 -0
  148. data/spec/minitest_spec_spec.rb +4 -0
  149. data/spec/per_session_config_spec.rb +1 -1
  150. data/spec/rack_test_spec.rb +30 -12
  151. data/spec/result_spec.rb +32 -35
  152. data/spec/rspec/features_spec.rb +3 -3
  153. data/spec/rspec/scenarios_spec.rb +2 -2
  154. data/spec/rspec/shared_spec_matchers.rb +3 -3
  155. data/spec/rspec_matchers_spec.rb +25 -0
  156. data/spec/rspec_spec.rb +2 -2
  157. data/spec/sauce_spec_chrome.rb +4 -4
  158. data/spec/selector_spec.rb +4 -4
  159. data/spec/selenium_spec_chrome.rb +16 -16
  160. data/spec/selenium_spec_chrome_remote.rb +15 -14
  161. data/spec/selenium_spec_edge.rb +12 -6
  162. data/spec/selenium_spec_firefox.rb +24 -7
  163. data/spec/selenium_spec_firefox_remote.rb +19 -4
  164. data/spec/selenium_spec_ie.rb +7 -8
  165. data/spec/selenium_spec_safari.rb +34 -20
  166. data/spec/server_spec.rb +7 -7
  167. data/spec/shared_selenium_node.rb +0 -4
  168. data/spec/shared_selenium_session.rb +24 -14
  169. data/spec/spec_helper.rb +34 -1
  170. data/spec/whitespace_normalizer_spec.rb +54 -0
  171. data/spec/xpath_builder_spec.rb +1 -1
  172. metadata +40 -14
  173. data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -21,8 +21,8 @@ def ensure_selenium_running!
21
21
  rescue StandardError
22
22
  if timer.expired?
23
23
  raise 'Selenium is not running. ' \
24
- "You can run a selenium server easily with: \n" \
25
- ' $ docker-compose up -d selenium_firefox'
24
+ "You can run a selenium server easily with: \n. " \
25
+ '$ docker-compose up -d selenium_firefox'
26
26
  else
27
27
  puts 'Waiting for Selenium docker instance...'
28
28
  sleep 1
@@ -35,11 +35,10 @@ Capybara.register_driver :selenium_firefox_remote do |app|
35
35
  ensure_selenium_running!
36
36
 
37
37
  url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
38
- browser_options = ::Selenium::WebDriver::Firefox::Options.new
38
+ browser_options = Selenium::WebDriver::Firefox::Options.new
39
39
 
40
40
  Capybara::Selenium::Driver.new app,
41
41
  browser: :remote,
42
- desired_capabilities: :firefox,
43
42
  options: browser_options,
44
43
  url: url
45
44
  end
@@ -65,6 +64,22 @@ Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVE
65
64
  when /#accept_confirm should work with nested modals$/
66
65
  # skip because this is timing based and hence flaky when set to pending
67
66
  skip 'Broken in FF 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if firefox_gte?(63, @session)
67
+ when 'Capybara::Session selenium_firefox_remote #fill_in should handle carriage returns with line feeds in a textarea correctly'
68
+ pending 'Not sure what firefox is doing here'
69
+ when 'Capybara::Session selenium_firefox_remote node #shadow_root should find elements inside the shadow dom using CSS',
70
+ 'Capybara::Session selenium_firefox_remote node #shadow_root should find nested shadow roots',
71
+ 'Capybara::Session selenium_firefox_remote node #shadow_root should click on elements',
72
+ 'Capybara::Session selenium_firefox_remote node #shadow_root should use convenience methods once moved to a descendant of the shadow root',
73
+ 'Capybara::Session selenium_firefox_remote node #shadow_root should produce error messages when failing',
74
+ 'Capybara::Session with firefox with selenium driver #evaluate_script returns a shadow root'
75
+ pending "Firefox doesn't yet have full W3C shadow root support"
76
+ when /Capybara::Session selenium_firefox_remote node #shadow_root should get visible text/
77
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
78
+ when /Capybara::Session selenium_firefox_remote node #shadow_root/
79
+ skip 'Not supported with this Selenium version' if selenium_lt?('4.1', @session)
80
+ skip 'Not supported with this geckodriver version' if geckodriver_lt?('0.31.0', @session)
81
+ when /Capybara::Session selenium_firefox_remote node #set should submit single text input forms if ended with \\n/
82
+ pending 'Firefox/geckodriver doesn\'t submit with values ending in \n'
68
83
  end
69
84
  end
70
85
 
@@ -28,7 +28,7 @@ end
28
28
 
29
29
  Capybara.register_driver :selenium_ie do |app|
30
30
  # ::Selenium::WebDriver.logger.level = "debug"
31
- options = ::Selenium::WebDriver::IE::Options.new
31
+ options = Selenium::WebDriver::IE::Options.new
32
32
  # options.require_window_focus = true
33
33
  # options.add_option("log", {"level": "trace"})
34
34
 
@@ -71,13 +71,10 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumIE, 'selenium', capybara_sk
71
71
  pending "IE 11 doesn't support date input types"
72
72
  when /#click_link_or_button with :disabled option happily clicks on links which incorrectly have the disabled attribute$/
73
73
  skip 'IE 11 obeys non-standard disabled attribute on anchor tag'
74
- when /#right_click should allow modifiers$/
75
- skip "Windows can't :meta click because :meta triggers start menu"
76
- when /#click should allow modifiers$/
74
+ when /#click should allow modifiers$/, /#double_click should allow modifiers$/
77
75
  pending "Doesn't work with IE for some unknown reason$"
78
- when /#double_click should allow modifiers$/
79
76
  pending "Doesn't work with IE for some unknown reason$"
80
- when /#click should allow multiple modifiers$/
77
+ when /#click should allow multiple modifiers$/, /#right_click should allow modifiers$/
81
78
  skip "Windows can't :meta click because :meta triggers start menu"
82
79
  when /#double_click should allow multiple modifiers$/
83
80
  skip "Windows can't :alt double click due to being properties shortcut"
@@ -91,7 +88,7 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumIE, 'selenium', capybara_sk
91
88
  pending "Window 7 and 8.1 don't support 308 http status code"
92
89
  when /#scroll_to can scroll an element to the center of the viewport$/,
93
90
  /#scroll_to can scroll an element to the center of the scrolling element$/
94
- pending " IE doesn't support ScrollToOptions"
91
+ pending "IE doesn't support ScrollToOptions"
95
92
  when /#attach_file with multipart form should fire change once for each set of files uploaded$/,
96
93
  /#attach_file with multipart form should fire change once when uploading multiple files from empty$/,
97
94
  /#attach_file with multipart form should not break when using HTML5 multiple file input uploading multiple files$/
@@ -106,11 +103,13 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumIE, 'selenium', capybara_sk
106
103
  when /#attach_file with a block/
107
104
  skip 'Hangs IE testing for unknown reason'
108
105
  when /drag_to.*HTML5/
109
- pending "IE doesn't support a DataTransfer constuctor"
106
+ pending "IE doesn't support a DataTransfer constructor"
110
107
  when /template elements should not be visible/
111
108
  skip "IE doesn't support template elements"
112
109
  when /Element#drop/
113
110
  pending "IE doesn't support DataTransfer constructor"
111
+ when /Capybara::Session selenium_chrome node #shadow_root should get visible text/
112
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
114
113
  end
115
114
  end
116
115
 
@@ -8,28 +8,40 @@ require 'rspec/shared_spec_matchers'
8
8
 
9
9
  SAFARI_DRIVER = :selenium_safari
10
10
 
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
+ # 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'
16
16
 
17
- browser_options = ::Selenium::WebDriver::Safari::Options.new
17
+ browser_options = Selenium::WebDriver::Safari::Options.new
18
18
  # browser_options.headless! if ENV['HEADLESS']
19
- # browser_options.add_option(:w3c, !!ENV['W3C'])
20
19
 
21
20
  Capybara.register_driver :selenium_safari do |app|
22
- Capybara::Selenium::Driver.new(app, browser: :safari, options: browser_options, timeout: 30).tap do |driver|
21
+ version = Capybara::Selenium::Driver.load_selenium
22
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
23
+ driver_options = { browser: :safari, timeout: 30 }.tap do |opts|
24
+ opts[options_key] = browser_options
25
+ end
26
+
27
+ Capybara::Selenium::Driver.new(app, **driver_options).tap do |driver|
23
28
  # driver.browser.download_path = Capybara.save_path
24
29
  end
25
30
  end
26
31
 
27
32
  Capybara.register_driver :selenium_safari_not_clear_storage do |app|
28
- safari_options = {
33
+ version = Capybara::Selenium::Driver.load_selenium
34
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
35
+ driver_options = {
29
36
  browser: :safari,
30
- options: browser_options
31
- }
32
- Capybara::Selenium::Driver.new(app, safari_options.merge(clear_local_storage: false, clear_session_storage: false))
37
+ clear_local_storage: false,
38
+ clear_session_storage: false,
39
+ timeout: 30
40
+ }.tap do |opts|
41
+ opts[options_key] = browser_options
42
+ end
43
+
44
+ Capybara::Selenium::Driver.new(app, **driver_options)
33
45
  end
34
46
 
35
47
  module TestSessions
@@ -65,16 +77,19 @@ Capybara::SpecHelper.run_specs TestSessions::Safari, SAFARI_DRIVER.to_s, capybar
65
77
  when 'Capybara::Session selenium_safari node #double_click should allow to adjust the offset',
66
78
  'Capybara::Session selenium_safari node #double_click should double click an element'
67
79
  pending "safardriver doesn't generate a double click event"
68
- when 'Capybara::Session selenium_safari node #click should allow multiple modifiers',
69
- /Capybara::Session selenium_safari node #(click|right_click|double_click) should allow modifiers/
70
- pending "safaridriver doesn't take key state into account when clicking"
71
- when 'Capybara::Session selenium_safari #fill_in on a pre-populated textfield with a reformatting onchange should trigger change when clearing field'
72
- pending "safardriver clear doesn't generate change event"
80
+ when 'Capybara::Session selenium_safari node #double_click should allow modifiers'
81
+ pending "safaridriver doesn't generate double click with key modifiers"
82
+ when /when w3c_click_offset is true should offset/
83
+ pending 'w3c_click_offset is not currently supported with safaridriver'
73
84
  when 'Capybara::Session selenium_safari #go_back should fetch a response from the driver from the previous page',
74
85
  'Capybara::Session selenium_safari #go_forward should fetch a response from the driver from the previous page'
75
86
  skip 'safaridriver loses the ability to find elements in the document after `go_back`'
76
- when /drag_to.*HTML5/
77
- pending "Safari doesn't support"
87
+ when 'Capybara::Session selenium node #shadow_root should get the shadow root',
88
+ 'Capybara::Session selenium node #shadow_root should find elements inside the shadow dom using CSS',
89
+ 'Capybara::Session selenium node #shadow_root should find nested shadow roots'
90
+ pending "Safari doesn't yet have W3C shadow root support"
91
+ when /Capybara::Session selenium_chrome node #shadow_root should get visible text/
92
+ pending "Selenium doesn't currently support getting visible text for shadow root elements"
78
93
  end
79
94
  end
80
95
 
@@ -124,7 +139,6 @@ RSpec.describe 'Capybara::Session with safari' do
124
139
  end
125
140
 
126
141
  it 'should fill in a date input with a String' do
127
- pending "Safari doesn't support date inputs"
128
142
  session.fill_in('form_date', with: '06/19/1983')
129
143
  session.click_button('awesome')
130
144
  expect(Date.parse(extract_results(session)['date'])).to eq datetime.to_date
data/spec/server_spec.rb CHANGED
@@ -20,7 +20,7 @@ RSpec.describe Capybara::Server do
20
20
 
21
21
  it 'should bind to the specified host' do
22
22
  # TODO: travis with jruby in container mode has an issue with this test
23
- skip 'This platform has an issue with this test' if (ENV['TRAVIS'] && (RUBY_ENGINE == 'jruby')) || Gem.win_platform?
23
+ skip 'This platform has an issue with this test' if (ENV.fetch('TRAVIS', nil) && (RUBY_ENGINE == 'jruby')) || Gem.win_platform?
24
24
 
25
25
  begin
26
26
  app = proc { |_env| [200, {}, ['Hello Server!']] }
@@ -78,7 +78,7 @@ RSpec.describe Capybara::Server do
78
78
  # Use a port to force a EADDRINUSE error to be generated
79
79
  server = TCPServer.new('0.0.0.0', 0)
80
80
  server_port = server.addr[1]
81
- d_server = instance_double('TCPServer', addr: [nil, server_port, nil, nil], close: nil)
81
+ d_server = instance_double(TCPServer, addr: [nil, server_port, nil, nil], close: nil)
82
82
  call_count = 0
83
83
  allow(TCPServer).to receive(:new).and_wrap_original do |m, *args|
84
84
  call_count.zero? ? d_server : m.call(*args)
@@ -95,7 +95,7 @@ RSpec.describe Capybara::Server do
95
95
  it 'should return its #base_url' do
96
96
  app = proc { |_env| [200, {}, ['Hello Server!']] }
97
97
  server = described_class.new(app).boot
98
- uri = ::Addressable::URI.parse(server.base_url)
98
+ uri = Addressable::URI.parse(server.base_url)
99
99
  expect(uri.to_hash).to include(scheme: 'http', host: server.host, port: server.port)
100
100
  end
101
101
 
@@ -136,7 +136,7 @@ RSpec.describe Capybara::Server do
136
136
  end
137
137
 
138
138
  expect(res.body).to include('Hello SSL Server!')
139
- uri = ::Addressable::URI.parse(server.base_url)
139
+ uri = Addressable::URI.parse(server.base_url)
140
140
  expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port)
141
141
  ensure
142
142
  Capybara.server = :default
@@ -184,7 +184,7 @@ RSpec.describe Capybara::Server do
184
184
  start_request(server2, 3.0)
185
185
  server1.wait_for_pending_requests
186
186
  end.to change { done }.from(0).to(2)
187
- expect(server2.send(:pending_requests?)).to eq(false)
187
+ expect(server2.send(:pending_requests?)).to be(false)
188
188
  end
189
189
  end
190
190
 
@@ -229,7 +229,7 @@ RSpec.describe Capybara::Server do
229
229
  start_request(server2, 3.0)
230
230
  server1.wait_for_pending_requests
231
231
  end.to change { done }.from(0).to(1)
232
- expect(server2.send(:pending_requests?)).to eq(true)
232
+ expect(server2.send(:pending_requests?)).to be(true)
233
233
  expect do
234
234
  server2.wait_for_pending_requests
235
235
  end.to change { done }.from(1).to(2)
@@ -274,7 +274,7 @@ RSpec.describe Capybara::Server do
274
274
  app = -> { [200, {}, ['Hello, world']] }
275
275
  server = described_class.new(app)
276
276
  allow(Net::HTTP).to receive(:start).and_raise(SystemCallError.allocate)
277
- expect(server.responsive?).to eq false
277
+ expect(server.responsive?).to be false
278
278
  end
279
279
 
280
280
  [EOFError, Net::ReadTimeout].each do |err|
@@ -61,8 +61,6 @@ RSpec.shared_examples 'Capybara::Node' do |session, _mode|
61
61
  end
62
62
 
63
63
  it 'will use native displayed if told to' do
64
- pending "Chromedriver < 76.0.3809.25 doesn't support native displayed in W3C mode" if chrome_lt?(76, session) && (ENV['W3C'] != 'false')
65
-
66
64
  session.driver.options[:native_displayed] = true
67
65
  session.visit('/form')
68
66
  session.find(:css, '#address1_city', visible: true)
@@ -71,8 +69,6 @@ RSpec.shared_examples 'Capybara::Node' do |session, _mode|
71
69
  end
72
70
 
73
71
  it "won't use native displayed if told not to" do
74
- skip 'Non-W3C uses native' if chrome?(session) && (ENV['W3C'] == 'false')
75
-
76
72
  session.driver.options[:native_displayed] = false
77
73
  session.visit('/form')
78
74
  session.find(:css, '#address1_city', visible: true)
@@ -23,7 +23,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
23
23
  it 'freshly reset session should not be touched' do
24
24
  session.instance_variable_set(:@touched, true)
25
25
  session.reset!
26
- expect(session.instance_variable_get(:@touched)).to eq false
26
+ expect(session.instance_variable_get(:@touched)).to be false
27
27
  end
28
28
  end
29
29
 
@@ -74,7 +74,6 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
74
74
 
75
75
  describe '#fill_in_with empty string and no options' do
76
76
  it 'should trigger change when clearing a field' do
77
- pending "safaridriver doesn't trigger change for clear" if safari?(session)
78
77
  session.visit('/with_js')
79
78
  session.fill_in('with_change_event', with: '')
80
79
  # click outside the field to trigger the change event
@@ -188,14 +187,12 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
188
187
 
189
188
  it 'should generate standard events on changing value' do
190
189
  pending "IE 11 doesn't support date input type" if ie?(session)
191
- pending "Safari doesn't support date input type" if safari?(session)
192
190
  session.fill_in('form_date', with: Date.today)
193
191
  expect(session.evaluate_script('window.capybara_formDateFiredEvents')).to eq %w[focus input change]
194
192
  end
195
193
 
196
194
  it 'should not generate input and change events if the value is not changed' do
197
195
  pending "IE 11 doesn't support date input type" if ie?(session)
198
- pending "Safari doesn't support date input type" if safari?(session)
199
196
  session.fill_in('form_date', with: Date.today)
200
197
  session.fill_in('form_date', with: Date.today)
201
198
  # Chrome adds an extra focus for some reason - ok for now
@@ -223,14 +220,14 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
223
220
  end
224
221
 
225
222
  describe '#send_keys' do
226
- it 'defaults to sending keys to the document.activeElement' do
223
+ it 'defaults to sending keys to the active_element' do
227
224
  session.visit('/form')
228
225
 
229
- expect(session.evaluate_script('document.activeElement')).to eq(session.find('//body'))
226
+ expect(session.active_element).to match_selector(:css, 'body')
230
227
 
231
228
  session.send_keys(:tab)
232
229
 
233
- expect(session.evaluate_script('document.activeElement')).to eq(session.first(:field))
230
+ expect(session.active_element).to match_selector(:css, '[tabindex="1"]')
234
231
  end
235
232
  end
236
233
 
@@ -283,6 +280,15 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
283
280
  expect(element).to eq session.find(:id, 'form_title')
284
281
  end
285
282
 
283
+ it 'returns a shadow root' do
284
+ skip 'Not supported with this Selenium version' if selenium_lt?('4.1', session)
285
+ pending "Geckodriver doesn't fully support shadow root yet" if firefox?(session)
286
+ session.visit('/with_shadow')
287
+ shadow = session.find(:css, '#shadow_host')
288
+ element = session.evaluate_script('arguments[0].shadowRoot', shadow)
289
+ expect(element).to be_instance_of(Capybara::Node::Element)
290
+ end
291
+
286
292
  it 'can return arrays of nested elements' do
287
293
  session.visit('/form')
288
294
  elements = session.evaluate_script('document.querySelectorAll("#form_city option")')
@@ -339,17 +345,15 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
339
345
  it 'can attach a directory' do
340
346
  pending "Geckodriver doesn't support uploading a directory" if firefox?(session)
341
347
  pending "Selenium remote doesn't support transferring a directory" if remote?(session)
342
- 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']
348
+ 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) && chrome_lt?(110, session) && ENV.fetch('HEADLESS', nil)
343
349
  pending "IE doesn't support uploading a directory" if ie?(session)
344
350
  pending 'Chrome/chromedriver 73 breaks this' if chrome?(session) && chrome_gte?(73, session) && chrome_lt?(75, session)
345
- pending "Safari doesn't support uploading a directory" if safari?(session)
346
- # pending "Edge/msedgedriver doesn't support directory upload" if edge?(session) && edge_gte?(75, session)
347
351
 
348
352
  session.visit('/form')
349
353
  test_file_dir = File.expand_path('./fixtures', File.dirname(__FILE__))
350
354
  session.attach_file('Directory Upload', test_file_dir)
351
355
  session.click_button('Upload Multiple')
352
- expect(session.body).to include('5 | ') # number of files
356
+ expect(session).to have_text('5 | ') # number of files
353
357
  end
354
358
 
355
359
  it 'can attach a relative file' do
@@ -358,7 +362,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
358
362
  session.visit('/form')
359
363
  session.attach_file('Single Document', 'spec/fixtures/capybara.csv')
360
364
  session.click_button('Upload Single')
361
- expect(session.body).to include('Content-type: text/csv')
365
+ expect(session).to have_text('Content-type: text/csv')
362
366
  end
363
367
  end
364
368
 
@@ -381,6 +385,12 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
381
385
  @animation_session = Capybara::Session.new(session.mode, TestApp.new)
382
386
  end
383
387
 
388
+ it 'should add CSS to the <head> element' do
389
+ @animation_session.visit('with_animation')
390
+
391
+ expect(@animation_session).to have_selector(:css, 'head > style', text: 'transition: none', visible: :hidden)
392
+ end
393
+
384
394
  it 'should disable CSS transitions' do
385
395
  @animation_session.visit('with_animation')
386
396
  @animation_session.click_link('transition me away')
@@ -514,8 +524,8 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
514
524
 
515
525
  it 'can query attributes with strange characters' do
516
526
  session.visit('/form')
517
- expect(session).to have_selector(:element, "{custom}": true)
518
- expect(session).to have_selector(:element, "{custom}": 'abcdef')
527
+ expect(session).to have_selector(:element, '{custom}': true)
528
+ expect(session).to have_selector(:element, '{custom}': 'abcdef')
519
529
  end
520
530
  end
521
531
 
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rspec/expectations'
4
- require 'webdrivers' if ENV['CI'] || ENV['WEBDRIVERS']
4
+ require 'webdrivers' if ENV.fetch('CI', nil) || ENV.fetch('WEBDRIVERS', nil)
5
5
  require 'selenium_statistics'
6
6
  if ENV['TRAVIS']
7
7
  require 'coveralls'
@@ -28,6 +28,18 @@ module Capybara
28
28
  firefox?(session) && (session.driver.browser.capabilities[:browser_version].to_f >= version)
29
29
  end
30
30
 
31
+ def geckodriver_version(session)
32
+ Gem::Version.new(session.driver.browser.capabilities['moz:geckodriverVersion'])
33
+ end
34
+
35
+ def geckodriver_gte?(version, session)
36
+ firefox?(session) && geckodriver_version(session) >= Gem::Version.new(version)
37
+ end
38
+
39
+ def geckodriver_lt?(version, session)
40
+ firefox?(session) && geckodriver_version(session) < Gem::Version.new(version)
41
+ end
42
+
31
43
  def chrome?(session)
32
44
  browser_name(session) == :chrome
33
45
  end
@@ -45,6 +57,27 @@ module Capybara
45
57
  chrome?(session) && (chrome_version(session) >= version)
46
58
  end
47
59
 
60
+ def chromedriver_version(session)
61
+ Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0])
62
+ end
63
+
64
+ def chromedriver_gte?(version, session)
65
+ chrome?(session) && chromedriver_version(session) >= Gem::Version.new(version)
66
+ end
67
+
68
+ def chromedriver_lt?(version, session)
69
+ chrome?(session) && chromedriver_version(session) < Gem::Version.new(version)
70
+ end
71
+
72
+ def selenium?(session)
73
+ session.driver.is_a? Capybara::Selenium::Driver
74
+ end
75
+
76
+ def selenium_lt?(version, session)
77
+ selenium?(session) &&
78
+ Gem::Version.new(::Selenium::WebDriver::VERSION) < Gem::Version.new(version)
79
+ end
80
+
48
81
  def edge?(session)
49
82
  browser_name(session).to_s.start_with?('edge')
50
83
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'capybara/node/whitespace_normalizer'
5
+
6
+ RSpec.describe Capybara::Node::WhitespaceNormalizer do
7
+ subject(:normalizer) do
8
+ klass = Class.new do
9
+ include Capybara::Node::WhitespaceNormalizer
10
+ end
11
+
12
+ klass.new
13
+ end
14
+
15
+ let(:text_needing_correction) do
16
+ <<~TEXT
17
+ Some #{described_class::NON_BREAKING_SPACE}text
18
+ #{described_class::RIGHT_TO_LEFT_MARK}
19
+ #{described_class::ZERO_WIDTH_SPACE * 30}
20
+ #{described_class::LEFT_TO_RIGHT_MARK}
21
+ Here
22
+ TEXT
23
+ end
24
+
25
+ describe '#normalize_spacing' do
26
+ it 'does nothing to text not containing special characters' do
27
+ expect(normalizer.normalize_spacing('text')).to eq('text')
28
+ end
29
+
30
+ it 'compresses excess breaking spacing' do
31
+ expect(
32
+ normalizer.normalize_spacing(text_needing_correction)
33
+ ).to eq('Some text Here')
34
+ end
35
+ end
36
+
37
+ describe '#normalize_visible_spacing' do
38
+ it 'does nothing to text not containing special characters' do
39
+ expect(normalizer.normalize_visible_spacing('text')).to eq('text')
40
+ end
41
+
42
+ it 'compresses excess breaking visible spacing' do
43
+ expect(
44
+ normalizer.normalize_visible_spacing(text_needing_correction)
45
+ ).to eq <<~TEXT.chomp
46
+ Some text
47
+ #{described_class::RIGHT_TO_LEFT_MARK}
48
+ #{described_class::ZERO_WIDTH_SPACE * 30}
49
+ #{described_class::LEFT_TO_RIGHT_MARK}
50
+ Here
51
+ TEXT
52
+ end
53
+ end
54
+ end
@@ -5,7 +5,7 @@ require 'spec_helper'
5
5
  # rubocop:disable RSpec/InstanceVariable
6
6
  RSpec.describe Capybara::Selector::XPathBuilder do
7
7
  let :builder do
8
- ::Capybara::Selector::XPathBuilder.new(@xpath)
8
+ described_class.new(@xpath)
9
9
  end
10
10
 
11
11
  context 'add_attribute_conditions' do
metadata CHANGED
@@ -1,16 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.35.3
4
+ version: 3.39.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Walpole
8
8
  - Jonas Nicklas
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
- cert_chain:
12
- - gem-public_cert.pem
13
- date: 2021-01-30 00:00:00.000000000 Z
11
+ cert_chain: []
12
+ date: 2023-04-03 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: addressable
@@ -26,6 +25,20 @@ dependencies:
26
25
  - - ">="
27
26
  - !ruby/object:Gem::Version
28
27
  version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: matrix
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
29
42
  - !ruby/object:Gem::Dependency
30
43
  name: mini_mime
31
44
  requirement: !ruby/object:Gem::Requirement
@@ -372,16 +385,22 @@ dependencies:
372
385
  name: selenium-webdriver
373
386
  requirement: !ruby/object:Gem::Requirement
374
387
  requirements:
375
- - - "~>"
388
+ - - ">="
389
+ - !ruby/object:Gem::Version
390
+ version: 3.142.7
391
+ - - "<"
376
392
  - !ruby/object:Gem::Version
377
- version: '3.5'
393
+ version: '5.0'
378
394
  type: :development
379
395
  prerelease: false
380
396
  version_requirements: !ruby/object:Gem::Requirement
381
397
  requirements:
382
- - - "~>"
398
+ - - ">="
399
+ - !ruby/object:Gem::Version
400
+ version: 3.142.7
401
+ - - "<"
383
402
  - !ruby/object:Gem::Version
384
- version: '3.5'
403
+ version: '5.0'
385
404
  - !ruby/object:Gem::Dependency
386
405
  name: sinatra
387
406
  requirement: !ruby/object:Gem::Requirement
@@ -468,6 +487,8 @@ files:
468
487
  - lib/capybara/node/finders.rb
469
488
  - lib/capybara/node/matchers.rb
470
489
  - lib/capybara/node/simple.rb
490
+ - lib/capybara/node/whitespace_normalizer.rb
491
+ - lib/capybara/queries/active_element_query.rb
471
492
  - lib/capybara/queries/ancestor_query.rb
472
493
  - lib/capybara/queries/base_query.rb
473
494
  - lib/capybara/queries/current_path_query.rb
@@ -587,6 +608,7 @@ files:
587
608
  - lib/capybara/spec/session/accept_alert_spec.rb
588
609
  - lib/capybara/spec/session/accept_confirm_spec.rb
589
610
  - lib/capybara/spec/session/accept_prompt_spec.rb
611
+ - lib/capybara/spec/session/active_element_spec.rb
590
612
  - lib/capybara/spec/session/all_spec.rb
591
613
  - lib/capybara/spec/session/ancestor_spec.rb
592
614
  - lib/capybara/spec/session/assert_all_of_selectors_spec.rb
@@ -686,6 +708,7 @@ files:
686
708
  - lib/capybara/spec/views/header_links.erb
687
709
  - lib/capybara/spec/views/host_links.erb
688
710
  - lib/capybara/spec/views/initial_alert.erb
711
+ - lib/capybara/spec/views/layout.erb
689
712
  - lib/capybara/spec/views/obscured.erb
690
713
  - lib/capybara/spec/views/offset.erb
691
714
  - lib/capybara/spec/views/path.erb
@@ -712,10 +735,10 @@ files:
712
735
  - lib/capybara/spec/views/with_namespace.erb
713
736
  - lib/capybara/spec/views/with_scope.erb
714
737
  - lib/capybara/spec/views/with_scope_other.erb
738
+ - lib/capybara/spec/views/with_shadow.erb
715
739
  - lib/capybara/spec/views/with_simple_html.erb
716
740
  - lib/capybara/spec/views/with_slow_unload.erb
717
741
  - lib/capybara/spec/views/with_sortable_js.erb
718
- - lib/capybara/spec/views/with_title.erb
719
742
  - lib/capybara/spec/views/with_unload_alert.erb
720
743
  - lib/capybara/spec/views/with_windows.erb
721
744
  - lib/capybara/spec/views/within_frames.erb
@@ -723,6 +746,7 @@ files:
723
746
  - lib/capybara/window.rb
724
747
  - spec/basic_node_spec.rb
725
748
  - spec/capybara_spec.rb
749
+ - spec/counter_spec.rb
726
750
  - spec/css_builder_spec.rb
727
751
  - spec/css_splitter_spec.rb
728
752
  - spec/dsl_spec.rb
@@ -758,6 +782,7 @@ files:
758
782
  - spec/shared_selenium_node.rb
759
783
  - spec/shared_selenium_session.rb
760
784
  - spec/spec_helper.rb
785
+ - spec/whitespace_normalizer_spec.rb
761
786
  - spec/xpath_builder_spec.rb
762
787
  homepage: https://github.com/teamcapybara/capybara
763
788
  licenses:
@@ -765,7 +790,8 @@ licenses:
765
790
  metadata:
766
791
  changelog_uri: https://github.com/teamcapybara/capybara/blob/master/History.md
767
792
  source_code_uri: https://github.com/teamcapybara/capybara
768
- post_install_message:
793
+ rubygems_mfa_required: 'true'
794
+ post_install_message:
769
795
  rdoc_options: []
770
796
  require_paths:
771
797
  - lib
@@ -773,15 +799,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
773
799
  requirements:
774
800
  - - ">="
775
801
  - !ruby/object:Gem::Version
776
- version: 2.5.0
802
+ version: 2.7.0
777
803
  required_rubygems_version: !ruby/object:Gem::Requirement
778
804
  requirements:
779
805
  - - ">="
780
806
  - !ruby/object:Gem::Version
781
807
  version: '0'
782
808
  requirements: []
783
- rubygems_version: 3.1.2
784
- signing_key:
809
+ rubygems_version: 3.3.7
810
+ signing_key:
785
811
  specification_version: 4
786
812
  summary: Capybara aims to simplify the process of integration testing Rack applications,
787
813
  such as Rails, Sinatra or Merb
@@ -1,5 +0,0 @@
1
-
2
- <title>Test Title</title>
3
- <body>
4
- <svg><title>abcdefg</title></svg>
5
- </body>