capybara 3.29.0 → 3.36.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +203 -15
  3. data/README.md +13 -4
  4. data/lib/capybara/config.rb +24 -10
  5. data/lib/capybara/cucumber.rb +1 -1
  6. data/lib/capybara/driver/base.rb +8 -0
  7. data/lib/capybara/driver/node.rb +1 -1
  8. data/lib/capybara/dsl.rb +10 -2
  9. data/lib/capybara/helpers.rb +19 -2
  10. data/lib/capybara/minitest/spec.rb +156 -97
  11. data/lib/capybara/minitest.rb +232 -144
  12. data/lib/capybara/node/actions.rb +41 -37
  13. data/lib/capybara/node/base.rb +6 -6
  14. data/lib/capybara/node/document.rb +2 -2
  15. data/lib/capybara/node/document_matchers.rb +3 -3
  16. data/lib/capybara/node/element.rb +24 -21
  17. data/lib/capybara/node/finders.rb +25 -18
  18. data/lib/capybara/node/matchers.rb +72 -57
  19. data/lib/capybara/node/simple.rb +13 -3
  20. data/lib/capybara/queries/active_element_query.rb +18 -0
  21. data/lib/capybara/queries/ancestor_query.rb +4 -3
  22. data/lib/capybara/queries/base_query.rb +2 -1
  23. data/lib/capybara/queries/current_path_query.rb +14 -4
  24. data/lib/capybara/queries/selector_query.rb +71 -23
  25. data/lib/capybara/queries/sibling_query.rb +4 -3
  26. data/lib/capybara/queries/style_query.rb +1 -1
  27. data/lib/capybara/queries/text_query.rb +7 -1
  28. data/lib/capybara/rack_test/browser.rb +13 -4
  29. data/lib/capybara/rack_test/driver.rb +2 -1
  30. data/lib/capybara/rack_test/form.rb +2 -2
  31. data/lib/capybara/rack_test/node.rb +43 -15
  32. data/lib/capybara/registration_container.rb +44 -0
  33. data/lib/capybara/registrations/drivers.rb +18 -12
  34. data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
  35. data/lib/capybara/registrations/servers.rb +3 -2
  36. data/lib/capybara/result.rb +35 -15
  37. data/lib/capybara/rspec/matcher_proxies.rb +8 -8
  38. data/lib/capybara/rspec/matchers/base.rb +12 -6
  39. data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
  40. data/lib/capybara/rspec/matchers/have_ancestor.rb +4 -3
  41. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  42. data/lib/capybara/rspec/matchers/have_selector.rb +16 -8
  43. data/lib/capybara/rspec/matchers/have_sibling.rb +3 -3
  44. data/lib/capybara/rspec/matchers/have_text.rb +3 -3
  45. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  46. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  47. data/lib/capybara/rspec/matchers/match_style.rb +7 -2
  48. data/lib/capybara/rspec/matchers/spatial_sugar.rb +2 -1
  49. data/lib/capybara/rspec/matchers.rb +33 -32
  50. data/lib/capybara/rspec.rb +2 -0
  51. data/lib/capybara/selector/builders/css_builder.rb +2 -2
  52. data/lib/capybara/selector/builders/xpath_builder.rb +4 -2
  53. data/lib/capybara/selector/css.rb +2 -2
  54. data/lib/capybara/selector/definition/button.rb +35 -13
  55. data/lib/capybara/selector/definition/checkbox.rb +3 -3
  56. data/lib/capybara/selector/definition/css.rb +3 -1
  57. data/lib/capybara/selector/definition/datalist_input.rb +2 -2
  58. data/lib/capybara/selector/definition/datalist_option.rb +1 -1
  59. data/lib/capybara/selector/definition/element.rb +3 -2
  60. data/lib/capybara/selector/definition/field.rb +1 -1
  61. data/lib/capybara/selector/definition/file_field.rb +2 -2
  62. data/lib/capybara/selector/definition/fillable_field.rb +3 -3
  63. data/lib/capybara/selector/definition/label.rb +5 -3
  64. data/lib/capybara/selector/definition/link.rb +8 -0
  65. data/lib/capybara/selector/definition/radio_button.rb +3 -3
  66. data/lib/capybara/selector/definition/select.rb +33 -14
  67. data/lib/capybara/selector/definition/table.rb +6 -3
  68. data/lib/capybara/selector/definition/table_row.rb +2 -2
  69. data/lib/capybara/selector/definition.rb +14 -11
  70. data/lib/capybara/selector/filter_set.rb +17 -17
  71. data/lib/capybara/selector/filters/base.rb +6 -1
  72. data/lib/capybara/selector/filters/locator_filter.rb +1 -1
  73. data/lib/capybara/selector/selector.rb +13 -3
  74. data/lib/capybara/selector.rb +37 -19
  75. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
  76. data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
  77. data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
  78. data/lib/capybara/selenium/driver.rb +79 -16
  79. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +11 -13
  80. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +10 -12
  81. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +4 -4
  82. data/lib/capybara/selenium/extensions/find.rb +4 -4
  83. data/lib/capybara/selenium/extensions/html5_drag.rb +30 -13
  84. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  85. data/lib/capybara/selenium/logger_suppressor.rb +8 -2
  86. data/lib/capybara/selenium/node.rb +110 -26
  87. data/lib/capybara/selenium/nodes/chrome_node.rb +34 -19
  88. data/lib/capybara/selenium/nodes/edge_node.rb +5 -3
  89. data/lib/capybara/selenium/nodes/firefox_node.rb +11 -6
  90. data/lib/capybara/selenium/nodes/safari_node.rb +3 -3
  91. data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
  92. data/lib/capybara/selenium/patches/atoms.rb +4 -4
  93. data/lib/capybara/selenium/patches/logs.rb +7 -9
  94. data/lib/capybara/server/animation_disabler.rb +17 -6
  95. data/lib/capybara/server/checker.rb +1 -1
  96. data/lib/capybara/server/middleware.rb +22 -10
  97. data/lib/capybara/server.rb +15 -3
  98. data/lib/capybara/session/config.rb +9 -3
  99. data/lib/capybara/session/matchers.rb +11 -11
  100. data/lib/capybara/session.rb +73 -37
  101. data/lib/capybara/spec/public/test.js +75 -7
  102. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  103. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  104. data/lib/capybara/spec/session/all_spec.rb +62 -9
  105. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  106. data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
  107. data/lib/capybara/spec/session/check_spec.rb +15 -0
  108. data/lib/capybara/spec/session/choose_spec.rb +6 -0
  109. data/lib/capybara/spec/session/click_button_spec.rb +16 -0
  110. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  111. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  112. data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
  113. data/lib/capybara/spec/session/find_spec.rb +31 -8
  114. data/lib/capybara/spec/session/has_any_selectors_spec.rb +4 -0
  115. data/lib/capybara/spec/session/has_button_spec.rb +75 -0
  116. data/lib/capybara/spec/session/has_css_spec.rb +14 -10
  117. data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
  118. data/lib/capybara/spec/session/has_field_spec.rb +40 -0
  119. data/lib/capybara/spec/session/has_link_spec.rb +24 -0
  120. data/lib/capybara/spec/session/has_select_spec.rb +32 -4
  121. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  122. data/lib/capybara/spec/session/has_table_spec.rb +51 -5
  123. data/lib/capybara/spec/session/has_text_spec.rb +25 -1
  124. data/lib/capybara/spec/session/html_spec.rb +1 -1
  125. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  126. data/lib/capybara/spec/session/node_spec.rb +184 -33
  127. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  128. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  129. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  130. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  131. data/lib/capybara/spec/session/scroll_spec.rb +4 -4
  132. data/lib/capybara/spec/session/selectors_spec.rb +15 -2
  133. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  134. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  135. data/lib/capybara/spec/session/window/window_spec.rb +8 -8
  136. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  137. data/lib/capybara/spec/spec_helper.rb +17 -17
  138. data/lib/capybara/spec/test_app.rb +40 -29
  139. data/lib/capybara/spec/views/animated.erb +1 -1
  140. data/lib/capybara/spec/views/form.erb +52 -6
  141. data/lib/capybara/spec/views/frame_child.erb +1 -1
  142. data/lib/capybara/spec/views/frame_one.erb +1 -1
  143. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  144. data/lib/capybara/spec/views/frame_two.erb +1 -1
  145. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  146. data/lib/capybara/spec/views/layout.erb +10 -0
  147. data/lib/capybara/spec/views/obscured.erb +1 -1
  148. data/lib/capybara/spec/views/offset.erb +2 -1
  149. data/lib/capybara/spec/views/path.erb +2 -2
  150. data/lib/capybara/spec/views/popup_one.erb +1 -1
  151. data/lib/capybara/spec/views/popup_two.erb +1 -1
  152. data/lib/capybara/spec/views/react.erb +2 -2
  153. data/lib/capybara/spec/views/scroll.erb +2 -1
  154. data/lib/capybara/spec/views/spatial.erb +1 -1
  155. data/lib/capybara/spec/views/with_animation.erb +10 -3
  156. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  157. data/lib/capybara/spec/views/with_dragula.erb +5 -3
  158. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  159. data/lib/capybara/spec/views/with_hover.erb +2 -2
  160. data/lib/capybara/spec/views/with_html.erb +3 -3
  161. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  162. data/lib/capybara/spec/views/with_js.erb +5 -3
  163. data/lib/capybara/spec/views/with_jstree.erb +1 -1
  164. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  165. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  166. data/lib/capybara/spec/views/with_sortable_js.erb +3 -3
  167. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  168. data/lib/capybara/spec/views/with_windows.erb +1 -1
  169. data/lib/capybara/spec/views/within_frames.erb +1 -1
  170. data/lib/capybara/version.rb +1 -1
  171. data/lib/capybara/window.rb +3 -7
  172. data/lib/capybara.rb +35 -29
  173. data/spec/basic_node_spec.rb +25 -11
  174. data/spec/capybara_spec.rb +1 -1
  175. data/spec/dsl_spec.rb +16 -3
  176. data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
  177. data/spec/minitest_spec.rb +3 -2
  178. data/spec/minitest_spec_spec.rb +46 -46
  179. data/spec/rack_test_spec.rb +37 -11
  180. data/spec/regexp_dissassembler_spec.rb +40 -36
  181. data/spec/result_spec.rb +42 -32
  182. data/spec/rspec/features_spec.rb +5 -2
  183. data/spec/rspec/scenarios_spec.rb +4 -0
  184. data/spec/rspec/shared_spec_matchers.rb +68 -56
  185. data/spec/rspec_spec.rb +8 -4
  186. data/spec/selector_spec.rb +17 -2
  187. data/spec/selenium_spec_chrome.rb +48 -25
  188. data/spec/selenium_spec_chrome_remote.rb +13 -6
  189. data/spec/selenium_spec_firefox.rb +25 -17
  190. data/spec/selenium_spec_firefox_remote.rb +2 -2
  191. data/spec/selenium_spec_ie.rb +3 -6
  192. data/spec/selenium_spec_safari.rb +27 -19
  193. data/spec/server_spec.rb +84 -31
  194. data/spec/session_spec.rb +1 -1
  195. data/spec/shared_selenium_node.rb +21 -7
  196. data/spec/shared_selenium_session.rb +114 -19
  197. data/spec/spec_helper.rb +1 -1
  198. metadata +78 -21
  199. data/lib/capybara/spec/session/source_spec.rb +0 -0
  200. data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -1,4 +1,4 @@
1
- <!doctype html>
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
1
2
  <html xmlns="http://www.w3.org/1999/xhtml">
2
3
  <head>
3
4
  <title>Namespace</title>
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html>
1
2
  <html>
2
3
  <head>
3
4
  <script>
@@ -14,4 +15,4 @@
14
15
  <body>
15
16
  <div>This delays unload by 2 seconds</div>
16
17
  </body>
17
- </html>
18
+ </html>
@@ -1,8 +1,9 @@
1
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
1
+ <!DOCTYPE html>
2
+ <html lang="en">
2
3
  <head>
3
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
4
5
  <title>with_sortable_js</title>
5
- <script src="https://sortablejs.github.io/Sortable/Sortable.js" type="text/javascript"></script>
6
+ <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.12.0/dist/sortable.umd.min.js" type="text/javascript"></script>
6
7
  </head>
7
8
 
8
9
  <body id="with_sortable_js">
@@ -18,4 +19,3 @@
18
19
  </script>
19
20
  </body>
20
21
  </html>
21
-
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html>
1
2
  <html>
2
3
  <head>
3
4
  <script>
@@ -1,4 +1,4 @@
1
-
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <title>With Windows</title>
@@ -1,4 +1,4 @@
1
-
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <title>With Frames</title>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Capybara
4
- VERSION = '3.29.0'
4
+ VERSION = '3.36.0'
5
5
  end
@@ -4,7 +4,7 @@ module Capybara
4
4
  ##
5
5
  # The {Window} class represents a browser window.
6
6
  #
7
- # You can get an instance of the class by calling either of:
7
+ # You can get an instance of the class by calling any of:
8
8
  #
9
9
  # * {Capybara::Session#windows}
10
10
  # * {Capybara::Session#current_window}
@@ -82,8 +82,8 @@ module Capybara
82
82
  # Resize window.
83
83
  #
84
84
  # @macro about_current
85
- # @param width [String] the new window width in pixels
86
- # @param height [String] the new window height in pixels
85
+ # @param width [Integer] the new window width in pixels
86
+ # @param height [Integer] the new window height in pixels
87
87
  #
88
88
  def resize_to(width, height)
89
89
  wait_for_stable_size { @driver.resize_window_to(handle, width, height) }
@@ -138,9 +138,5 @@ module Capybara
138
138
  end
139
139
  raise Capybara::WindowError, "Window size not stable within #{seconds} seconds."
140
140
  end
141
-
142
- def raise_unless_current(what)
143
- raise Capybara::WindowError, "#{what} not current window is not possible." unless current?
144
- end
145
141
  end
146
142
  end
data/lib/capybara.rb CHANGED
@@ -5,6 +5,7 @@ require 'nokogiri'
5
5
  require 'xpath'
6
6
  require 'forwardable'
7
7
  require 'capybara/config'
8
+ require 'capybara/registration_container'
8
9
 
9
10
  module Capybara
10
11
  class CapybaraError < StandardError; end
@@ -38,7 +39,7 @@ module Capybara
38
39
  # See {Capybara.configure}
39
40
  # @!method javascript_driver
40
41
  # See {Capybara.configure}
41
- # @!method allow_gumbo
42
+ # @!method use_html5_parsing
42
43
  # See {Capybara.configure}
43
44
  Config::OPTIONS.each do |method|
44
45
  def_delegators :config, method, "#{method}="
@@ -68,7 +69,7 @@ module Capybara
68
69
  #
69
70
  # #### Configurable options
70
71
  #
71
- # - **allow_gumbo** (Boolean = `false`) - When `nokogumbo` is available, whether it will be used to parse HTML strings.
72
+ # - **use_html5_parsing** (Boolean = `false`) - When Nokogiri >= 1.12.0 or `nokogumbo` is installed, whether HTML5 parsing will be used for HTML strings.
72
73
  # - **always_include_port** (Boolean = `false`) - Whether the Rack server's port should automatically be inserted into every visited URL
73
74
  # unless another port is explicitly specified.
74
75
  # - **app_host** (String, `nil`) - The default host to use when giving a relative URL to visit, must be a valid URL e.g. `http://www.example.com`.
@@ -81,6 +82,7 @@ module Capybara
81
82
  # - **default_selector** (`:css`, `:xpath` = `:css`) - Methods which take a selector use the given type by default. See also {Capybara::Selector}.
82
83
  # - **default_set_options** (Hash = `{}`) - The default options passed to {Capybara::Node::Element#set Element#set}.
83
84
  # - **enable_aria_label** (Boolean = `false`) - Whether fields, links, and buttons will match against `aria-label` attribute.
85
+ # - **enable_aria_role** (Boolean = `false`) - Selectors will check for relevant aria role (currently only `button`).
84
86
  # - **exact** (Boolean = `false`) - Whether locators are matched exactly or with substrings. Only affects selector conditions
85
87
  # written using the `XPath#is` method.
86
88
  # - **exact_text** (Boolean = `false`) - Whether the text matchers and `:text` filter match exactly or on substrings.
@@ -93,6 +95,7 @@ module Capybara
93
95
  # - **save_path** (String = `Dir.pwd`) - Where to put pages saved through {Capybara::Session#save_page save_page}, {Capybara::Session#save_screenshot save_screenshot},
94
96
  # {Capybara::Session#save_and_open_page save_and_open_page}, or {Capybara::Session#save_and_open_screenshot save_and_open_screenshot}.
95
97
  # - **server** (Symbol = `:default` (which uses puma)) - The name of the registered server to use when running the app under test.
98
+ # - **server_port** (Integer) - The port Capybara will run the application server on, if not specified a random port will be used.
96
99
  # - **server_errors** (Array\<Class> = `[Exception]`) - Error classes that should be raised in the tests if they are raised in the server
97
100
  # and {configure raise_server_errors} is `true`.
98
101
  # - **test_id** (Symbol, String, `nil` = `nil`) - Optional attribute to match locator against with built-in selectors along with id.
@@ -124,7 +127,7 @@ module Capybara
124
127
  # @yieldreturn [Capybara::Driver::Base] A Capybara driver instance
125
128
  #
126
129
  def register_driver(name, &block)
127
- drivers[name] = block
130
+ drivers.send(:register, name, block)
128
131
  end
129
132
 
130
133
  ##
@@ -143,7 +146,7 @@ module Capybara
143
146
  # @yieldparam host The host/ip to bind to
144
147
  #
145
148
  def register_server(name, &block)
146
- servers[name.to_sym] = block
149
+ servers.send(:register, name.to_sym, block)
147
150
  end
148
151
 
149
152
  ##
@@ -197,11 +200,11 @@ module Capybara
197
200
  end
198
201
 
199
202
  def drivers
200
- @drivers ||= {}
203
+ @drivers ||= RegistrationContainer.new
201
204
  end
202
205
 
203
206
  def servers
204
- @servers ||= {}
207
+ @servers ||= RegistrationContainer.new
205
208
  end
206
209
 
207
210
  # Wraps the given string, which should contain an HTML document or fragment
@@ -349,7 +352,8 @@ module Capybara
349
352
  #
350
353
  # Yield a block using a specific session name or {Capybara::Session} instance.
351
354
  #
352
- def using_session(name_or_session)
355
+ def using_session(name_or_session, &block)
356
+ previous_session = current_session
353
357
  previous_session_info = {
354
358
  specified_session: specified_session,
355
359
  session_name: session_name,
@@ -362,7 +366,12 @@ module Capybara
362
366
  else
363
367
  self.session_name = name_or_session
364
368
  end
365
- yield
369
+
370
+ if block.arity.zero?
371
+ yield
372
+ else
373
+ yield current_session, previous_session
374
+ end
366
375
  ensure
367
376
  self.session_name, self.specified_session = previous_session_info.values_at(:session_name, :specified_session)
368
377
  self.current_driver, self.app = previous_session_info.values_at(:current_driver, :app) if threadsafe
@@ -376,26 +385,21 @@ module Capybara
376
385
  # @return [Nokogiri::HTML::Document] HTML document
377
386
  #
378
387
  def HTML(html) # rubocop:disable Naming/MethodName
379
- if Nokogiri.respond_to?(:HTML5) && Capybara.allow_gumbo # Nokogumbo installed and allowed for use
380
- Nokogiri::HTML5(html).tap do |document|
381
- document.xpath('//template').each do |template|
382
- # template elements content is not part of the document
383
- template.inner_html = ''
384
- end
385
- document.xpath('//textarea').each do |textarea|
386
- # The Nokogumbo HTML5 parser already returns spec compliant contents
387
- textarea['_capybara_raw_value'] = textarea.content
388
- end
389
- end
388
+ # Nokogiri >= 1.12.0 or Nokogumbo installed and allowed for use
389
+ html_parser, using_html5 = if defined?(Nokogiri::HTML5) && Capybara.use_html5_parsing
390
+ [Nokogiri::HTML5, true]
390
391
  else
391
- Nokogiri::HTML(html).tap do |document|
392
- document.xpath('//template').each do |template|
393
- # template elements content is not part of the document
394
- template.inner_html = ''
395
- end
396
- document.xpath('//textarea').each do |textarea|
397
- textarea['_capybara_raw_value'] = textarea.content.sub(/\A\n/, '')
398
- end
392
+ [defined?(Nokogiri::HTML4) ? Nokogiri::HTML4 : Nokogiri::HTML, false]
393
+ end
394
+
395
+ html_parser.parse(html).tap do |document|
396
+ document.xpath('//template').each do |template|
397
+ # template elements content is not part of the document
398
+ template.inner_html = ''
399
+ end
400
+ document.xpath('//textarea').each do |textarea|
401
+ # The Nokogiri HTML5 parser already returns spec compliant contents
402
+ textarea['_capybara_raw_value'] = using_html5 ? textarea.content : textarea.content.delete_prefix("\n")
399
403
  end
400
404
  end
401
405
  end
@@ -458,6 +462,7 @@ module Capybara
458
462
  require 'capybara/queries/ancestor_query'
459
463
  require 'capybara/queries/sibling_query'
460
464
  require 'capybara/queries/style_query'
465
+ require 'capybara/queries/active_element_query'
461
466
 
462
467
  require 'capybara/node/finders'
463
468
  require 'capybara/node/matchers'
@@ -475,7 +480,7 @@ module Capybara
475
480
  require 'capybara/rack_test/node'
476
481
  require 'capybara/rack_test/form'
477
482
  require 'capybara/rack_test/browser'
478
- require 'capybara/rack_test/css_handlers.rb'
483
+ require 'capybara/rack_test/css_handlers'
479
484
 
480
485
  require 'capybara/selenium/node'
481
486
  require 'capybara/selenium/driver'
@@ -501,11 +506,12 @@ Capybara.configure do |config|
501
506
  config.visible_text_only = false
502
507
  config.automatic_label_click = false
503
508
  config.enable_aria_label = false
509
+ config.enable_aria_role = false
504
510
  config.reuse_server = true
505
511
  config.default_set_options = {}
506
512
  config.test_id = nil
507
513
  config.predicates_wait = true
508
514
  config.default_normalize_ws = false
509
- config.allow_gumbo = false
515
+ config.use_html5_parsing = false
510
516
  config.w3c_click_offset = false
511
517
  end
@@ -3,6 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe Capybara do
6
+ include Capybara::RSpecMatchers
6
7
  describe '.string' do
7
8
  let :string do
8
9
  described_class.string <<-STRING
@@ -110,14 +111,27 @@ RSpec.describe Capybara do
110
111
  expect(string.find('//form/input[@name="meh"]')).not_to be_disabled
111
112
  end
112
113
 
114
+ it 'allows finding siblings' do
115
+ h1 = string.find(:css, 'h1')
116
+ expect(h1).to have_sibling(:css, 'p', text: 'Yes it is')
117
+ expect(h1).not_to have_sibling(:css, 'p', text: 'Jonas Nicklas')
118
+ end
119
+
120
+ it 'allows finding ancestor' do
121
+ h1 = string.find(:css, 'h1')
122
+ expect(h1).to have_ancestor(:css, '#content')
123
+ expect(h1).not_to have_ancestor(:css, '#footer')
124
+ end
125
+
113
126
  it 'drops illegal fragments when using gumbo' do
114
127
  skip 'libxml is less strict than Gumbo' unless Nokogiri.respond_to?(:HTML5)
128
+ described_class.use_html5_parsing = true
115
129
  expect(described_class.string('<td>1</td>')).not_to have_css('td')
116
130
  end
117
131
 
118
- it 'can disable use of gumbo' do
119
- skip "Test doesn't make sense unlesss nokogumbo is loaded" unless Nokogiri.respond_to?(:HTML5)
120
- described_class.allow_gumbo = false
132
+ it 'can disable use of HTML5 parsing' do
133
+ skip "Test doesn't make sense unlesss HTML5 parsing is loaded (Nokogumbo or Nokogiri >= 1.12.0)" unless Nokogiri.respond_to?(:HTML5)
134
+ described_class.use_html5_parsing = false
121
135
  expect(described_class.string('<td>1</td>')).to have_css('td')
122
136
  end
123
137
 
@@ -129,25 +143,25 @@ RSpec.describe Capybara do
129
143
 
130
144
  describe '#has_title?' do
131
145
  it 'returns whether the page has the given title' do
132
- expect(string.has_title?('simple_node')).to be_truthy
133
- expect(string.has_title?('monkey')).to be_falsey
146
+ expect(string.has_title?('simple_node')).to be true
147
+ expect(string.has_title?('monkey')).to be false
134
148
  end
135
149
 
136
150
  it 'allows regexp matches' do
137
- expect(string.has_title?(/s[a-z]+_node/)).to be_truthy
138
- expect(string.has_title?(/monkey/)).to be_falsey
151
+ expect(string.has_title?(/s[a-z]+_node/)).to be true
152
+ expect(string.has_title?(/monkey/)).to be false
139
153
  end
140
154
  end
141
155
 
142
156
  describe '#has_no_title?' do
143
157
  it 'returns whether the page does not have the given title' do
144
- expect(string.has_no_title?('simple_node')).to be_falsey
145
- expect(string.has_no_title?('monkey')).to be_truthy
158
+ expect(string.has_no_title?('simple_node')).to be false
159
+ expect(string.has_no_title?('monkey')).to be true
146
160
  end
147
161
 
148
162
  it 'allows regexp matches' do
149
- expect(string.has_no_title?(/s[a-z]+_node/)).to be_falsey
150
- expect(string.has_no_title?(/monkey/)).to be_truthy
163
+ expect(string.has_no_title?(/s[a-z]+_node/)).to be false
164
+ expect(string.has_no_title?(/monkey/)).to be true
151
165
  end
152
166
  end
153
167
  end
@@ -32,7 +32,7 @@ RSpec.describe Capybara do
32
32
  # do nothing
33
33
  end
34
34
 
35
- expect(described_class.servers).to have_key(:blob)
35
+ expect(described_class.servers[:blob]).to be_truthy
36
36
  end
37
37
  end
38
38
 
data/spec/dsl_spec.rb CHANGED
@@ -8,7 +8,7 @@ class TestClass
8
8
  end
9
9
 
10
10
  Capybara::SpecHelper.run_specs TestClass.new, 'DSL', capybara_skip: %i[
11
- js modals screenshot frames windows send_keys server hover about_scheme psc download css driver scroll spatial
11
+ js modals screenshot frames windows send_keys server hover about_scheme psc download css driver scroll spatial html_validation shadow_dom active_element
12
12
  ] do |example|
13
13
  case example.metadata[:full_description]
14
14
  when /has_css\? should support case insensitive :class and :id options/
@@ -19,6 +19,10 @@ Capybara::SpecHelper.run_specs TestClass.new, 'DSL', capybara_skip: %i[
19
19
  end
20
20
 
21
21
  RSpec.describe Capybara::DSL do
22
+ before do
23
+ Capybara.use_default_driver
24
+ end
25
+
22
26
  after do
23
27
  Capybara.session_name = nil
24
28
  Capybara.default_driver = nil
@@ -92,7 +96,7 @@ RSpec.describe Capybara::DSL do
92
96
  driver_before_block = Capybara.current_driver
93
97
  begin
94
98
  Capybara.using_driver(:selenium) { raise 'ohnoes!' }
95
- rescue Exception # rubocop:disable Lint/RescueException,Lint/HandleExceptions
99
+ rescue Exception # rubocop:disable Lint/RescueException,Lint/SuppressedException
96
100
  end
97
101
  expect(Capybara.current_driver).to eq(driver_before_block)
98
102
  end
@@ -208,7 +212,7 @@ RSpec.describe Capybara::DSL do
208
212
  Capybara.using_session(:raise) do
209
213
  raise
210
214
  end
211
- rescue Exception # rubocop:disable Lint/RescueException,Lint/HandleExceptions
215
+ rescue Exception # rubocop:disable Lint/RescueException,Lint/SuppressedException
212
216
  end
213
217
  expect(Capybara.session_name).to eq(:default)
214
218
  end
@@ -238,6 +242,15 @@ RSpec.describe Capybara::DSL do
238
242
  end
239
243
  expect(Capybara.current_session).to eq(original_session)
240
244
  end
245
+
246
+ it 'should pass the new session if block accepts' do
247
+ original_session = Capybara.current_session
248
+ Capybara.using_session(:administrator) do |admin_session, prev_session|
249
+ expect(admin_session).to be(Capybara.current_session)
250
+ expect(prev_session).to be(original_session)
251
+ expect(prev_session).not_to be(admin_session)
252
+ end
253
+ end
241
254
  end
242
255
 
243
256
  describe '#session_name' do
@@ -6,8 +6,8 @@ require 'selenium-webdriver'
6
6
  RSpec.describe Capybara::Selenium::Driver do
7
7
  it 'should exit with a zero exit status' do
8
8
  options = { browser: (ENV['SELENIUM_BROWSER'] || :firefox).to_sym }
9
- browser = described_class.new(TestApp, options).browser
9
+ browser = described_class.new(TestApp, **options).browser
10
10
  expect(browser).to be_truthy
11
- expect(true).to eq(true) # rubocop:disable RSpec/ExpectActual
11
+ expect(true).to eq(true) # rubocop:disable RSpec/ExpectActual,RSpec/IdenticalEqualityAssertion
12
12
  end
13
13
  end
@@ -16,7 +16,7 @@ class MinitestTest < Minitest::Test
16
16
  end
17
17
 
18
18
  def test_assert_text
19
- assert_text('Form')
19
+ assert_text('Form', normalize_ws: false)
20
20
  assert_no_text('Not on the page')
21
21
  refute_text('Also Not on the page')
22
22
  end
@@ -30,6 +30,7 @@ class MinitestTest < Minitest::Test
30
30
 
31
31
  def test_assert_current_path
32
32
  assert_current_path('/form')
33
+ assert_current_path('/form') { |url| url.query.nil? }
33
34
  assert_no_current_path('/not_form')
34
35
  refute_current_path('/not_form')
35
36
  end
@@ -158,6 +159,6 @@ RSpec.describe 'capybara/minitest' do
158
159
  reporter.start
159
160
  MinitestTest.run reporter, {}
160
161
  reporter.report
161
- expect(output.string).to include('22 runs, 52 assertions, 0 failures, 0 errors, 1 skips')
162
+ expect(output.string).to include('22 runs, 53 assertions, 0 failures, 0 errors, 1 skips')
162
163
  end
163
164
  end
@@ -17,125 +17,125 @@ class MinitestSpecTest < Minitest::Spec
17
17
  end
18
18
 
19
19
  it 'supports text expectations' do
20
- page.must_have_text('Form', minimum: 1)
21
- page.wont_have_text('Not a form')
20
+ _(page).must_have_text('Form', minimum: 1)
21
+ _(page).wont_have_text('Not a form')
22
22
  form = find(:css, 'form', text: 'Title')
23
- form.must_have_text('Customer Email')
24
- form.wont_have_text('Some other email')
23
+ _(form).must_have_text('Customer Email')
24
+ _(form).wont_have_text('Some other email')
25
25
  end
26
26
 
27
27
  it 'supports current_path expectations' do
28
- page.must_have_current_path('/form')
29
- page.wont_have_current_path('/form2')
28
+ _(page).must_have_current_path('/form')
29
+ _(page).wont_have_current_path('/form2')
30
30
  end
31
31
 
32
32
  it 'supports title expectations' do
33
33
  visit('/with_title')
34
- page.must_have_title('Test Title')
35
- page.wont_have_title('Not the title')
34
+ _(page).must_have_title('Test Title')
35
+ _(page).wont_have_title('Not the title')
36
36
  end
37
37
 
38
38
  it 'supports xpath expectations' do
39
- page.must_have_xpath('.//input[@id="customer_email"]')
40
- page.wont_have_xpath('.//select[@id="not_form_title"]')
41
- page.wont_have_xpath('.//input[@id="customer_email"]') { |el| el[:id] == 'not_customer_email' }
39
+ _(page).must_have_xpath('.//input[@id="customer_email"]')
40
+ _(page).wont_have_xpath('.//select[@id="not_form_title"]')
41
+ _(page).wont_have_xpath('.//input[@id="customer_email"]') { |el| el[:id] == 'not_customer_email' }
42
42
  select = find(:select, 'form_title')
43
- select.must_have_xpath('.//option[@class="title"]')
44
- select.must_have_xpath('.//option', count: 1) { |option| option[:class] != 'title' && !option.disabled? }
45
- select.wont_have_xpath('.//input[@id="customer_email"]')
43
+ _(select).must_have_xpath('.//option[@class="title"]')
44
+ _(select).must_have_xpath('.//option', count: 1) { |option| option[:class] != 'title' && !option.disabled? }
45
+ _(select).wont_have_xpath('.//input[@id="customer_email"]')
46
46
  end
47
47
 
48
48
  it 'support css expectations' do
49
- page.must_have_css('input#customer_email')
50
- page.wont_have_css('select#not_form_title')
49
+ _(page).must_have_css('input#customer_email')
50
+ _(page).wont_have_css('select#not_form_title')
51
51
  el = find(:select, 'form_title')
52
- el.must_have_css('option.title')
53
- el.wont_have_css('input#customer_email')
52
+ _(el).must_have_css('option.title')
53
+ _(el).wont_have_css('input#customer_email')
54
54
  end
55
55
 
56
56
  it 'supports link expectations' do
57
57
  visit('/with_html')
58
- page.must_have_link('A link')
59
- page.wont_have_link('Not on page')
58
+ _(page).must_have_link('A link')
59
+ _(page).wont_have_link('Not on page')
60
60
  end
61
61
 
62
62
  it 'supports button expectations' do
63
- page.must_have_button('fresh_btn')
64
- page.wont_have_button('not_btn')
63
+ _(page).must_have_button('fresh_btn')
64
+ _(page).wont_have_button('not_btn')
65
65
  end
66
66
 
67
67
  it 'supports field expectations' do
68
- page.must_have_field('customer_email')
69
- page.wont_have_field('not_on_the_form')
68
+ _(page).must_have_field('customer_email')
69
+ _(page).wont_have_field('not_on_the_form')
70
70
  end
71
71
 
72
72
  it 'supports select expectations' do
73
- page.must_have_select('form_title')
74
- page.wont_have_select('not_form_title')
73
+ _(page).must_have_select('form_title')
74
+ _(page).wont_have_select('not_form_title')
75
75
  end
76
76
 
77
77
  it 'supports checked_field expectations' do
78
- page.must_have_checked_field('form_pets_dog')
79
- page.wont_have_checked_field('form_pets_cat')
78
+ _(page).must_have_checked_field('form_pets_dog')
79
+ _(page).wont_have_checked_field('form_pets_cat')
80
80
  end
81
81
 
82
82
  it 'supports unchecked_field expectations' do
83
- page.must_have_unchecked_field('form_pets_cat')
84
- page.wont_have_unchecked_field('form_pets_dog')
83
+ _(page).must_have_unchecked_field('form_pets_cat')
84
+ _(page).wont_have_unchecked_field('form_pets_dog')
85
85
  end
86
86
 
87
87
  it 'supports table expectations' do
88
88
  visit('/tables')
89
- page.must_have_table('agent_table')
90
- page.wont_have_table('not_on_form')
89
+ _(page).must_have_table('agent_table')
90
+ _(page).wont_have_table('not_on_form')
91
91
  end
92
92
 
93
93
  it 'supports all_of_selectors expectations' do
94
- page.must_have_all_of_selectors(:css, 'select#form_other_title', 'input#form_last_name')
94
+ _(page).must_have_all_of_selectors(:css, 'select#form_other_title', 'input#form_last_name')
95
95
  end
96
96
 
97
97
  it 'supports none_of_selectors expectations' do
98
- page.must_have_none_of_selectors(:css, 'input#not_on_page', 'input#also_not_on_page')
98
+ _(page).must_have_none_of_selectors(:css, 'input#not_on_page', 'input#also_not_on_page')
99
99
  end
100
100
 
101
101
  it 'supports any_of_selectors expectations' do
102
- page.must_have_any_of_selectors(:css, 'select#form_other_title', 'input#not_on_page')
102
+ _(page).must_have_any_of_selectors(:css, 'select#form_other_title', 'input#not_on_page')
103
103
  end
104
104
 
105
105
  it 'supports match_selector expectations' do
106
- find(:field, 'customer_email').must_match_selector(:field, 'customer_email')
107
- find(:select, 'form_title').wont_match_selector(:field, 'customer_email')
106
+ _(find(:field, 'customer_email')).must_match_selector(:field, 'customer_email')
107
+ _(find(:select, 'form_title')).wont_match_selector(:field, 'customer_email')
108
108
  end
109
109
 
110
110
  it 'supports match_css expectations' do
111
- find(:select, 'form_title').must_match_css('select#form_title')
112
- find(:select, 'form_title').wont_match_css('select#form_other_title')
111
+ _(find(:select, 'form_title')).must_match_css('select#form_title')
112
+ _(find(:select, 'form_title')).wont_match_css('select#form_other_title')
113
113
  end
114
114
 
115
115
  it 'supports match_xpath expectations' do
116
- find(:select, 'form_title').must_match_xpath('.//select[@id="form_title"]')
117
- find(:select, 'form_title').wont_match_xpath('.//select[@id="not_on_page"]')
116
+ _(find(:select, 'form_title')).must_match_xpath('.//select[@id="form_title"]')
117
+ _(find(:select, 'form_title')).wont_match_xpath('.//select[@id="not_on_page"]')
118
118
  end
119
119
 
120
120
  it 'handles failures' do
121
- page.must_have_select('non_existing_form_title')
121
+ _(page).must_have_select('non_existing_form_title')
122
122
  end
123
123
 
124
124
  it 'supports style expectations' do
125
125
  skip "Rack test doesn't support style" if Capybara.current_driver == :rack_test
126
126
  visit('/with_html')
127
- find(:css, '#second').must_have_style('display' => 'inline') # deprecated
128
- find(:css, '#second').must_match_style('display' => 'inline')
127
+ _(find(:css, '#second')).must_have_style('display' => 'inline') # deprecated
128
+ _(find(:css, '#second')).must_match_style('display' => 'inline')
129
129
  end
130
130
 
131
131
  it 'supports ancestor expectations' do
132
132
  option = find(:option, 'Finnish')
133
- option.must_have_ancestor(:css, '#form_locale')
133
+ _(option).must_have_ancestor(:css, '#form_locale')
134
134
  end
135
135
 
136
136
  it 'supports sibling expectations' do
137
137
  option = find(:css, '#form_title').find(:option, 'Mrs')
138
- option.must_have_sibling(:option, 'Mr')
138
+ _(option).must_have_sibling(:option, 'Mr')
139
139
  end
140
140
  end
141
141