capybara 3.35.0 → 3.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +168 -5
  3. data/README.md +199 -39
  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 +9 -14
  9. data/lib/capybara/minitest/spec.rb +18 -6
  10. data/lib/capybara/minitest.rb +14 -1
  11. data/lib/capybara/node/actions.rb +14 -9
  12. data/lib/capybara/node/base.rb +2 -1
  13. data/lib/capybara/node/document.rb +2 -2
  14. data/lib/capybara/node/element.rb +13 -2
  15. data/lib/capybara/node/finders.rb +11 -2
  16. data/lib/capybara/node/matchers.rb +25 -0
  17. data/lib/capybara/node/simple.rb +5 -1
  18. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  19. data/lib/capybara/queries/active_element_query.rb +18 -0
  20. data/lib/capybara/queries/ancestor_query.rb +2 -1
  21. data/lib/capybara/queries/base_query.rb +2 -2
  22. data/lib/capybara/queries/current_path_query.rb +1 -1
  23. data/lib/capybara/queries/selector_query.rb +40 -11
  24. data/lib/capybara/queries/sibling_query.rb +2 -1
  25. data/lib/capybara/queries/text_query.rb +1 -1
  26. data/lib/capybara/rack_test/browser.rb +64 -8
  27. data/lib/capybara/rack_test/driver.rb +4 -4
  28. data/lib/capybara/rack_test/form.rb +29 -7
  29. data/lib/capybara/rack_test/node.rb +32 -33
  30. data/lib/capybara/registration_container.rb +2 -5
  31. data/lib/capybara/registrations/drivers.rb +7 -7
  32. data/lib/capybara/registrations/servers.rb +37 -16
  33. data/lib/capybara/result.rb +2 -2
  34. data/lib/capybara/rspec/matcher_proxies.rb +6 -6
  35. data/lib/capybara/rspec/matchers/base.rb +8 -6
  36. data/lib/capybara/rspec/matchers/compound.rb +1 -1
  37. data/lib/capybara/rspec/matchers/have_selector.rb +9 -17
  38. data/lib/capybara/rspec/matchers.rb +21 -16
  39. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  40. data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
  41. data/lib/capybara/selector/css.rb +6 -6
  42. data/lib/capybara/selector/definition/button.rb +10 -5
  43. data/lib/capybara/selector/definition/checkbox.rb +1 -1
  44. data/lib/capybara/selector/definition/file_field.rb +1 -1
  45. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  46. data/lib/capybara/selector/definition/link.rb +2 -1
  47. data/lib/capybara/selector/definition/radio_button.rb +1 -1
  48. data/lib/capybara/selector/definition/table.rb +1 -1
  49. data/lib/capybara/selector/definition/table_row.rb +2 -2
  50. data/lib/capybara/selector/definition.rb +4 -2
  51. data/lib/capybara/selector/filter_set.rb +4 -7
  52. data/lib/capybara/selector/regexp_disassembler.rb +2 -5
  53. data/lib/capybara/selector/selector.rb +5 -1
  54. data/lib/capybara/selector.rb +252 -0
  55. data/lib/capybara/selenium/driver.rb +31 -54
  56. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
  57. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -5
  58. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +2 -7
  59. data/lib/capybara/selenium/extensions/html5_drag.rb +5 -4
  60. data/lib/capybara/selenium/node.rb +60 -38
  61. data/lib/capybara/selenium/nodes/chrome_node.rb +4 -16
  62. data/lib/capybara/selenium/nodes/edge_node.rb +19 -13
  63. data/lib/capybara/selenium/nodes/firefox_node.rb +3 -3
  64. data/lib/capybara/selenium/nodes/safari_node.rb +4 -4
  65. data/lib/capybara/selenium/patches/atoms.rb +1 -1
  66. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -1
  67. data/lib/capybara/server/animation_disabler.rb +40 -23
  68. data/lib/capybara/server/middleware.rb +1 -1
  69. data/lib/capybara/server.rb +1 -1
  70. data/lib/capybara/session/config.rb +4 -2
  71. data/lib/capybara/session.rb +34 -34
  72. data/lib/capybara/spec/public/test.js +4 -0
  73. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  74. data/lib/capybara/spec/session/all_spec.rb +11 -15
  75. data/lib/capybara/spec/session/assert_text_spec.rb +17 -17
  76. data/lib/capybara/spec/session/attach_file_spec.rb +6 -0
  77. data/lib/capybara/spec/session/check_spec.rb +10 -0
  78. data/lib/capybara/spec/session/choose_spec.rb +6 -0
  79. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  80. data/lib/capybara/spec/session/click_link_spec.rb +12 -1
  81. data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
  82. data/lib/capybara/spec/session/fill_in_spec.rb +6 -0
  83. data/lib/capybara/spec/session/find_link_spec.rb +10 -0
  84. data/lib/capybara/spec/session/find_spec.rb +15 -1
  85. data/lib/capybara/spec/session/first_spec.rb +1 -1
  86. data/lib/capybara/spec/session/frame/within_frame_spec.rb +2 -0
  87. data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
  88. data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -2
  89. data/lib/capybara/spec/session/has_any_selectors_spec.rb +6 -2
  90. data/lib/capybara/spec/session/has_button_spec.rb +30 -0
  91. data/lib/capybara/spec/session/has_current_path_spec.rb +3 -3
  92. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  93. data/lib/capybara/spec/session/has_field_spec.rb +25 -1
  94. data/lib/capybara/spec/session/has_link_spec.rb +40 -0
  95. data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
  96. data/lib/capybara/spec/session/has_select_spec.rb +10 -4
  97. data/lib/capybara/spec/session/has_selector_spec.rb +15 -0
  98. data/lib/capybara/spec/session/has_table_spec.rb +13 -2
  99. data/lib/capybara/spec/session/has_text_spec.rb +6 -14
  100. data/lib/capybara/spec/session/matches_style_spec.rb +2 -0
  101. data/lib/capybara/spec/session/node_spec.rb +88 -1
  102. data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
  103. data/lib/capybara/spec/session/reset_session_spec.rb +13 -0
  104. data/lib/capybara/spec/session/scroll_spec.rb +7 -5
  105. data/lib/capybara/spec/session/uncheck_spec.rb +1 -1
  106. data/lib/capybara/spec/session/visit_spec.rb +20 -0
  107. data/lib/capybara/spec/session/window/window_spec.rb +1 -1
  108. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  109. data/lib/capybara/spec/session/within_spec.rb +13 -0
  110. data/lib/capybara/spec/spec_helper.rb +12 -5
  111. data/lib/capybara/spec/test_app.rb +91 -14
  112. data/lib/capybara/spec/views/animated.erb +1 -1
  113. data/lib/capybara/spec/views/form.erb +34 -4
  114. data/lib/capybara/spec/views/frame_child.erb +1 -1
  115. data/lib/capybara/spec/views/frame_one.erb +1 -1
  116. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  117. data/lib/capybara/spec/views/frame_two.erb +1 -1
  118. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  119. data/lib/capybara/spec/views/layout.erb +10 -0
  120. data/lib/capybara/spec/views/obscured.erb +1 -1
  121. data/lib/capybara/spec/views/offset.erb +2 -1
  122. data/lib/capybara/spec/views/path.erb +2 -2
  123. data/lib/capybara/spec/views/popup_one.erb +1 -1
  124. data/lib/capybara/spec/views/popup_two.erb +1 -1
  125. data/lib/capybara/spec/views/react.erb +2 -2
  126. data/lib/capybara/spec/views/scroll.erb +2 -1
  127. data/lib/capybara/spec/views/spatial.erb +1 -1
  128. data/lib/capybara/spec/views/with_animation.erb +2 -3
  129. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  130. data/lib/capybara/spec/views/with_dragula.erb +2 -2
  131. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  132. data/lib/capybara/spec/views/with_hover.erb +2 -2
  133. data/lib/capybara/spec/views/with_html.erb +5 -3
  134. data/lib/capybara/spec/views/with_jquery_animation.erb +1 -1
  135. data/lib/capybara/spec/views/with_js.erb +2 -3
  136. data/lib/capybara/spec/views/with_jstree.erb +1 -1
  137. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  138. data/lib/capybara/spec/views/with_scope.erb +2 -2
  139. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  140. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  141. data/lib/capybara/spec/views/with_sortable_js.erb +2 -2
  142. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  143. data/lib/capybara/spec/views/with_windows.erb +1 -1
  144. data/lib/capybara/spec/views/within_frames.erb +1 -1
  145. data/lib/capybara/version.rb +1 -1
  146. data/lib/capybara/window.rb +1 -1
  147. data/lib/capybara.rb +30 -30
  148. data/spec/basic_node_spec.rb +16 -3
  149. data/spec/capybara_spec.rb +12 -0
  150. data/spec/counter_spec.rb +35 -0
  151. data/spec/css_builder_spec.rb +1 -1
  152. data/spec/css_splitter_spec.rb +1 -1
  153. data/spec/dsl_spec.rb +5 -3
  154. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
  155. data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
  156. data/spec/minitest_spec.rb +12 -1
  157. data/spec/minitest_spec_spec.rb +4 -0
  158. data/spec/per_session_config_spec.rb +1 -1
  159. data/spec/rack_test_spec.rb +30 -12
  160. data/spec/result_spec.rb +41 -35
  161. data/spec/rspec/features_spec.rb +3 -3
  162. data/spec/rspec/scenarios_spec.rb +2 -2
  163. data/spec/rspec/shared_spec_matchers.rb +27 -3
  164. data/spec/rspec_matchers_spec.rb +25 -0
  165. data/spec/rspec_spec.rb +3 -3
  166. data/spec/sauce_spec_chrome.rb +5 -5
  167. data/spec/selector_spec.rb +4 -4
  168. data/spec/selenium_spec_chrome.rb +20 -18
  169. data/spec/selenium_spec_chrome_remote.rb +15 -19
  170. data/spec/selenium_spec_edge.rb +19 -6
  171. data/spec/selenium_spec_firefox.rb +26 -8
  172. data/spec/selenium_spec_firefox_remote.rb +18 -4
  173. data/spec/selenium_spec_ie.rb +7 -8
  174. data/spec/selenium_spec_safari.rb +34 -20
  175. data/spec/server_spec.rb +19 -7
  176. data/spec/shared_selenium_node.rb +0 -4
  177. data/spec/shared_selenium_session.rb +22 -14
  178. data/spec/spec_helper.rb +36 -3
  179. data/spec/whitespace_normalizer_spec.rb +54 -0
  180. data/spec/xpath_builder_spec.rb +1 -1
  181. metadata +49 -30
  182. data/lib/capybara/selenium/logger_suppressor.rb +0 -34
  183. data/lib/capybara/selenium/patches/action_pauser.rb +0 -26
  184. 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,21 @@ 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 remote 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 geckodriver version' if geckodriver_lt?('0.31.0', @session)
80
+ when /Capybara::Session selenium node #set should submit single text input forms if ended with \\n/
81
+ pending 'Firefox/geckodriver doesn\'t submit with values ending in \n'
68
82
  end
69
83
  end
70
84
 
@@ -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
 
@@ -118,6 +118,18 @@ RSpec.describe Capybara::Server do
118
118
  Capybara.server = :default
119
119
  end
120
120
 
121
+ it 'should not emit any warnings when booting puma' do
122
+ Capybara.server = :puma
123
+ app_proc = proc { |_env| [200, {}, ['Hello Puma!']] }
124
+ require 'puma'
125
+
126
+ expect do
127
+ described_class.new(app_proc).boot
128
+ end.not_to output.to_stderr
129
+ ensure
130
+ Capybara.server = :default
131
+ end
132
+
121
133
  it 'should support SSL' do
122
134
  key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem')
123
135
  cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem')
@@ -136,7 +148,7 @@ RSpec.describe Capybara::Server do
136
148
  end
137
149
 
138
150
  expect(res.body).to include('Hello SSL Server!')
139
- uri = ::Addressable::URI.parse(server.base_url)
151
+ uri = Addressable::URI.parse(server.base_url)
140
152
  expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port)
141
153
  ensure
142
154
  Capybara.server = :default
@@ -184,7 +196,7 @@ RSpec.describe Capybara::Server do
184
196
  start_request(server2, 3.0)
185
197
  server1.wait_for_pending_requests
186
198
  end.to change { done }.from(0).to(2)
187
- expect(server2.send(:pending_requests?)).to eq(false)
199
+ expect(server2.send(:pending_requests?)).to be(false)
188
200
  end
189
201
  end
190
202
 
@@ -229,7 +241,7 @@ RSpec.describe Capybara::Server do
229
241
  start_request(server2, 3.0)
230
242
  server1.wait_for_pending_requests
231
243
  end.to change { done }.from(0).to(1)
232
- expect(server2.send(:pending_requests?)).to eq(true)
244
+ expect(server2.send(:pending_requests?)).to be(true)
233
245
  expect do
234
246
  server2.wait_for_pending_requests
235
247
  end.to change { done }.from(1).to(2)
@@ -274,7 +286,7 @@ RSpec.describe Capybara::Server do
274
286
  app = -> { [200, {}, ['Hello, world']] }
275
287
  server = described_class.new(app)
276
288
  allow(Net::HTTP).to receive(:start).and_raise(SystemCallError.allocate)
277
- expect(server.responsive?).to eq false
289
+ expect(server.responsive?).to be false
278
290
  end
279
291
 
280
292
  [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,13 @@ 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
+ session.visit('/with_shadow')
285
+ shadow = session.find(:css, '#shadow_host')
286
+ element = session.evaluate_script('arguments[0].shadowRoot', shadow)
287
+ expect(element).to be_instance_of(Capybara::Node::Element)
288
+ end
289
+
286
290
  it 'can return arrays of nested elements' do
287
291
  session.visit('/form')
288
292
  elements = session.evaluate_script('document.querySelectorAll("#form_city option")')
@@ -339,17 +343,15 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
339
343
  it 'can attach a directory' do
340
344
  pending "Geckodriver doesn't support uploading a directory" if firefox?(session)
341
345
  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']
346
+ 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
347
  pending "IE doesn't support uploading a directory" if ie?(session)
344
348
  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
349
 
348
350
  session.visit('/form')
349
351
  test_file_dir = File.expand_path('./fixtures', File.dirname(__FILE__))
350
352
  session.attach_file('Directory Upload', test_file_dir)
351
353
  session.click_button('Upload Multiple')
352
- expect(session.body).to include('5 | ') # number of files
354
+ expect(session).to have_text('5 | ') # number of files
353
355
  end
354
356
 
355
357
  it 'can attach a relative file' do
@@ -358,7 +360,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
358
360
  session.visit('/form')
359
361
  session.attach_file('Single Document', 'spec/fixtures/capybara.csv')
360
362
  session.click_button('Upload Single')
361
- expect(session.body).to include('Content-type: text/csv')
363
+ expect(session).to have_text('Content-type: text/csv')
362
364
  end
363
365
  end
364
366
 
@@ -381,6 +383,12 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
381
383
  @animation_session = Capybara::Session.new(session.mode, TestApp.new)
382
384
  end
383
385
 
386
+ it 'should add CSS to the <head> element' do
387
+ @animation_session.visit('with_animation')
388
+
389
+ expect(@animation_session).to have_selector(:css, 'head > style', text: 'transition: none', visible: :hidden)
390
+ end
391
+
384
392
  it 'should disable CSS transitions' do
385
393
  @animation_session.visit('with_animation')
386
394
  @animation_session.click_link('transition me away')
@@ -514,8 +522,8 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
514
522
 
515
523
  it 'can query attributes with strange characters' do
516
524
  session.visit('/form')
517
- expect(session).to have_selector(:element, "{custom}": true)
518
- expect(session).to have_selector(:element, "{custom}": 'abcdef')
525
+ expect(session).to have_selector(:element, '{custom}': true)
526
+ expect(session).to have_selector(:element, '{custom}': 'abcdef')
519
527
  end
520
528
  end
521
529
 
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('WEBDRIVERS', nil)
5
5
  require 'selenium_statistics'
6
6
  if ENV['TRAVIS']
7
7
  require 'coveralls'
@@ -16,7 +16,7 @@ module Capybara
16
16
  module SpecHelper
17
17
  def firefox?(session)
18
18
  browser_name(session) == :firefox &&
19
- ((defined?(::Selenium::WebDriver::VERSION) && (::Selenium::WebDriver::VERSION.to_f >= 4)) ||
19
+ ((defined?(::Selenium::WebDriver::VERSION) && (Gem::Version.new(::Selenium::WebDriver::VERSION) >= Gem::Version.new('4'))) ||
20
20
  session.driver.browser.capabilities.is_a?(::Selenium::WebDriver::Remote::W3C::Capabilities))
21
21
  end
22
22
 
@@ -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
@@ -81,7 +114,7 @@ module Capybara
81
114
  mod = mod::Service if ::Selenium::WebDriver::Service.respond_to? :driver_path
82
115
  path = mod.driver_path
83
116
  path = path.call if path.respond_to? :call
84
- $stdout.puts `#{path.gsub(' ', '\ ')} --version`
117
+ $stdout.puts `#{path.gsub(' ', '\ ')} --version` if path
85
118
  end
86
119
  end
87
120
  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